diff --git a/.github/workflows/auto-start-ci.yml b/.github/workflows/auto-start-ci.yml index 34488eeed6d7..0a69ff636f25 100644 --- a/.github/workflows/auto-start-ci.yml +++ b/.github/workflows/auto-start-ci.yml @@ -1,3 +1,6 @@ +# This action uses the following secrets: +# JENKINS_USER: GitHub user whose Jenkins token is defined below +# JENKINS_TOKEN: Jenkins token, to be used to start CI name: Auto Start CI on: @@ -36,11 +39,13 @@ jobs: -t '{{ range . }}{{ .number }} {{ end }}' \ --limit 5)" >> "$GITHUB_OUTPUT" env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ github.token }} start-ci: permissions: + checks: read contents: read pull-requests: write + statuses: read needs: get-prs-for-ci if: needs.get-prs-for-ci.outputs.numbers != '' runs-on: ubuntu-slim @@ -59,10 +64,10 @@ jobs: ncu-config set token "$GH_TOKEN" ncu-config set jenkins_token "$JENKINS_TOKEN" ncu-config set owner "$GITHUB_REPOSITORY_OWNER" - ncu-config set repo "$(echo "$GITHUB_REPOSITORY" | cut -d/ -f2)" + ncu-config set repo "${GITHUB_REPOSITORY#*/}" env: USERNAME: ${{ secrets.JENKINS_USER }} - GH_TOKEN: ${{ secrets.GH_USER_TOKEN }} + GH_TOKEN: ${{ github.token }} JENKINS_TOKEN: ${{ secrets.JENKINS_TOKEN }} - name: Start the CI @@ -70,5 +75,4 @@ jobs: curl -fsSL "https://github.com/${GITHUB_REPOSITORY}/raw/${GITHUB_SHA}/tools/actions/start-ci.sh" \ | sh -s -- ${{ needs.get-prs-for-ci.outputs.numbers }} env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} + GH_TOKEN: ${{ github.token }} diff --git a/.github/workflows/build-tarball.yml b/.github/workflows/build-tarball.yml index 0f1701375547..4bb9702797de 100644 --- a/.github/workflows/build-tarball.yml +++ b/.github/workflows/build-tarball.yml @@ -81,7 +81,7 @@ jobs: if: github.base_ref == 'main' || github.ref_name == 'main' uses: Mozilla-Actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11 with: - version: v0.16.0 + version: v0.17.0 - name: Download tarball uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: diff --git a/.github/workflows/commit-queue.yml b/.github/workflows/commit-queue.yml index 7af712268711..a1d691e9e19f 100644 --- a/.github/workflows/commit-queue.yml +++ b/.github/workflows/commit-queue.yml @@ -22,78 +22,152 @@ permissions: contents: read jobs: - get_mergeable_prs: + get_candidate_prs: permissions: pull-requests: read if: github.repository == 'nodejs/node' runs-on: ubuntu-slim outputs: - numbers: ${{ steps.get_mergeable_prs.outputs.numbers }} + candidates: ${{ steps.get_candidate_prs.outputs.candidates }} steps: - - name: Get Pull Requests - id: get_mergeable_prs + - name: Get Pull Request Candidates + id: get_candidate_prs run: | - prs=$(gh pr list \ + list_prs() { + gh pr list \ --repo "$GITHUB_REPOSITORY" \ --base "$GITHUB_REF_NAME" \ --label 'commit-queue' \ + "$@" \ --json 'number' \ - --search "created:<=$(date --date="2 days ago" +"%Y-%m-%dT%H:%M:%S%z") -label:blocked" \ -t '{{ range . }}{{ .number }} {{ end }}' \ - --limit 100) - fast_track_prs=$(gh pr list \ - --repo "$GITHUB_REPOSITORY" \ - --base "$GITHUB_REF_NAME" \ - --label 'commit-queue' \ + --limit 100 + } + aged_prs=$(list_prs \ + --search "created:<=$(date --date="2 days ago" +"%Y-%m-%dT%H:%M:%S%z") -label:blocked") + fast_track_prs=$(list_prs \ --label 'fast-track' \ - --search "-label:blocked" \ - --json 'number' \ - -t '{{ range . }}{{ .number }} {{ end }}' \ - --limit 100) - numbers=$(echo $prs' '$fast_track_prs | jq -r -s 'unique | join(" ")') - echo "numbers=$numbers" >> "$GITHUB_OUTPUT" + --search "-label:blocked") + candidates=$(printf '%s %s\n' "$fast_track_prs" "$aged_prs" | + jq -r -s 'reduce .[] as $pr ([]; if index($pr) then . else . + [$pr] end) | join(" ")') + echo "candidates=$candidates" >> "$GITHUB_OUTPUT" env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ github.token }} commitQueue: - needs: get_mergeable_prs - if: needs.get_mergeable_prs.outputs.numbers != '' + needs: get_candidate_prs + if: needs.get_candidate_prs.outputs.candidates != '' + permissions: + checks: read + contents: read + pull-requests: read + statuses: read runs-on: ubuntu-slim steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - # A personal token is required because pushing with GITHUB_TOKEN will - # prevent commits from running CI after they land. It needs - # to be set here because `checkout` configures GitHub authentication - # for push as well. - token: ${{ secrets.GH_USER_TOKEN }} - - # Install dependencies - name: Install Node.js uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: ${{ env.NODE_VERSION }} + - name: Install @node-core/utils run: npm install -g @node-core/utils - - name: Set variables - run: | - echo "REPOSITORY=$(echo "$GITHUB_REPOSITORY" | cut -d/ -f2)" >> "$GITHUB_ENV" - - name: Configure @node-core/utils run: | - ncu-config set branch "${GITHUB_REF_NAME}" - ncu-config set upstream origin - ncu-config set username "$USERNAME" - ncu-config set token "$GITHUB_TOKEN" - ncu-config set jenkins_token "$JENKINS_TOKEN" - ncu-config set repo "${REPOSITORY}" - ncu-config set owner "${GITHUB_REPOSITORY_OWNER}" + # Keep the config outside the workspace so checkout does not remove it. + ncu-config --global set branch "${GITHUB_REF_NAME}" + ncu-config --global set upstream origin + ncu-config --global set username "$USERNAME" + ncu-config --global set token "$GH_TOKEN" + ncu-config --global set jenkins_token "$JENKINS_TOKEN" + ncu-config --global set repo "${GITHUB_REPOSITORY#*/}" + ncu-config --global set owner "${GITHUB_REPOSITORY_OWNER}" env: USERNAME: ${{ secrets.JENKINS_USER }} - GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }} + GH_TOKEN: ${{ github.token }} JENKINS_TOKEN: ${{ secrets.JENKINS_TOKEN }} + - name: Filter Pull Requests + id: get_mergeable_prs + run: | + readme="${RUNNER_TEMP}/README.md" + curl -fsSLo "$readme" "https://github.com/${GITHUB_REPOSITORY}/raw/${GITHUB_SHA}/README.md" + + numbers= + # shellcheck disable=SC2086 + for pr in $CANDIDATES; do + metadata="${RUNNER_TEMP}/metadata-${pr}.json" + output="${RUNNER_TEMP}/metadata-${pr}.txt" + if git node metadata "$pr" \ + --readme "$readme" \ + --json > "$metadata" 2> "$output"; then + metadata_status=0 + else + metadata_status=$? + fi + + if [ -s "$output" ]; then + cat "$output" + fi + + case "$metadata_status" in + 0|2[0-9]|4[0-9]) ;; + *) + echo "git node metadata failed for pr ${pr} with exit code ${metadata_status}" + exit 1 + ;; + esac + + metadata_exit_code=$(jq -r '.exitCode' "$metadata") || { + echo "failed to parse metadata JSON for pr ${pr}" + exit 1 + } + if [ "$metadata_exit_code" != "$metadata_status" ]; then + echo "metadata JSON exitCode mismatch for pr ${pr}" + exit 1 + fi + metadata_reason_codes=$(jq -r '.reasonCodes | join(", ")' "$metadata") || { + echo "failed to parse metadata reason codes for pr ${pr}" + exit 1 + } + + if [ "$metadata_status" -eq 0 ]; then + echo "pr ${pr} is ready for the commit queue" + numbers="$numbers $pr" + continue + fi + + if [ "$metadata_status" -ge 20 ] && [ "$metadata_status" -le 29 ]; then + echo "pr ${pr} skipped, not ready to land" + echo "reason codes: ${metadata_reason_codes}" + continue + fi + + echo "pr ${pr} will be handled by the commit queue" + echo "reason codes: ${metadata_reason_codes}" + numbers="$numbers $pr" + done + + numbers=$(echo "$numbers" | xargs) + echo "numbers=$numbers" >> "$GITHUB_OUTPUT" + env: + CANDIDATES: ${{ needs.get_candidate_prs.outputs.candidates }} + GH_TOKEN: ${{ github.token }} + + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + if: steps.get_mergeable_prs.outputs.numbers != '' + with: + # A personal token is required because pushing with GITHUB_TOKEN will + # prevent commits from running CI after they land. It needs + # to be set here because `checkout` configures GitHub authentication + # for push as well. + token: ${{ secrets.GH_USER_TOKEN }} + - name: Start the Commit Queue - run: ./tools/actions/commit-queue.sh "${GITHUB_REPOSITORY_OWNER}" "${REPOSITORY}" ${{ needs.get_mergeable_prs.outputs.numbers }} + if: steps.get_mergeable_prs.outputs.numbers != '' + run: | + git config --local user.email "github-bot@iojs.org" + git config --local user.name "Node.js GitHub Bot" + ncu-config set token "$GH_TOKEN" + ./tools/actions/commit-queue.sh ${{ steps.get_mergeable_prs.outputs.numbers }} env: - GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }} + GH_TOKEN: ${{ secrets.GH_USER_TOKEN }} diff --git a/.github/workflows/coverage-linux-without-intl.yml b/.github/workflows/coverage-linux-without-intl.yml index a76d4d47e599..19e03391f1cf 100644 --- a/.github/workflows/coverage-linux-without-intl.yml +++ b/.github/workflows/coverage-linux-without-intl.yml @@ -60,7 +60,7 @@ jobs: if: github.base_ref == 'main' || github.ref_name == 'main' uses: Mozilla-Actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11 with: - version: v0.16.0 + version: v0.17.0 - name: Install gcovr run: pip install gcovr==7.2 - name: Configure diff --git a/.github/workflows/coverage-linux.yml b/.github/workflows/coverage-linux.yml index 65f52f5b366d..c2c4b22c57a3 100644 --- a/.github/workflows/coverage-linux.yml +++ b/.github/workflows/coverage-linux.yml @@ -60,7 +60,7 @@ jobs: if: github.base_ref == 'main' || github.ref_name == 'main' uses: Mozilla-Actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11 with: - version: v0.16.0 + version: v0.17.0 - name: Install gcovr run: pip install gcovr==7.2 - name: Configure diff --git a/.github/workflows/stress-test.yml b/.github/workflows/stress-test.yml index eca8c6aa5a2d..10f61e8f922e 100644 --- a/.github/workflows/stress-test.yml +++ b/.github/workflows/stress-test.yml @@ -78,7 +78,7 @@ jobs: - name: Set up sccache uses: Mozilla-Actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11 with: - version: v0.16.0 + version: v0.17.0 # This is needed due to https://github.com/nodejs/build/issues/3878 - name: Cleanup if: runner.os == 'macOS' diff --git a/.github/workflows/test-internet.yml b/.github/workflows/test-internet.yml index bbc9fc9436e6..2bc7a1f029a1 100644 --- a/.github/workflows/test-internet.yml +++ b/.github/workflows/test-internet.yml @@ -57,7 +57,7 @@ jobs: if: github.base_ref == 'main' || github.ref_name == 'main' uses: Mozilla-Actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11 with: - version: v0.16.0 + version: v0.17.0 - name: Build run: make build-ci -j4 V=1 CONFIG_FLAGS="--error-on-warn" - name: Test Internet diff --git a/.github/workflows/test-linux-quic.yml b/.github/workflows/test-linux-quic.yml index 64c2e7d7ea9e..9916b7993d00 100644 --- a/.github/workflows/test-linux-quic.yml +++ b/.github/workflows/test-linux-quic.yml @@ -57,7 +57,7 @@ jobs: if: github.base_ref == 'main' || github.ref_name == 'main' uses: Mozilla-Actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11 with: - version: v0.16.0 + version: v0.17.0 - name: Build working-directory: node run: make build-ci -j4 V=1 CONFIG_FLAGS="--error-on-warn --experimental-quic" diff --git a/.github/workflows/test-linux.yml b/.github/workflows/test-linux.yml index 887db1dab85e..e154ee866df8 100644 --- a/.github/workflows/test-linux.yml +++ b/.github/workflows/test-linux.yml @@ -66,7 +66,7 @@ jobs: if: github.base_ref == 'main' || github.ref_name == 'main' uses: Mozilla-Actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11 with: - version: v0.16.0 + version: v0.17.0 - name: Build working-directory: node run: make build-ci -j4 V=1 CONFIG_FLAGS="--error-on-warn" diff --git a/.github/workflows/test-macos.yml b/.github/workflows/test-macos.yml index 7db72c856875..943ea4cb6c7c 100644 --- a/.github/workflows/test-macos.yml +++ b/.github/workflows/test-macos.yml @@ -64,7 +64,7 @@ jobs: if: github.base_ref == 'main' || github.ref_name == 'main' uses: Mozilla-Actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11 with: - version: v0.16.0 + version: v0.17.0 # The `npm ci` for this step fails a lot as part of the Test step. Run it # now so that we don't have to wait 2 hours for the Build step to pass # first before that failure happens. (And if there's something about diff --git a/.mailmap b/.mailmap index 0860e8e01478..6cdb3bc4f739 100644 --- a/.mailmap +++ b/.mailmap @@ -55,6 +55,7 @@ Ashok Suthar Ashutosh Kumar Singh Atsuo Fukaya Austin Kelleher +Aviv Keller Azard <330815461@qq.com> Ben Lugavere Ben Noordhuis diff --git a/BUILDING.md b/BUILDING.md index b54a167b0f89..36d80912f582 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -934,11 +934,11 @@ as `deps/icu` (You'll have: `deps/icu/source/...`) ### Configure OpenSSL appname Node.js can use an OpenSSL configuration file by specifying the environment -variable `OPENSSL_CONF`, or using the command line option `--openssl-conf`, and -if none of those are specified will default to reading the default OpenSSL -configuration file `openssl.cnf`. Node.js will only read a section that is by -default named `nodejs_conf`, but this name can be overridden using the following -configure option: +variable `OPENSSL_CONF`, or using the command line option `--openssl-config`, +which takes precedence. If neither is specified, Node.js defaults to reading the +default OpenSSL configuration file `openssl.cnf`. Node.js will only read a +section that is by default named `nodejs_conf`, but this name can be overridden +using the following configure option: ```bash ./configure --openssl-conf-name= @@ -950,6 +950,8 @@ Node.js supports FIPS when statically or dynamically linked with OpenSSL 3 via [OpenSSL's provider model](https://docs.openssl.org/3.0/man7/crypto/#OPENSSL-PROVIDERS). It is not necessary to rebuild Node.js to enable support for FIPS. +When using OpenSSL 1.1.1, Node.js must be built against a FIPS-capable OpenSSL. + See [FIPS mode](doc/api/crypto.md#fips-mode) for more information on how to enable FIPS support in Node.js. diff --git a/CHANGELOG.md b/CHANGELOG.md index d88832e8d427..6791109aecaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,7 +40,8 @@ release. -24.20.0
+24.21.0
+24.20.0
24.19.0
24.18.1
24.18.0
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b47b9868461b..cfc1bf72b47f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,6 +25,7 @@ works. * [Issues](#issues) * [Pull Requests](#pull-requests) * [Automation and bots](#automation-and-bots) +* [AI Use Policy and Guidelines](#ai-use-policy-and-guidelines) * [Developer's Certificate of Origin 1.1](#developers-certificate-of-origin-11) ## [Code of Conduct](./doc/contributing/code-of-conduct.md) @@ -46,6 +47,8 @@ See [details on our policy on Code of Conduct](./doc/contributing/code-of-conduc Pull Requests are the way concrete changes are made to the code, documentation, dependencies, and tools contained in the `nodejs/node` repository. +Contributors who are not Collaborators may have no more than 10 pull requests +open at a time. * [Dependencies](./doc/contributing/pull-requests.md#dependencies) * [Setting up your local environment](./doc/contributing/pull-requests.md#setting-up-your-local-environment) @@ -66,6 +69,15 @@ by an automation that was not authorized by Node.js collaborators are subject to immediate moderation enforcement on the automation and owner without notice. +## [AI Use Policy and Guidelines](./doc/contributing/ai-guidelines.md) + +Node.js requires contributors to understand and take full responsibility for +every change they propose. Pull requests containing AI-generated code the +contributor has not personally understood, tested, and verified will likely be closed +without review. + +See [details on our AI use policy and guidelines](./doc/contributing/ai-guidelines.md). + ## Developer's Certificate of Origin 1.1 ```text diff --git a/README.md b/README.md index a6cf7d6683fa..3827556a44fb 100644 --- a/README.md +++ b/README.md @@ -182,8 +182,6 @@ For information about the governance of the Node.js project, see **Ruy Adorno** <> (he/him) * [ShogunPanda](https://github.com/ShogunPanda) - **Paolo Insogna** <> (he/him) -* [targos](https://github.com/targos) - - **Michaël Zasso** <> (he/him) * [tniessen](https://github.com/tniessen) - **Tobias Nießen** <> (he/him) @@ -260,6 +258,8 @@ For information about the governance of the Node.js project, see **Sam Roberts** <> * [shigeki](https://github.com/shigeki) - **Shigeki Ohtsu** <> (he/him) +* [targos](https://github.com/targos) - + **Michaël Zasso** <> (he/him) * [thefourtheye](https://github.com/thefourtheye) - **Sakthipriyan Vairamani** <> (he/him) * [TimothyGu](https://github.com/TimothyGu) - @@ -323,8 +323,6 @@ For information about the governance of the Node.js project, see **Erick Wendel** <> (he/him) * [Ethan-Arrowood](https://github.com/Ethan-Arrowood) - **Ethan Arrowood** <> (he/him) -* [fhinkel](https://github.com/fhinkel) - - **Franziska Hinkelmann** <> (she/her) * [Flarna](https://github.com/Flarna) - **Gerhard Stöbich** <> (he/they) * [gabrielschulhof](https://github.com/gabrielschulhof) - @@ -431,8 +429,6 @@ For information about the governance of the Node.js project, see **Stefan Stojanovic** <> (he/him) * [sxa](https://github.com/sxa) - **Stewart X Addison** <> (he/him) -* [targos](https://github.com/targos) - - **Michaël Zasso** <> (he/him) * [theanarkh](https://github.com/theanarkh) - **theanarkh** <> (he/him) * [tniessen](https://github.com/tniessen) - @@ -525,6 +521,8 @@ For information about the governance of the Node.js project, see **Evan Lucas** <> (he/him) * [F3n67u](https://github.com/F3n67u) - **Feng Yu** <> (he/him) +* [fhinkel](https://github.com/fhinkel) - + **Franziska Hinkelmann** <> (she/her) * [firedfox](https://github.com/firedfox) - **Daniel Wang** <> * [Fishrock123](https://github.com/Fishrock123) - @@ -699,6 +697,8 @@ For information about the governance of the Node.js project, see **Weijia Wang** <> * [stefanmb](https://github.com/stefanmb) - **Stefan Budeanu** <> +* [targos](https://github.com/targos) - + **Michaël Zasso** <> (he/him) * [tellnes](https://github.com/tellnes) - **Christian Tellnes** <> * [thefourtheye](https://github.com/thefourtheye) - @@ -779,8 +779,6 @@ Primary GPG keys for Node.js Releasers (some Releasers sign with subkeys): `DD792F5973C6DE52C432CBDAC77ABFA00DDBF2B7` * **Marco Ippolito** <> `CC68F5A3106FF448322E48ED27F5E38D5B0A215F` -* **Michaël Zasso** <> - `8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600` * **Rafael Gonzaga** <> `890C08DB8579162FEE0DF9DB8BEAB4DFCF555EF4` * **Richard Lau** <> @@ -846,6 +844,8 @@ verify a downloaded file. `61FC681DFB92A079F1685E77973F295594EC4689` * **Julien Gilli** <> `114F43EE0176B71C7BC219DD50A3051F888C628D` +* **Michaël Zasso** <> + `8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600` * **Myles Borins** <> `C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8` * **Rod Vagg** <> diff --git a/benchmark/_benchmark_progress.js b/benchmark/_benchmark_progress.js index 6c925f34e682..117e86609028 100644 --- a/benchmark/_benchmark_progress.js +++ b/benchmark/_benchmark_progress.js @@ -25,9 +25,10 @@ function getTime(diff) { // A run is an item in the job queue: { binary, filename, iter } // A config is an item in the subqueue: { binary, filename, iter, configs } class BenchmarkProgress { - constructor(queue, benchmarks) { + constructor(queue, benchmarks, options = {}) { this.queue = queue; // Scheduled runs. this.benchmarks = benchmarks; // Filenames of scheduled benchmarks. + this.analyze = !!options.analyze; // stdout is not piped, but unused. this.completedRuns = 0; // Number of completed runs. this.scheduledRuns = queue.length; // Number of scheduled runs. // Time when starting to run benchmarks. @@ -107,7 +108,10 @@ class BenchmarkProgress { } updateProgress() { - if (!process.stderr.isTTY || process.stdout.isTTY) { + // Progress renders on stderr when stdout is piped (not a TTY). + // In --analyze mode, stdout is the terminal but is unused during + // the run, so treat it the same as piped. + if (!process.stderr.isTTY || (process.stdout.isTTY && !this.analyze)) { return; } readline.clearLine(process.stderr); diff --git a/benchmark/compare.js b/benchmark/compare.js index ad3084db3904..6aaaee7a9190 100644 --- a/benchmark/compare.js +++ b/benchmark/compare.js @@ -13,7 +13,8 @@ const cli = new CLI(`usage: ./node compare.js [options] [--] ... Run each benchmark in the directory many times using two different node versions. More than one directory can be specified. The output is formatted as csv, which can be processed using for - example 'compare.R'. + example 'compare.R'. Use --analyze to perform statistical analysis + directly without R. --new ./new-node-binary new node binary (required) --old ./old-node-binary old node binary (required) @@ -24,13 +25,21 @@ const cli = new CLI(`usage: ./node compare.js [options] [--] ... repeated) --set variable=value set benchmark variable (can be repeated) --no-progress don't show benchmark progress indicator + --analyze perform statistical analysis after benchmarks + complete (Welch's t-test, effect size) instead + of printing csv output + --scale 1000 rate-to-integer multiplier for histogram + precision when using --analyze (default: 1000) + --max-regression N exit with code 1 if any statistically + significant regression exceeds N% (implies + --analyze) Examples: --set CPUSET=0 Runs benchmarks on CPU core 0. --set CPUSET=0-2 Specifies that benchmarks should run on CPU cores 0 to 2. Note: The CPUSET format should match the specifications of the 'taskset' command -`, { arrayArgs: ['set', 'filter', 'exclude'], boolArgs: ['no-progress'] }); +`, { arrayArgs: ['set', 'filter', 'exclude'], boolArgs: ['no-progress', 'analyze'] }); if (!cli.optional.new || !cli.optional.old) { cli.abort(cli.usage); @@ -38,6 +47,11 @@ if (!cli.optional.new || !cli.optional.old) { const binaries = ['old', 'new']; const runs = cli.optional.runs ? parseInt(cli.optional.runs, 10) : 30; +const maxRegression = cli.optional['max-regression'] ? + parseFloat(cli.optional['max-regression']) : + 0; +const analyze = !!cli.optional.analyze || maxRegression > 0; +const scale = cli.optional.scale ? parseInt(cli.optional.scale, 10) : 1000; const benchmarks = cli.benchmarks(); if (benchmarks.length === 0) { @@ -46,6 +60,9 @@ if (benchmarks.length === 0) { return; } +// When --analyze is set, collect results for statistical analysis. +const results = analyze ? new Map() : null; + // Create queue from the benchmarks list such both node versions are tested // `runs` amount of times each. // Note: BenchmarkProgress relies on this order to estimate @@ -61,15 +78,17 @@ for (const filename of benchmarks) { } // queue.length = binary.length * runs * benchmarks.length -// Print csv header -console.log('"binary","filename","configuration","rate","time"'); +// Print csv header (unless analyzing inline). +if (!analyze) { + console.log('"binary","filename","configuration","rate","time"'); +} const kStartOfQueue = 0; const showProgress = !cli.optional['no-progress']; let progress; if (showProgress) { - progress = new BenchmarkProgress(queue, benchmarks); + progress = new BenchmarkProgress(queue, benchmarks, { analyze }); progress.startQueue(kStartOfQueue); } @@ -99,11 +118,20 @@ if (showProgress) { conf += ` ${key}=${inspect(data.conf[key])}`; } conf = conf.slice(1); - // Escape quotes (") for correct csv formatting - conf = conf.replace(/"/g, '""'); - console.log(`"${job.binary}","${job.filename}","${conf}",` + - `${data.rate},${data.time}`); + if (analyze) { + // Collect results for post-run analysis. + const name = `${job.filename} ${conf}`; + if (!results.has(name)) { + results.set(name, { old: [], new: [] }); + } + results.get(name)[job.binary].push(data.rate); + } else { + // Escape quotes (") for correct csv formatting + conf = conf.replace(/"/g, '""'); + console.log(`"${job.binary}","${job.filename}","${conf}",` + + `${data.rate},${data.time}`); + } if (showProgress) { // One item in the subqueue has been completed. progress.completeConfig(data); @@ -125,6 +153,199 @@ if (showProgress) { // If there are more benchmarks execute the next if (i + 1 < queue.length) { recursive(i + 1); + } else if (analyze) { + printAnalysis(results, scale, maxRegression); } }); })(kStartOfQueue); + +function printAnalysis(results, scale, maxRegression) { + const { createHistogram } = require('node:perf_hooks'); + + // Build per-benchmark histograms and run statistical tests. + const rows = []; + let maxNameLen = 0; + + let skipped = 0; + + for (const [name, { old: oldRates, new: newRates }] of results) { + if (oldRates.length < 2 || newRates.length < 2) { + skipped++; + continue; + } + + const hOld = createHistogram({ figures: 3 }); + const hNew = createHistogram({ figures: 3 }); + + for (const r of oldRates) hOld.record(Math.max(1, Math.round(r * scale))); + for (const r of newRates) hNew.record(Math.max(1, Math.round(r * scale))); + + const oldMean = oldRates.reduce((a, b) => a + b, 0) / oldRates.length; + const newMean = newRates.reduce((a, b) => a + b, 0) / newRates.length; + const improvement = ((newMean - oldMean) / oldMean) * 100; + + // Query the three confidence levels. The p-value and t-statistic + // are the same regardless of the confidence level, so we extract + // them from the first result. + const w95 = hOld.welchTest(hNew, { confidence: 0.95 }); + const w99 = hOld.welchTest(hNew, { confidence: 0.99 }); + const w999 = hOld.welchTest(hNew, { confidence: 0.999 }); + + // Significance stars matching compare.R convention. + let stars = ''; + if (w95.pValue < 0.001) stars = '***'; + else if (w95.pValue < 0.01) stars = ' **'; + else if (w95.pValue < 0.05) stars = ' *'; + + // Confidence intervals expressed as percentage of the old mean. + const ciPct = (w) => { + const half = + (w.confidenceInterval.upper - w.confidenceInterval.lower) / 2; + return (half / (oldMean * scale)) * 100; + }; + + rows.push({ + name, + stars, + improvement, + ci95: ciPct(w95), + ci99: ciPct(w99), + ci999: ciPct(w999), + pValue: w95.pValue, + }); + + if (name.length > maxNameLen) maxNameLen = name.length; + } + + // Print header. + const pad = (s, n) => s + ' '.repeat(Math.max(0, n - s.length)); + const rpad = (s, n) => ' '.repeat(Math.max(0, n - s.length)) + s; + + console.log(`${pad('', maxNameLen)} confidence` + + ` improvement accuracy (*) (**) (***)`); + + for (const row of rows) { + const imp = `${row.improvement >= 0 ? '+' : ''}${row.improvement.toFixed(2)} %`; + console.log( + `${pad(row.name, maxNameLen)} ${pad(row.stars, 10)}` + + ` ${rpad(imp, 11)}` + + ` ±${row.ci95.toFixed(2)}%` + + ` ±${row.ci99.toFixed(2)}%` + + ` ±${row.ci999.toFixed(2)}%`, + ); + } + + if (skipped > 0) { + console.log(''); + console.log( + `Note: ${skipped} configuration${skipped === 1 ? ' was' : 's were'}` + + ` skipped because Welch's t-test requires at least 2 samples per` + + ` binary. Use --runs 2 or higher.`, + ); + } + + // --- Bar chart visualization --- + printChart(rows, maxNameLen); + + console.log(''); + console.log( + `Rates were scaled by ${scale}x into HdrHistogram (3 significant figures).\n` + + `Use --scale to adjust precision if needed.\n`, + ); + console.log( + `Be aware that when doing many comparisons the risk of a false-positive\n` + + `result increases. In this case, there are ${rows.length} comparisons, ` + + `you can thus\nexpect the following amount of false-positive results:\n` + + ` ${(rows.length * 0.05).toFixed(2)} false positives, when considering ` + + `a 5% risk acceptance (*, **, ***),\n` + + ` ${(rows.length * 0.01).toFixed(2)} false positives, when considering ` + + `a 1% risk acceptance (**, ***),\n` + + ` ${(rows.length * 0.001).toFixed(2)} false positives, when considering ` + + `a 0.1% risk acceptance (***)`, + ); + + // Gate: exit with error if any significant regression exceeds the limit. + if (maxRegression > 0) { + const failures = rows.filter( + (r) => r.stars.trim() !== '' && r.improvement < -maxRegression, + ); + if (failures.length > 0) { + console.log(''); + console.log( + `FAIL: ${failures.length} benchmark${failures.length === 1 ? '' : 's'}` + + ` showed a statistically significant regression exceeding` + + ` ${maxRegression}%:`, + ); + for (const f of failures) { + console.log(` ${f.name} ${f.improvement.toFixed(2)}%`); + } + process.exitCode = 1; + } + } +} + +function printChart(rows, maxNameLen) { + if (rows.length === 0) return; + + // Determine the chart scale from the data. The bar region covers + // the range [-maxAbs, +maxAbs] so the zero line sits in the center. + const barWidth = 40; + const halfWidth = barWidth / 2; + let maxAbs = 0; + for (const row of rows) { + const extent = Math.abs(row.improvement) + row.ci95; + if (extent > maxAbs) maxAbs = extent; + } + if (maxAbs === 0) maxAbs = 1; + + const pad = (s, n) => s + ' '.repeat(Math.max(0, n - s.length)); + + // Scale axis labels. + const axisLeft = `-${maxAbs.toFixed(1)}%`; + const axisRight = `+${maxAbs.toFixed(1)}%`; + const axisCenter = '0%'; + + // Print axis header. + const labelPad = maxNameLen + 5; + const leftLabel = ' '.repeat(labelPad) + + axisLeft + + ' '.repeat(Math.max(0, halfWidth - axisLeft.length - Math.floor(axisCenter.length / 2))) + + axisCenter + + ' '.repeat(Math.max(0, halfWidth - Math.ceil(axisCenter.length / 2) - axisRight.length)) + + axisRight; + console.log(''); + console.log(leftLabel); + + for (const row of rows) { + const imp = row.improvement; + const ci = row.ci95; + + // Position of the improvement value in the bar region [0, barWidth]. + const center = halfWidth; + const impPos = center + (imp / maxAbs) * halfWidth; + + // CI extent in bar positions. + const ciLeft = center + ((imp - ci) / maxAbs) * halfWidth; + const ciRight = center + ((imp + ci) / maxAbs) * halfWidth; + + // Build the bar character by character. + const chars = []; + for (let x = 0; x < barWidth; x++) { + const pos = x + 0.5; // Center of this character cell. + if (x === Math.floor(center)) { + chars.push('|'); + } else if ((imp >= 0 && pos > center && pos <= impPos) || + (imp < 0 && pos < center && pos >= impPos)) { + chars.push(row.stars ? '\u2588' : '\u2593'); // solid or dark shade + } else if (pos >= ciLeft && pos <= ciRight) { + chars.push('\u2591'); // Light shade for CI region + } else { + chars.push(' '); + } + } + + const label = `${row.improvement >= 0 ? '+' : ''}${row.improvement.toFixed(2)}%`; + const sig = row.stars.trim(); + console.log(`${pad(row.name, maxNameLen)} ${chars.join('')} ${label} ${sig}`); + } +} diff --git a/benchmark/esm/get-data-protocol-format.js b/benchmark/esm/get-data-protocol-format.js new file mode 100644 index 000000000000..35e54a770035 --- /dev/null +++ b/benchmark/esm/get-data-protocol-format.js @@ -0,0 +1,30 @@ +// Benchmarks defaultGetFormat() on `data:` URLs. The MIME-matching regex used +// to be susceptible to catastrophic backtracking on malformed input lacking a +// `,` separator (https://github.com/nodejs/node/issues/61904); `pathLength` +// scales the malformed path so a regression shows up as a sharp drop in ops/sec +// rather than a hang. +'use strict'; + +const common = require('../common.js'); + +const configs = { + n: [1e4], + pathLength: [1e2, 1e3, 1e4], +}; + +const options = { + flags: ['--expose-internals'], +}; + +const bench = common.createBenchmark(main, configs, options); + +function main({ n, pathLength }) { + const { defaultGetFormat } = require('internal/modules/esm/get_format'); + const url = new URL(`data:a/${'a'.repeat(pathLength)}B`); + + bench.start(); + for (let i = 0; i < n; i++) { + defaultGetFormat(url, { parentURL: undefined }); + } + bench.end(n); +} diff --git a/benchmark/fetch/headers.js b/benchmark/fetch/headers.js new file mode 100644 index 000000000000..4ff5091ebfbf --- /dev/null +++ b/benchmark/fetch/headers.js @@ -0,0 +1,94 @@ +'use strict'; +const common = require('../common.js'); + +const bench = common.createBenchmark(main, { + n: [1e5], + method: [ + 'construct-empty', + 'construct-object', + 'construct-headers', + 'get', + 'get-common', + 'set', + 'append', + 'has', + 'delete', + 'iterate', + ], +}); + +const objectInit = { + 'Accept': 'application/json', + 'Content-Type': 'text/plain', + 'User-Agent': 'benchmark', + 'Authorization': 'Bearer token', + 'Cookie': 'a=1', + 'X-Request-Id': 'abc', + 'Cache-Control': 'no-cache', + 'Host': 'example.com', +}; + +function main({ n, method }) { + const headers = new Headers(objectInit); + const copySource = new Headers(objectInit); + let result; + + bench.start(); + switch (method) { + case 'construct-empty': + for (let i = 0; i < n; i++) + new Headers(); + break; + case 'construct-object': + for (let i = 0; i < n; i++) + new Headers(objectInit); + break; + case 'construct-headers': + for (let i = 0; i < n; i++) + new Headers(copySource); + break; + case 'get': + for (let i = 0; i < n; i++) + result = headers.get('x-request-id'); + break; + case 'get-common': + for (let i = 0; i < n; i++) + result = headers.get('content-type'); + break; + case 'set': + for (let i = 0; i < n; i++) + headers.set('x-count', i); + break; + case 'append': + for (let i = 0; i < n; i++) { + const current = new Headers(); + current.append('Accept', 'text/html'); + current.append('X-Custom', i); + } + break; + case 'has': + for (let i = 0; i < n; i++) + result = headers.has('authorization'); + break; + case 'delete': { + for (let i = 0; i < n; i++) { + const current = new Headers(objectInit); + current.delete('content-type'); + } + break; + } + case 'iterate': + for (let i = 0; i < n; i++) { + for (const entry of headers) + result = entry; + } + break; + default: + throw new Error(`Unexpected method "${method}"`); + } + bench.end(n); + + // Keep a live use so V8 cannot DCE the loop. + if (result === Symbol.for('benchmark-never')) + throw new Error('unreachable'); +} diff --git a/benchmark/http/bench-parser.js b/benchmark/http/bench-parser.js index 0a1e8f7b5e8a..72cb2b6feb18 100644 --- a/benchmark/http/bench-parser.js +++ b/benchmark/http/bench-parser.js @@ -31,6 +31,8 @@ function main({ len, n }) { function newParser(type) { const parser = new HTTPParser(); parser.initialize(type, {}); + // Direct parsers bypass cleanParser(); use its production default. + parser.maxHeaderPairs = 2000; parser.headers = []; diff --git a/benchmark/http/end-string.js b/benchmark/http/end-string.js new file mode 100644 index 000000000000..9c5c6afc5869 --- /dev/null +++ b/benchmark/http/end-string.js @@ -0,0 +1,35 @@ +// Responses sent as a single res.end(string) with a known Content-Length - +// the shape a JSON or HTML endpoint produces. +'use strict'; + +const common = require('../common.js'); + +const bench = common.createBenchmark(main, { + len: [4, 64, 1024, 16384, 102400], + c: [50], + duration: 5, +}); + +function main({ len, c, duration }) { + const http = require('http'); + const body = 'a'.repeat(len); + const headers = { + 'Content-Type': 'text/plain', + 'Content-Length': `${len}`, + }; + + const server = http.createServer((req, res) => { + res.writeHead(200, headers); + res.end(body); + }); + + server.listen(0, () => { + bench.http({ + connections: c, + duration, + port: server.address().port, + }, () => { + server.close(); + }); + }); +} diff --git a/benchmark/net/net-blocklist.js b/benchmark/net/net-blocklist.js new file mode 100644 index 000000000000..9c293682ff61 --- /dev/null +++ b/benchmark/net/net-blocklist.js @@ -0,0 +1,146 @@ +'use strict'; + +const common = require('../common.js'); +const { BlockList, SocketAddress } = require('net'); + +const hasAddAddresses = typeof BlockList.prototype.addAddresses === 'function'; + +const operations = ['check', 'checkWithSocketAddress', 'addAddress']; +if (hasAddAddresses) { + operations.push('addAddresses'); +} + +const bench = common.createBenchmark(main, { + n: [1e6], + ruleCount: [10, 100, 1000, 10000], + ruleType: ['address', 'subnet', 'mixed'], + checkResult: ['hit', 'miss'], + operation: operations, +}, { + combinationFilter({ operation, ruleCount, ruleType }) { + // addAddress and addAddresses only need address rules, not subnets. + if ((operation === 'addAddress' || operation === 'addAddresses') && + ruleType !== 'address') { + return false; + } + return true; + }, +}); + +function generateIPv4(index) { + return `${(index >>> 24) & 0xff}.${(index >>> 16) & 0xff}.` + + `${(index >>> 8) & 0xff}.${index & 0xff}`; +} + +function buildBlockList(ruleCount, ruleType) { + const blockList = new BlockList(); + + if (ruleType === 'address' || ruleType === 'mixed') { + const addressCount = ruleType === 'mixed' ? + Math.floor(ruleCount / 2) : ruleCount; + const addresses = []; + for (let i = 0; i < addressCount; i++) { + // Start from 10.0.0.1 to avoid 0.0.0.0 + addresses.push(generateIPv4(0x0a000001 + i)); + } + if (hasAddAddresses) { + blockList.addAddresses(addresses); + } else { + for (const addr of addresses) { + blockList.addAddress(addr); + } + } + } + + if (ruleType === 'subnet' || ruleType === 'mixed') { + const subnetCount = ruleType === 'mixed' ? + Math.floor(ruleCount / 2) : ruleCount; + for (let i = 0; i < subnetCount; i++) { + // Use distinct /24 subnets: 172.i.j.0/24 + const second = (i >>> 8) & 0xff; + const third = i & 0xff; + blockList.addSubnet(`172.${second}.${third}.0`, 24); + } + } + + return blockList; +} + +function main({ n, ruleCount, ruleType, checkResult, operation }) { + if (operation === 'check') { + benchCheck(n, ruleCount, ruleType, checkResult); + } else if (operation === 'checkWithSocketAddress') { + benchCheckWithSocketAddress(n, ruleCount, ruleType, checkResult); + } else if (operation === 'addAddress') { + benchAddAddress(n, ruleCount); + } else if (operation === 'addAddresses') { + benchAddAddresses(n, ruleCount); + } +} + +// Benchmark check() with string addresses (the common JS API path). +function benchCheck(n, ruleCount, ruleType, checkResult) { + const blockList = buildBlockList(ruleCount, ruleType); + + // For 'hit', use an address that's in the list. + // For 'miss', use an address that's not in the list. + const address = checkResult === 'hit' ? '10.0.0.1' : '192.168.255.255'; + + bench.start(); + for (let i = 0; i < n; i++) { + blockList.check(address); + } + bench.end(n); +} + +// Benchmark check() with pre-created SocketAddress objects +// (avoids measuring SocketAddress construction overhead). +function benchCheckWithSocketAddress(n, ruleCount, ruleType, checkResult) { + const blockList = buildBlockList(ruleCount, ruleType); + + const address = checkResult === 'hit' ? '10.0.0.1' : '192.168.255.255'; + const sa = new SocketAddress({ address }); + + bench.start(); + for (let i = 0; i < n; i++) { + blockList.check(sa); + } + bench.end(n); +} + +// Benchmark single addAddress() calls (one lock acquire per call). +function benchAddAddress(n, ruleCount) { + // Scale n down for large rule counts to keep runtime reasonable. + const iterations = Math.min(n, ruleCount * 100); + + const addresses = []; + for (let i = 0; i < ruleCount; i++) { + addresses.push(generateIPv4(0x0a000001 + i)); + } + + bench.start(); + for (let i = 0; i < iterations; i++) { + const blockList = new BlockList(); + for (let j = 0; j < addresses.length; j++) { + blockList.addAddress(addresses[j]); + } + } + bench.end(iterations); +} + +// Benchmark batch addAddresses() (one lock acquire per batch). +function benchAddAddresses(n, ruleCount) { + const iterations = Math.min(n, ruleCount * 100); + + const addresses = []; + for (let i = 0; i < ruleCount; i++) { + addresses.push(generateIPv4(0x0a000001 + i)); + } + + bench.start(); + for (let i = 0; i < iterations; i++) { + const blockList = new BlockList(); + blockList.addAddresses(addresses); + } + bench.end(iterations); +} diff --git a/benchmark/repl/completion.js b/benchmark/repl/completion.js new file mode 100644 index 000000000000..b9f55d8416b0 --- /dev/null +++ b/benchmark/repl/completion.js @@ -0,0 +1,53 @@ +'use strict'; + +const common = require('../common.js'); +const repl = require('node:repl'); +const { PassThrough, Writable } = require('node:stream'); + +const bench = common.createBenchmark(main, { + n: [5e3], + query: [ + 'cons', + 'console.lo', + 'Buffer.prototype.wri', + "require('f", + ], + useGlobal: [0, 1], +}); + +function main({ n, query, useGlobal }) { + const input = new PassThrough(); + const output = new Writable({ write(c, e, cb) { cb(); } }); + const server = new repl.REPLServer({ + input, + output, + terminal: false, + useGlobal: !!useGlobal, + }); + + // Inspector callbacks do not keep the event loop alive on their own. + const keepAlive = setInterval(() => {}, 0x7fffffff); + let remaining = n; + + function complete() { + server.complete(query, onComplete); + } + + function onComplete(err) { + if (err) { + throw err; + } + + if (--remaining === 0) { + bench.end(n); + clearInterval(keepAlive); + server.close(); + return; + } + + setImmediate(complete); + } + + bench.start(); + setImmediate(complete); +} diff --git a/benchmark/repl/creation.js b/benchmark/repl/creation.js new file mode 100644 index 000000000000..60e795063d19 --- /dev/null +++ b/benchmark/repl/creation.js @@ -0,0 +1,39 @@ +'use strict'; + +const common = require('../common.js'); +const repl = require('node:repl'); +const { PassThrough, Writable } = require('node:stream'); + +const bench = common.createBenchmark(main, { + n: [500], + preview: [0, 1], + terminal: [0, 1], + useGlobal: [0, 1], +}, { + combinationFilter: ({ preview, terminal }) => !!terminal || !preview, +}); + +function main({ n, preview, terminal, useGlobal }) { + const inputs = Array.from({ length: n }, () => new PassThrough()); + const outputs = Array.from( + { length: n }, + () => new Writable({ write(c, e, cb) { cb(); } }), + ); + const servers = new Array(n); + + bench.start(); + for (let i = 0; i < n; i++) { + servers[i] = new repl.REPLServer({ + input: inputs[i], + output: outputs[i], + preview: !!preview, + terminal: !!terminal, + useGlobal: !!useGlobal, + }); + } + bench.end(n); + + for (const server of servers) { + server.close(); + } +} diff --git a/benchmark/repl/evaluate.js b/benchmark/repl/evaluate.js new file mode 100644 index 000000000000..48376a2b48fe --- /dev/null +++ b/benchmark/repl/evaluate.js @@ -0,0 +1,57 @@ +'use strict'; + +const common = require('../common.js'); +const repl = require('node:repl'); +const { PassThrough, Writable } = require('node:stream'); + +const bench = common.createBenchmark(main, { + n: [2e4], + code: [ + '1 + 1', + '({ answer: 42 })', + 'Promise.resolve(42)', + 'await Promise.resolve(42)', + ], + mode: ['sloppy', 'strict'], + useGlobal: [0, 1], +}); + +function main({ n, code, mode, useGlobal }) { + const input = new PassThrough(); + const output = new Writable({ write(c, e, cb) { cb(); } }); + const server = new repl.REPLServer({ + input, + output, + replMode: mode === 'strict' ? + repl.REPL_MODE_STRICT : + repl.REPL_MODE_SLOPPY, + terminal: false, + useGlobal: !!useGlobal, + }); + + // Inspector callbacks do not keep the event loop alive on their own. + const keepAlive = setInterval(() => {}, 0x7fffffff); + let remaining = n; + + function evaluate() { + server.eval(`${code}\n`, server.context, 'repl', onEvaluate); + } + + function onEvaluate(err) { + if (err) { + throw err; + } + + if (--remaining === 0) { + bench.end(n); + clearInterval(keepAlive); + server.close(); + return; + } + + setImmediate(evaluate); + } + + bench.start(); + setImmediate(evaluate); +} diff --git a/benchmark/repl/process-lines.js b/benchmark/repl/process-lines.js new file mode 100644 index 000000000000..fd019512f9fc --- /dev/null +++ b/benchmark/repl/process-lines.js @@ -0,0 +1,52 @@ +'use strict'; + +const common = require('../common.js'); +const repl = require('node:repl'); +const { PassThrough, Writable } = require('node:stream'); + +const bench = common.createBenchmark(main, { + n: [1e4], + code: [ + '1 + 1\n', + 'Promise.resolve(42)\n', + ], + mode: ['sloppy', 'strict'], + terminal: [0, 1], + useGlobal: [0, 1], +}); + +function main({ n, code: inputCode, mode, terminal, useGlobal }) { + const input = new PassThrough(); + const output = new Writable({ write(c, e, cb) { cb(); } }); + const server = new repl.REPLServer({ + input, + output, + replMode: mode === 'strict' ? + repl.REPL_MODE_STRICT : + repl.REPL_MODE_SLOPPY, + terminal: !!terminal, + useGlobal: !!useGlobal, + }); + const originalEval = server.eval; + // TTY input dispatch can briefly have no other active event loop handles. + const keepAlive = setInterval(() => {}, 0x7fffffff); + let remaining = n; + + // eslint-disable-next-line node-core/func-name-matching + server.eval = function REPLEval(code, context, file, callback) { + originalEval(code, context, file, function onEvaluate() { + const result = Reflect.apply(callback, this, arguments); + if (--remaining === 0) { + bench.end(n); + clearInterval(keepAlive); + server.close(); + } else { + setImmediate(() => input.write(inputCode)); + } + return result; + }); + }; + + bench.start(); + input.write(inputCode); +} diff --git a/benchmark/repl/reset-context.js b/benchmark/repl/reset-context.js new file mode 100644 index 000000000000..ab96f92564f2 --- /dev/null +++ b/benchmark/repl/reset-context.js @@ -0,0 +1,26 @@ +'use strict'; + +const common = require('../common.js'); +const repl = require('node:repl'); +const { PassThrough, Writable } = require('node:stream'); + +const bench = common.createBenchmark(main, { + n: [1e3], +}); + +function main({ n }) { + const input = new PassThrough(); + const output = new Writable({ write(c, e, cb) { cb(); } }); + const server = new repl.REPLServer({ + input, + output, + terminal: false, + }); + + bench.start(); + for (let i = 0; i < n; i++) { + server.resetContext(); + } + bench.end(n); + server.close(); +} diff --git a/benchmark/sqlite/sqlite-is-transaction.js b/benchmark/sqlite/sqlite-is-transaction.js index 3bfc896cf91c..dca31a18d986 100644 --- a/benchmark/sqlite/sqlite-is-transaction.js +++ b/benchmark/sqlite/sqlite-is-transaction.js @@ -16,14 +16,14 @@ function main(conf) { } let i; - let deadCodeElimination = true; + let deadCodeElimination; bench.start(); for (i = 0; i < conf.n; i += 1) - deadCodeElimination &&= db.isTransaction; + deadCodeElimination = db.isTransaction; bench.end(conf.n); - assert.ok(deadCodeElimination === (conf.transaction === 'true')); + assert.strictEqual(deadCodeElimination, conf.transaction === 'true'); if (conf.transaction === 'true') { db.exec('ROLLBACK'); diff --git a/benchmark/test_runner/hooks.js b/benchmark/test_runner/hooks.js new file mode 100644 index 000000000000..dc73ff4fb1e1 --- /dev/null +++ b/benchmark/test_runner/hooks.js @@ -0,0 +1,51 @@ +'use strict'; + +const common = require('../common'); +const { finished } = require('node:stream/promises'); +const reporter = require('../fixtures/empty-test-reporter'); +const { + after, + afterEach, + before, + beforeEach, + describe, + it, +} = require('node:test'); + +const bench = common.createBenchmark(main, { + n: [1000], + hook: ['before', 'after', 'beforeEach', 'afterEach'], +}, { + // We don't want to test the reporter here. + flags: ['--test-reporter=./benchmark/fixtures/empty-test-reporter.js'], +}); + +const hookList = { + before: before, + after: after, + beforeEach: beforeEach, + afterEach: afterEach, +}; + +const noop = () => {}; + +function run(loopAmount, hookFn) { + for (let i = 0; i < loopAmount; i++) { + describe(`${i}`, () => { + hookFn(noop); + it(`${i}`, noop); + }); + } + + return finished(reporter); +} + +function main(params) { + const hookFn = hookList[params.hook]; + + bench.start(); + + run(params.n, hookFn).then(() => { + bench.end(params.n); + }); +} diff --git a/benchmark/test_runner/mock-timers.js b/benchmark/test_runner/mock-timers.js new file mode 100644 index 000000000000..4815c20ecd73 --- /dev/null +++ b/benchmark/test_runner/mock-timers.js @@ -0,0 +1,262 @@ +'use strict'; + +const common = require('../common'); +const assert = require('node:assert'); +const { test } = require('node:test'); +const nodeTimersPromises = require('node:timers/promises'); + +const bench = common.createBenchmark(main, { + n: [1000], + mode: [ + 'enable-empty-apis', + 'enable-setTimeout', + 'enable-setInterval', + 'enable-setImmediate', + 'enable-Date', + 'enable-scheduler.wait', + 'enable-AbortSignal.timeout', + 'enable-all', + 'enable-default', + 'setTimeout', + 'setInterval', + 'setImmediate', + 'scheduler.wait', + 'AbortSignal.timeout', + 'Date', + 'setTime', + 'runAll', + ], +}, { + // We don't want to test the reporter here. + flags: ['--test-reporter=./benchmark/fixtures/empty-test-reporter.js'], +}); + +function benchmarkEnable(n, mode) { + const enableMode = mode.replace('enable-', ''); + let enableOptions = { apis: [enableMode] }; + + if (enableMode === 'all') { + enableOptions.apis = ['setTimeout', 'setInterval', 'setImmediate', 'Date', 'scheduler.wait', 'AbortSignal.timeout']; + } + + if (enableMode === 'empty-apis') { + enableOptions.apis = []; + } + + if (enableMode === 'default') { + enableOptions = undefined; + } + + test((t) => { + bench.start(); + + for (let i = 0; i < n; i++) { + t.mock.timers.enable(enableOptions); + t.mock.timers.reset(); + } + + bench.end(n); + }); +} + +function benchmarkSetTimeout(n) { + test((t) => { + let noDead; + + t.mock.timers.enable({ apis: ['setTimeout'] }); + bench.start(); + + for (let i = 0; i < n; i++) { + setTimeout(() => { + noDead = i; + }, i + 1); + } + + t.mock.timers.tick(n + 1); + bench.end(n); + + assert.strictEqual(noDead, n - 1); + }); +} + +function benchmarkSetInterval(n) { + test((t) => { + let noDead = 0; + + t.mock.timers.enable({ apis: ['setInterval'] }); + + setInterval(() => { + noDead++; + }, 1); + + bench.start(); + + t.mock.timers.tick(n); + + bench.end(n); + + assert.strictEqual(noDead, n); + }); +} + +function benchmarkSetImmediate(n) { + test((t) => { + let noDead; + + t.mock.timers.enable({ apis: ['setImmediate'] }); + + bench.start(); + + for (let i = 0; i < n; i++) { + setImmediate(() => { + noDead = i; + }); + } + + t.mock.timers.tick(0); + bench.end(n); + + assert.strictEqual(noDead, n - 1); + }); +} + +function benchmarkSchedulerWait(n) { + test(async (t) => { + const promises = []; + let noDead; + + t.mock.timers.enable({ apis: ['scheduler.wait'] }); + + bench.start(); + + for (let i = 0; i < n; i++) { + promises.push(nodeTimersPromises.scheduler.wait(i + 1).then(() => { + noDead = i; + })); + } + + t.mock.timers.tick(n + 1); + await Promise.all(promises); + bench.end(n); + + assert.strictEqual(noDead, n - 1); + }); +} + +function benchmarkAbortSignalTimeout(n) { + test((t) => { + let noDead; + + t.mock.timers.enable({ apis: ['AbortSignal.timeout'] }); + + bench.start(); + + for (let i = 0; i < n; i++) { + noDead = AbortSignal.timeout(i + 1); + } + + t.mock.timers.tick(n + 1); + bench.end(n); + + assert.strictEqual(noDead.aborted, true); + }); +} + +function benchmarkDate(n) { + test((t) => { + let noDead; + + t.mock.timers.enable({ apis: ['Date'] }); + + bench.start(); + + for (let i = 0; i < n; i++) { + noDead = Date.now(); + } + + bench.end(n); + + assert.strictEqual(noDead, 0); + }); +} + +function benchmarkSetTime(n) { + test((t) => { + let noDead; + + t.mock.timers.enable({ apis: ['Date'] }); + + bench.start(); + + for (let i = 0; i < n; i++) { + t.mock.timers.setTime(i); + noDead = Date.now(); + } + + bench.end(n); + + assert.strictEqual(noDead, n - 1); + }); +} + +function benchmarkRunAll(n) { + test((t) => { + let noDead = 0; + + t.mock.timers.enable({ apis: ['setTimeout'] }); + + for (let i = 0; i < n; i++) { + setTimeout(() => { + noDead++; + }, i + 1); + } + + bench.start(); + + t.mock.timers.runAll(); + + bench.end(n); + + assert.strictEqual(noDead, n); + }); +} + +function main({ n, mode }) { + switch (mode) { + case 'enable-empty-apis': + case 'enable-setTimeout': + case 'enable-setInterval': + case 'enable-setImmediate': + case 'enable-Date': + case 'enable-scheduler.wait': + case 'enable-AbortSignal.timeout': + case 'enable-all': + case 'enable-default': + benchmarkEnable(n, mode); + break; + case 'setTimeout': + benchmarkSetTimeout(n); + break; + case 'setInterval': + benchmarkSetInterval(n); + break; + case 'setImmediate': + benchmarkSetImmediate(n); + break; + case 'scheduler.wait': + benchmarkSchedulerWait(n); + break; + case 'AbortSignal.timeout': + benchmarkAbortSignalTimeout(n); + break; + case 'Date': + benchmarkDate(n); + break; + case 'setTime': + benchmarkSetTime(n); + break; + case 'runAll': + benchmarkRunAll(n); + break; + } +} diff --git a/benchmark/test_runner/test-only.js b/benchmark/test_runner/test-only.js new file mode 100644 index 000000000000..fe79f10dfdd8 --- /dev/null +++ b/benchmark/test_runner/test-only.js @@ -0,0 +1,39 @@ +'use strict'; + +const common = require('../common'); +const { finished } = require('node:stream/promises'); +const reporter = require('../fixtures/empty-test-reporter'); +const { test } = require('node:test'); + +const bench = common.createBenchmark(main, { + n: [10000], + selected: [1], +}, { + // We don't want to test the reporter here. + flags: [ + '--test-reporter=./benchmark/fixtures/empty-test-reporter.js', + '--test-only', + ], +}); + +async function run({ n, selected }) { + for (let i = 0; i < selected; i++) { + test(`selected-${i}`, { only: true }, () => {}); + } + + for (let i = 0; i < n; i++) { + test(`not-selected-${i}`, () => { + throw new Error(`This test ${i} should not run.`); + }); + } + + return finished(reporter); +} + +function main(params) { + bench.start(); + + run(params).then(() => { + bench.end(params.n); + }); +} diff --git a/benchmark/test_runner/test-options.js b/benchmark/test_runner/test-options.js new file mode 100644 index 000000000000..1d608c1f9ccb --- /dev/null +++ b/benchmark/test_runner/test-options.js @@ -0,0 +1,114 @@ +'use strict'; + +const common = require('../common'); +const { finished } = require('node:stream/promises'); +const reporter = require('../fixtures/empty-test-reporter'); +const { it } = require('node:test'); + +const bench = common.createBenchmark(main, { + n: [10000], + option: [ + 'none', + 'skip', + 'skip-with-message', + 'skip-method', + 'skip-method-with-message', + 'todo', + 'todo-with-message', + 'todo-method', + 'todo-method-with-message', + ], +}, { + // We don't want to test the reporter here. + flags: ['--test-reporter=./benchmark/fixtures/empty-test-reporter.js'], +}); + +const noop = () => {}; + +const allTests = { + 'none': (loopAmount) => { + for (let i = 0; i < loopAmount; i++) { + it(`${i}`, noop); + } + + return finished(reporter); + }, + 'skip': (loopAmount) => { + for (let i = 0; i < loopAmount; i++) { + it(`${i}`, { skip: true }, () => { + throw new Error('This test should not run.'); + }); + } + + return finished(reporter); + }, + 'skip-with-message': (loopAmount) => { + for (let i = 0; i < loopAmount; i++) { + it(`${i}`, { skip: 'skip reason' }, () => { + throw new Error('This test should not run.'); + }); + } + + return finished(reporter); + }, + 'skip-method': (loopAmount) => { + for (let i = 0; i < loopAmount; i++) { + it(`${i}`, (t) => { + t.skip(); + }); + } + + return finished(reporter); + }, + 'skip-method-with-message': (loopAmount) => { + for (let i = 0; i < loopAmount; i++) { + it(`${i}`, (t) => { + t.skip('skip reason'); + }); + } + + return finished(reporter); + }, + 'todo': (loopAmount) => { + for (let i = 0; i < loopAmount; i++) { + it(`${i}`, { todo: true }, noop); + } + + return finished(reporter); + }, + 'todo-with-message': (loopAmount) => { + for (let i = 0; i < loopAmount; i++) { + it(`${i}`, { todo: 'todo reason' }, noop); + } + + return finished(reporter); + }, + 'todo-method': (loopAmount) => { + for (let i = 0; i < loopAmount; i++) { + it(`${i}`, (t) => { + t.todo(); + }); + } + + return finished(reporter); + }, + 'todo-method-with-message': (loopAmount) => { + for (let i = 0; i < loopAmount; i++) { + it(`${i}`, (t) => { + t.todo('todo reason'); + }); + } + + return finished(reporter); + }, +}; + +function main({ n, option }) { + const runOption = allTests[option]; + + bench.start(); + + runOption(n).then(() => { + bench.end(n); + }); +} diff --git a/benchmark/webstreams/encoding-streams.js b/benchmark/webstreams/encoding-streams.js new file mode 100644 index 000000000000..00759bc09eb7 --- /dev/null +++ b/benchmark/webstreams/encoding-streams.js @@ -0,0 +1,39 @@ +'use strict'; +const common = require('../common.js'); +const { + ReadableStream, + TextEncoderStream, + TextDecoderStream, +} = require('node:stream/web'); + +const bench = common.createBenchmark(main, { + n: [1e5], + kind: ['encode', 'decode'], + len: [16, 1024], +}); + +async function main({ n, kind, len }) { + const encoded = new TextEncoder().encode('a'.repeat(len)); + const decoded = 'a'.repeat(len); + let i = 0; + const rs = new ReadableStream({ + pull(controller) { + if (i++ < n) { + controller.enqueue(kind === 'encode' ? decoded : encoded); + } else { + controller.close(); + } + }, + }); + const ts = kind === 'encode' ? + new TextEncoderStream() : + new TextDecoderStream(); + + const reader = rs.pipeThrough(ts).getReader(); + bench.start(); + for (;;) { + const { done } = await reader.read(); + if (done) break; + } + bench.end(n); +} diff --git a/benchmark/webstreams/from.js b/benchmark/webstreams/from.js new file mode 100644 index 000000000000..05eca4079f1d --- /dev/null +++ b/benchmark/webstreams/from.js @@ -0,0 +1,29 @@ +'use strict'; +const common = require('../common.js'); +const { + ReadableStream, +} = require('node:stream/web'); + +const bench = common.createBenchmark(main, { + n: [1e6], + kind: ['sync', 'async'], +}); + +async function main({ n, kind }) { + function* syncGen() { + for (let i = 0; i < n; i++) yield i; + } + + async function* asyncGen() { + for (let i = 0; i < n; i++) yield i; + } + + const reader = ReadableStream.from( + kind === 'sync' ? syncGen() : asyncGen()).getReader(); + bench.start(); + for (;;) { + const { done } = await reader.read(); + if (done) break; + } + bench.end(n); +} diff --git a/benchmark/webstreams/pipe-through.js b/benchmark/webstreams/pipe-through.js new file mode 100644 index 000000000000..8af088f4eed1 --- /dev/null +++ b/benchmark/webstreams/pipe-through.js @@ -0,0 +1,38 @@ +'use strict'; +const common = require('../common.js'); +const { + ReadableStream, + TransformStream, +} = require('node:stream/web'); + +const bench = common.createBenchmark(main, { + n: [5e5], + kind: ['default', 'transform'], +}); + +async function main({ n, kind }) { + const b = Buffer.alloc(64); + let i = 0; + const rs = new ReadableStream({ + pull(controller) { + if (i++ < n) { + controller.enqueue(b); + } else { + controller.close(); + } + }, + }); + const ts = kind === 'default' ? + new TransformStream() : + new TransformStream({ + transform(chunk, controller) { controller.enqueue(chunk); }, + }); + + const reader = rs.pipeThrough(ts).getReader(); + bench.start(); + for (;;) { + const { done } = await reader.read(); + if (done) break; + } + bench.end(n); +} diff --git a/benchmark/webstreams/pipe-to.js b/benchmark/webstreams/pipe-to.js index 38324cd20822..e902f67a9887 100644 --- a/benchmark/webstreams/pipe-to.js +++ b/benchmark/webstreams/pipe-to.js @@ -7,8 +7,8 @@ const { const bench = common.createBenchmark(main, { n: [5e5], - highWaterMarkR: [512, 1024, 2048, 4096], - highWaterMarkW: [512, 1024, 2048, 4096], + highWaterMarkR: [1, 1024, 4096], + highWaterMarkW: [1, 1024, 4096], }); @@ -16,7 +16,6 @@ async function main({ n, highWaterMarkR, highWaterMarkW }) { const b = Buffer.alloc(1024); let i = 0; const rs = new ReadableStream({ - highWaterMark: highWaterMarkR, pull: function(controller) { if (i++ < n) { controller.enqueue(b); @@ -24,12 +23,11 @@ async function main({ n, highWaterMarkR, highWaterMarkW }) { controller.close(); } }, - }); + }, { highWaterMark: highWaterMarkR }); const ws = new WritableStream({ - highWaterMark: highWaterMarkW, write(chunk, controller) {}, close() { bench.end(n); }, - }); + }, { highWaterMark: highWaterMarkW }); bench.start(); rs.pipeTo(ws); diff --git a/configure.py b/configure.py index 7fd64a9620e3..3c3b5a34925b 100755 --- a/configure.py +++ b/configure.py @@ -1015,7 +1015,7 @@ action='store_true', dest='enable_static', default=None, - help='build as static library') + help=argparse.SUPPRESS) # Deprecated parser.add_argument('--no-browser-globals', action='store_true', @@ -1405,7 +1405,7 @@ def get_openssl_version(o): return version_number - except (OSError, ValueError, subprocess.SubprocessError) as e: + except (OSError, TypeError, ValueError, subprocess.SubprocessError) as e: warn(f'Failed to determine OpenSSL version from header: {e}') return 0 @@ -1862,9 +1862,6 @@ def configure_node(o): if options.v8_options: o['variables']['node_v8_options'] = options.v8_options.replace('"', '\\"') - if options.enable_static: - o['variables']['node_target_type'] = 'static_library' - o['variables']['node_debug_lib'] = b(options.node_debug_lib) if options.debug_nghttp2: @@ -1907,10 +1904,13 @@ def configure_node(o): else: o['variables']['coverage'] = 'false' + if options.enable_static and options.shared: + error('--enable-static must not be set with --shared') + if options.enable_static: + warn('--enable-static is deprecated and libnode.a is always produced') + if options.shared: o['variables']['node_target_type'] = 'shared_library' - elif options.enable_static: - o['variables']['node_target_type'] = 'static_library' else: o['variables']['node_target_type'] = 'executable' diff --git a/deps/corepack/CHANGELOG.md b/deps/corepack/CHANGELOG.md index be8dfa5c8cb8..c90032328ab3 100644 --- a/deps/corepack/CHANGELOG.md +++ b/deps/corepack/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## [0.36.0](https://github.com/nodejs/corepack/compare/v0.35.0...v0.36.0) (2026-08-28) + + +### Features + +* add `COREPACK_ON_UNVERIFIED_DOWNLOAD` env variable ([#856](https://github.com/nodejs/corepack/issues/856)) ([0125d89](https://github.com/nodejs/corepack/commit/0125d89ac904672bb42bc48bb6612d137beeccda)) +* fall back to package-root metadata when dist.signatures is missing on the version endpoint ([#870](https://github.com/nodejs/corepack/issues/870)) ([b26c9d5](https://github.com/nodejs/corepack/commit/b26c9d52fdbc5db326e631de3f6557f7e1b7e55d)) +* only load closest env file, for every commands ([#891](https://github.com/nodejs/corepack/issues/891)) ([b856c51](https://github.com/nodejs/corepack/commit/b856c516c3d0a92ded6b3f9cbbaa0d3f3eb094f1)) +* update package manager versions ([#852](https://github.com/nodejs/corepack/issues/852)) ([7e613b8](https://github.com/nodejs/corepack/commit/7e613b84b079411cb9eab1f90b254597fb9ef70c)) +* use range from `devEngines` when no `packageManager` is set ([#892](https://github.com/nodejs/corepack/issues/892)) ([dec830b](https://github.com/nodejs/corepack/commit/dec830b035f540d1b4ebc516e81fbf43c5e0ffcf)) + + +### Bug Fixes + +* **npmRegistryUtils:** env vars names in integrity check fail error message ([#854](https://github.com/nodejs/corepack/issues/854)) ([8ca01c3](https://github.com/nodejs/corepack/commit/8ca01c3fbeed6c8b5d1bb94df1aacb3fe6cff846)) +* strip trailing slashes from COREPACK_NPM_REGISTRY ([#871](https://github.com/nodejs/corepack/issues/871)) ([b81e92c](https://github.com/nodejs/corepack/commit/b81e92c2338ed6c4c38cfe1239002a261e47e6d5)) + ## [0.35.0](https://github.com/nodejs/corepack/compare/v0.34.7...v0.35.0) (2026-05-15) diff --git a/deps/corepack/README.md b/deps/corepack/README.md index dd32b4ad09f1..e2adeb94958c 100644 --- a/deps/corepack/README.md +++ b/deps/corepack/README.md @@ -127,9 +127,9 @@ Depending on the value of `devEngines.packageManager.onFail`: of mismatch. If the top-level `packageManager` field is missing, Corepack will use the -package manager defined in `devEngines.packageManager` – in which case you must -provide a specific version in `devEngines.packageManager.version`, ideally with -a hash, as explained in the previous section: +package manager defined in `devEngines.packageManager`. You should provide a +specific version in `devEngines.packageManager.version`, ideally with a hash, as +explained in the previous section: ```json { @@ -142,6 +142,16 @@ a hash, as explained in the previous section: } ``` +When `devEngines.packageManager.version` is a range rather than a specific +version, Corepack resolves it the same way as when a range is given on the +command line: the latest version matching the range is looked up on the npm +registry, which means the resolution requires network access (or a cache +containing a matching version, see [Offline Workflow](#offline-workflow)), and +may change over time. Set `COREPACK_ENABLE_AUTO_PIN=1` to have Corepack add the +resolved version to the `packageManager` field. When +`devEngines.packageManager.version` is missing, Corepack falls back to its +[Known Good Release](#known-good-releases) for that package manager. + ## Known Good Releases When running Corepack within projects that don't list a supported package @@ -349,6 +359,19 @@ same major line. Should you need to upgrade to a new major, use an explicit environment variables are required and as plain text. If you want to send an empty password, explicitly set `COREPACK_NPM_PASSWORD` to an empty string. +- `COREPACK_ON_UNVERIFIED_DOWNLOAD` can be set to: + - `warn` (case insensitive): attempting to download an unsigned version without + providing a hash will emit a warning to stderr. + - `error` (case insensitive): attempting to download an unsigned version without + providing a hash will fail with an error, and nothing gets downloaded. + - `strict-warn` (case insensitive): same as `warn`, and additionally emits a + warning when downloading a version that is not pinned by a hash, even when + its signature can be verified. + - `strict-error` (case insensitive): same as `error`, and additionally fails + when downloading a version that is not pinned by a hash, even when its + signature can be verified. + - `ignore` (or any other unsupported value): disables that security feature. + - `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` are supported through [`NODE_USE_ENV_PROXY=1`](https://nodejs.org/api/cli.html#node_use_env_proxy1). diff --git a/deps/corepack/dist/lib/corepack.cjs b/deps/corepack/dist/lib/corepack.cjs index 478389c3e2d0..ff66960d4aee 100644 --- a/deps/corepack/dist/lib/corepack.cjs +++ b/deps/corepack/dist/lib/corepack.cjs @@ -5,11 +5,20 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; -var __esm = (fn2, res) => function __init() { - return fn2 && (res = (0, fn2[__getOwnPropNames(fn2)[0]])(fn2 = 0)), res; +var __esm = (fn2, res, err) => function __init() { + if (err) throw err[0]; + try { + return fn2 && (res = (0, fn2[__getOwnPropNames(fn2)[0]])(fn2 = 0)), res; + } catch (e) { + throw err = [e], e; + } }; var __commonJS = (cb, mod) => function __require() { - return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + try { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + } catch (e) { + throw mod = 0, e; + } }; var __export = (target, all) => { for (var name2 in all) @@ -3240,32 +3249,44 @@ var require_semver = __commonJS({ var { safeRe: re, t } = require_re(); var parseOptions = require_parse_options(); var { compareIdentifiers } = require_identifiers(); + var isPrereleaseIdentifier = (prerelease, identifier) => { + const identifiers = identifier.split("."); + if (identifiers.length > prerelease.length) { + return false; + } + for (let i = 0; i < identifiers.length; i++) { + if (compareIdentifiers(prerelease[i], identifiers[i]) !== 0) { + return false; + } + } + return true; + }; var SemVer3 = class _SemVer { - constructor(version2, options) { + constructor(version, options) { options = parseOptions(options); - if (version2 instanceof _SemVer) { - if (version2.loose === !!options.loose && version2.includePrerelease === !!options.includePrerelease) { - return version2; + if (version instanceof _SemVer) { + if (version.loose === !!options.loose && version.includePrerelease === !!options.includePrerelease) { + return version; } else { - version2 = version2.version; + version = version.version; } - } else if (typeof version2 !== "string") { - throw new TypeError(`Invalid version. Must be a string. Got type "${typeof version2}".`); + } else if (typeof version !== "string") { + throw new TypeError(`Invalid version. Must be a string. Got type "${typeof version}".`); } - if (version2.length > MAX_LENGTH) { + if (version.length > MAX_LENGTH) { throw new TypeError( `version is longer than ${MAX_LENGTH} characters` ); } - debug("SemVer", version2, options); + debug("SemVer", version, options); this.options = options; this.loose = !!options.loose; this.includePrerelease = !!options.includePrerelease; - const m = version2.trim().match(options.loose ? re[t.LOOSE] : re[t.FULL]); + const m = version.trim().match(options.loose ? re[t.LOOSE] : re[t.FULL]); if (!m) { - throw new TypeError(`Invalid Version: ${version2}`); + throw new TypeError(`Invalid Version: ${version}`); } - this.raw = version2; + this.raw = version; this.major = +m[1]; this.minor = +m[2]; this.patch = +m[3]; @@ -3486,8 +3507,9 @@ var require_semver = __commonJS({ if (identifierBase === false) { prerelease = [identifier]; } - if (compareIdentifiers(this.prerelease[0], identifier) === 0) { - if (isNaN(this.prerelease[1])) { + if (isPrereleaseIdentifier(this.prerelease, identifier)) { + const prereleaseBase = this.prerelease[identifier.split(".").length]; + if (isNaN(prereleaseBase)) { this.prerelease = prerelease; } } else { @@ -3535,12 +3557,12 @@ var require_parse = __commonJS({ "node_modules/semver/functions/parse.js"(exports2, module2) { "use strict"; var SemVer3 = require_semver(); - var parse4 = (version2, options, throwErrors = false) => { - if (version2 instanceof SemVer3) { - return version2; + var parse4 = (version, options, throwErrors = false) => { + if (version instanceof SemVer3) { + return version; } try { - return new SemVer3(version2, options); + return new SemVer3(version, options); } catch (er) { if (!throwErrors) { return null; @@ -3557,8 +3579,8 @@ var require_valid = __commonJS({ "node_modules/semver/functions/valid.js"(exports2, module2) { "use strict"; var parse4 = require_parse(); - var valid = (version2, options) => { - const v = parse4(version2, options); + var valid = (version, options) => { + const v = parse4(version, options); return v ? v.version : null; }; module2.exports = valid; @@ -3762,19 +3784,19 @@ var require_comparator = __commonJS({ toString() { return this.value; } - test(version2) { - debug("Comparator.test", version2, this.options.loose); - if (this.semver === ANY || version2 === ANY) { + test(version) { + debug("Comparator.test", version, this.options.loose); + if (this.semver === ANY || version === ANY) { return true; } - if (typeof version2 === "string") { + if (typeof version === "string") { try { - version2 = new SemVer3(version2, this.options); + version = new SemVer3(version, this.options); } catch (er) { return false; } } - return cmp(version2, this.operator, this.semver, this.options); + return cmp(version, this.operator, this.semver, this.options); } intersects(comp, options) { if (!(comp instanceof _Comparator)) { @@ -3896,6 +3918,7 @@ var require_range = __commonJS({ return this.range; } parseRange(range) { + range = range.replace(BUILDSTRIPRE, ""); const memoOpts = (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) | (this.options.loose && FLAG_LOOSE); const memoKey = memoOpts + ":" + range; const cached = cache2.get(memoKey); @@ -3950,19 +3973,19 @@ var require_range = __commonJS({ }); } // if ANY of the sets match ALL of its comparators, then pass - test(version2) { - if (!version2) { + test(version) { + if (!version) { return false; } - if (typeof version2 === "string") { + if (typeof version === "string") { try { - version2 = new SemVer3(version2, this.options); + version = new SemVer3(version, this.options); } catch (er) { return false; } } for (let i = 0; i < this.set.length; i++) { - if (testSet(this.set[i], version2, this.options)) { + if (testSet(this.set[i], version, this.options)) { return true; } } @@ -3978,12 +4001,14 @@ var require_range = __commonJS({ var SemVer3 = require_semver(); var { safeRe: re, + src, t, comparatorTrimReplace, tildeTrimReplace, caretTrimReplace } = require_re(); var { FLAG_INCLUDE_PRERELEASE, FLAG_LOOSE } = require_constants2(); + var BUILDSTRIPRE = new RegExp(src[t.BUILD], "g"); var isNullSet = (c) => c.value === "<0.0.0-0"; var isAny = (c) => c.value === ""; var isSatisfiable = (comparators, options) => { @@ -4012,20 +4037,22 @@ var require_range = __commonJS({ return comp; }; var isX = (id) => !id || id.toLowerCase() === "x" || id === "*"; + var invalidXRangeOrder = (M, m, p) => isX(M) && !isX(m) || isX(m) && p && !isX(p); var replaceTildes = (comp, options) => { return comp.trim().split(/\s+/).map((c) => replaceTilde(c, options)).join(" "); }; var replaceTilde = (comp, options) => { const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE]; + const z = options.includePrerelease ? "-0" : ""; return comp.replace(r, (_, M, m, p, pr) => { debug("tilde", comp, _, M, m, p, pr); let ret; if (isX(M)) { ret = ""; } else if (isX(m)) { - ret = `>=${M}.0.0 <${+M + 1}.0.0-0`; + ret = `>=${M}.0.0${z} <${+M + 1}.0.0-0`; } else if (isX(p)) { - ret = `>=${M}.${m}.0 <${M}.${+m + 1}.0-0`; + ret = `>=${M}.${m}.0${z} <${M}.${+m + 1}.0-0`; } else if (pr) { debug("replaceTilde pr", pr); ret = `>=${M}.${m}.${p}-${pr} <${M}.${+m + 1}.0-0`; @@ -4071,9 +4098,9 @@ var require_range = __commonJS({ debug("no pr"); if (M === "0") { if (m === "0") { - ret = `>=${M}.${m}.${p}${z} <${M}.${m}.${+p + 1}-0`; + ret = `>=${M}.${m}.${p} <${M}.${m}.${+p + 1}-0`; } else { - ret = `>=${M}.${m}.${p}${z} <${M}.${+m + 1}.0-0`; + ret = `>=${M}.${m}.${p} <${M}.${+m + 1}.0-0`; } } else { ret = `>=${M}.${m}.${p} <${+M + 1}.0.0-0`; @@ -4092,6 +4119,9 @@ var require_range = __commonJS({ const r = options.loose ? re[t.XRANGELOOSE] : re[t.XRANGE]; return comp.replace(r, (ret, gtlt, M, m, p, pr) => { debug("xRange", comp, ret, gtlt, M, m, p, pr); + if (invalidXRangeOrder(M, m, p)) { + return comp; + } const xM = isX(M); const xm = xM || isX(m); const xp = xm || isX(p); @@ -4177,13 +4207,13 @@ var require_range = __commonJS({ } return `${from} ${to}`.trim(); }; - var testSet = (set, version2, options) => { + var testSet = (set, version, options) => { for (let i = 0; i < set.length; i++) { - if (!set[i].test(version2)) { + if (!set[i].test(version)) { return false; } } - if (version2.prerelease.length && !options.includePrerelease) { + if (version.prerelease.length && !options.includePrerelease) { for (let i = 0; i < set.length; i++) { debug(set[i].semver); if (set[i].semver === Comparator.ANY) { @@ -4191,7 +4221,7 @@ var require_range = __commonJS({ } if (set[i].semver.prerelease.length > 0) { const allowed = set[i].semver; - if (allowed.major === version2.major && allowed.minor === version2.minor && allowed.patch === version2.patch) { + if (allowed.major === version.major && allowed.minor === version.minor && allowed.patch === version.patch) { return true; } } @@ -4707,7 +4737,10 @@ function envForceColor() { if (env.FORCE_COLOR.length === 0) { return 1; } - const level = Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3); + if (!new RegExp("^\\d+$", "v").test(env.FORCE_COLOR)) { + return; + } + const level = Math.min(Number(env.FORCE_COLOR), 3); if (![0, 1, 2, 3].includes(level)) { return; } @@ -4741,6 +4774,9 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) { return 2; } } + if (forceColor !== void 0 && new RegExp("^\\d+$", "v").test(env.FORCE_COLOR)) { + return forceColor; + } if ("TF_BUILD" in env && "AGENT_NAME" in env) { return 1; } @@ -4759,16 +4795,16 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) { return 1; } if ("CI" in env) { - if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => key in env)) { + if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => Object.hasOwn(env, key))) { return 3; } - if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") { + if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => Object.hasOwn(env, sign)) || env.CI_NAME === "codeship") { return 1; } return min; } if ("TEAMCITY_VERSION" in env) { - return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0; + return new RegExp("^(?:9\\.0*[1-9]\\d*\\.|\\d{2,}\\.)", "v").test(env.TEAMCITY_VERSION) ? 1 : 0; } if (env.COLORTERM === "truecolor") { return 3; @@ -4783,20 +4819,20 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) { return 3; } if ("TERM_PROGRAM" in env) { - const version2 = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10); + const version = Number((env.TERM_PROGRAM_VERSION || "").split(".", 1)[0]); switch (env.TERM_PROGRAM) { case "iTerm.app": { - return version2 >= 3 ? 3 : 2; + return version >= 3 ? 3 : 2; } case "Apple_Terminal": { return 2; } } } - if (/-256(color)?$/i.test(env.TERM)) { + if (new RegExp("-256(?:color)?$", "iv").test(env.TERM)) { return 2; } - if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) { + if (new RegExp("^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux", "iv").test(env.TERM)) { return 1; } if ("COLORTERM" in env) { @@ -6879,10 +6915,22 @@ var init_large_numbers = __esm({ }); // node_modules/tar/dist/esm/types.js -var isCode, name, code; +var isCode, normalFsTypes, name, code; var init_types = __esm({ "node_modules/tar/dist/esm/types.js"() { isCode = (c) => name.has(c); + normalFsTypes = /* @__PURE__ */ new Set([ + "0", + "", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "D" + ]); name = /* @__PURE__ */ new Map([ ["0", "File"], // same as File @@ -6927,12 +6975,13 @@ var init_types = __esm({ }); // node_modules/tar/dist/esm/header.js -var import_node_path, Header, splitPrefix, decString, decDate, numToDate, decNumber, nanUndef, decSmallNumber, MAXNUM, encNumber, encSmallNumber, octalString, padOctal, encDate, NULLS, encString; +var import_node_path, notNegative, Header, splitPrefix, decString, decDate, numToDate, decNumber, nanUndef, decSmallNumber, MAXNUM, encNumber, encSmallNumber, octalString, padOctal, encDate, NULLS, encString; var init_header = __esm({ "node_modules/tar/dist/esm/header.js"() { import_node_path = require("node:path"); init_large_numbers(); init_types(); + notNegative = (n) => n === void 0 || n < 0 ? void 0 : n; Header = class { cksumValid = false; needPax = false; @@ -6969,18 +7018,21 @@ var init_header = __esm({ if (!buf || !(buf.length >= off + 512)) { throw new Error("need 512 bytes for header"); } - this.path = ex?.path ?? decString(buf, off, 100); - this.mode = ex?.mode ?? gex?.mode ?? decNumber(buf, off + 100, 8); - this.uid = ex?.uid ?? gex?.uid ?? decNumber(buf, off + 108, 8); - this.gid = ex?.gid ?? gex?.gid ?? decNumber(buf, off + 116, 8); - this.size = ex?.size ?? gex?.size ?? decNumber(buf, off + 124, 12); - this.mtime = ex?.mtime ?? gex?.mtime ?? decDate(buf, off + 136, 12); - this.cksum = decNumber(buf, off + 148, 12); - if (gex) - this.#slurp(gex, true); - if (ex) - this.#slurp(ex); const t = decString(buf, off + 156, 1); + const isNormalFS = normalFsTypes.has(t); + const exForFields = isNormalFS ? ex : void 0; + const gexForFields = isNormalFS ? gex : void 0; + this.path = exForFields?.path ?? decString(buf, off, 100); + this.mode = exForFields?.mode ?? gexForFields?.mode ?? decNumber(buf, off + 100, 8); + this.uid = exForFields?.uid ?? gexForFields?.uid ?? decNumber(buf, off + 108, 8); + this.gid = exForFields?.gid ?? gexForFields?.gid ?? decNumber(buf, off + 116, 8); + this.size = notNegative(exForFields?.size ?? gexForFields?.size ?? decNumber(buf, off + 124, 12)); + this.mtime = exForFields?.mtime ?? gexForFields?.mtime ?? decDate(buf, off + 136, 12); + this.cksum = decNumber(buf, off + 148, 12); + if (gexForFields) + this.#slurp(gexForFields, true); + if (exForFields) + this.#slurp(exForFields); if (isCode(t)) { this.#type = t || "0"; } @@ -6992,10 +7044,10 @@ var init_header = __esm({ } this.linkpath = decString(buf, off + 157, 100); if (buf.subarray(off + 257, off + 265).toString() === "ustar\x0000") { - this.uname = ex?.uname ?? gex?.uname ?? decString(buf, off + 265, 32); - this.gname = ex?.gname ?? gex?.gname ?? decString(buf, off + 297, 32); - this.devmaj = ex?.devmaj ?? gex?.devmaj ?? decNumber(buf, off + 329, 8) ?? 0; - this.devmin = ex?.devmin ?? gex?.devmin ?? decNumber(buf, off + 337, 8) ?? 0; + this.uname = exForFields?.uname ?? gexForFields?.uname ?? decString(buf, off + 265, 32); + this.gname = exForFields?.gname ?? gexForFields?.gname ?? decString(buf, off + 297, 32); + this.devmaj = exForFields?.devmaj ?? gexForFields?.devmaj ?? decNumber(buf, off + 329, 8) ?? 0; + this.devmin = exForFields?.devmin ?? gexForFields?.devmin ?? decNumber(buf, off + 337, 8) ?? 0; if (buf[off + 475] !== 0) { const prefix = decString(buf, off + 345, 155); this.path = prefix + "/" + this.path; @@ -7022,7 +7074,7 @@ var init_header = __esm({ } #slurp(ex, gex = false) { Object.assign(this, Object.fromEntries(Object.entries(ex).filter(([k, v]) => { - return !(v === null || v === void 0 || k === "path" && gex || k === "linkpath" && gex || k === "global"); + return !(v === null || v === void 0 || k === "size" && Number(v) < 0 || k === "path" && gex || k === "linkpath" && gex || k === "global"); }))); } encode(buf, off = 0) { @@ -7253,8 +7305,36 @@ var init_pax = __esm({ return set; } const k = r.replace(/^SCHILY\.(dev|ino|nlink)/, "$1"); - const v = kv.join("="); - set[k] = /^([A-Z]+\.)?([mac]|birth|creation)time$/.test(k) ? new Date(Number(v) * 1e3) : /^[0-9]+$/.test(v) ? +v : v; + const v = kv.join("=").replace(/\0.*/, ""); + switch (k) { + case "path": + case "linkpath": + case "type": + case "charset": + case "comment": + case "gname": + case "uname": + set[k] = v; + break; + case "ctime": + case "atime": + case "mtime": + set[k] = new Date(Number(v) * 1e3); + break; + case "size": + const s = +v; + if (s >= 0) + set[k] = s; + break; + case "gid": + case "uid": + case "dev": + case "ino": + case "nlink": + case "mode": + set[k] = +v; + break; + } return set; }; } @@ -7265,7 +7345,7 @@ var platform, normalizeWindowsPath; var init_normalize_windows_path = __esm({ "node_modules/tar/dist/esm/normalize-windows-path.js"() { platform = process.env.TESTING_TAR_FAKE_PLATFORM || process.platform; - normalizeWindowsPath = platform !== "win32" ? (p) => p : (p) => p && p.replaceAll(/\\/g, "/"); + normalizeWindowsPath = platform !== "win32" ? (p) => String(p) : (p) => String(p).replaceAll(/\\/g, "/"); } }); @@ -7422,7 +7502,7 @@ var init_warn_method = __esm({ }); // node_modules/tar/dist/esm/parse.js -var import_events3, maxMetaEntrySize, gzipHeader, zstdHeader, ZIP_HEADER_LEN, STATE, WRITEENTRY, READENTRY, NEXTENTRY, PROCESSENTRY, EX, GEX, META, EMITMETA, BUFFER2, QUEUE, ENDED, EMITTEDEND, EMIT, UNZIP, CONSUMECHUNK, CONSUMECHUNKSUB, CONSUMEBODY, CONSUMEMETA, CONSUMEHEADER, CONSUMING, BUFFERCONCAT, MAYBEEND, WRITING, ABORTED2, DONE, SAW_VALID_ENTRY, SAW_NULL_BLOCK, SAW_EOF, CLOSESTREAM, noop2, Parser; +var import_events3, maxMetaEntrySize, gzipHeader, zstdHeader, ZIP_HEADER_LEN, STATE, WRITEENTRY, READENTRY, NEXTENTRY, PROCESSENTRY, EX, GEX, META, EMITMETA, BUFFER2, QUEUE, ENDED, EMITTEDEND, EMIT, UNZIP, CONSUMECHUNK, CONSUMECHUNKSUB, CONSUMEBODY, CONSUMEMETA, CONSUMEHEADER, CONSUMING, BUFFERCONCAT, MAYBEEND, WRITING, ABORTED2, DONE, SAW_VALID_ENTRY, SAW_NULL_BLOCK, SAW_EOF, CLOSESTREAM, MAX_DECOMPRESSION_RATIO, COMPRESSEDBYTESREAD, DECOMPRESSEDBYTESREAD, CHECKDECOMPRESSIONRATIO, noop2, Parser; var init_parse = __esm({ "node_modules/tar/dist/esm/parse.js"() { import_events3 = require("events"); @@ -7465,6 +7545,10 @@ var init_parse = __esm({ SAW_NULL_BLOCK = /* @__PURE__ */ Symbol("sawNullBlock"); SAW_EOF = /* @__PURE__ */ Symbol("sawEOF"); CLOSESTREAM = /* @__PURE__ */ Symbol("closeStream"); + MAX_DECOMPRESSION_RATIO = 1e3; + COMPRESSEDBYTESREAD = /* @__PURE__ */ Symbol("compressedBytesRead"); + DECOMPRESSEDBYTESREAD = /* @__PURE__ */ Symbol("decompressedBytesRead"); + CHECKDECOMPRESSIONRATIO = /* @__PURE__ */ Symbol("checkDecompressionRatio"); noop2 = () => true; Parser = class extends import_events3.EventEmitter { file; @@ -7473,6 +7557,7 @@ var init_parse = __esm({ filter; brotli; zstd; + maxDecompressionRatio; writable = true; readable = false; [QUEUE] = []; @@ -7492,6 +7577,8 @@ var init_parse = __esm({ [WRITING] = false; [CONSUMING] = false; [EMITTEDEND] = false; + [COMPRESSEDBYTESREAD] = 0; + [DECOMPRESSEDBYTESREAD] = 0; constructor(opt = {}) { super(); this.file = opt.file || ""; @@ -7510,6 +7597,7 @@ var init_parse = __esm({ }); } this.strict = !!opt.strict; + this.maxDecompressionRatio = typeof opt.maxDecompressionRatio === "number" ? opt.maxDecompressionRatio : MAX_DECOMPRESSION_RATIO; this.maxMetaEntrySize = opt.maxMetaEntrySize || maxMetaEntrySize; this.filter = typeof opt.filter === "function" ? opt.filter : noop2; const isTBR = opt.file && (opt.file.endsWith(".tar.br") || opt.file.endsWith(".tbr")); @@ -7710,10 +7798,29 @@ var init_parse = __esm({ } } abort(error) { + if (this[ABORTED2]) { + return; + } + if (this[UNZIP]) { + const u = this[UNZIP]; + u.write = () => true; + u.end = () => u; + u.emit = () => false; + u.destroy?.(); + } this[ABORTED2] = true; this.emit("abort", error); this.warn("TAR_ABORT", error, { recoverable: false }); } + [CHECKDECOMPRESSIONRATIO](chunk) { + this[DECOMPRESSEDBYTESREAD] += chunk.length; + const ratio = this[DECOMPRESSEDBYTESREAD] / this[COMPRESSEDBYTESREAD]; + if (ratio > this.maxDecompressionRatio) { + this.abort(new Error(`max decompression ratio exceeded: ${ratio.toFixed(2)} > ${this.maxDecompressionRatio}`)); + return false; + } + return true; + } write(chunk, encoding, cb) { if (typeof encoding === "function") { cb = encoding; @@ -7779,13 +7886,22 @@ var init_parse = __esm({ const ended = this[ENDED]; this[ENDED] = false; this[UNZIP] = this[UNZIP] === void 0 ? new Unzip({}) : isZstd ? new ZstdDecompress({}) : new BrotliDecompress({}); - this[UNZIP].on("data", (chunk2) => this[CONSUMECHUNK](chunk2)); - this[UNZIP].on("error", (er) => this.abort(er)); + this[UNZIP].on("data", (chunk2) => { + if (this[CHECKDECOMPRESSIONRATIO](chunk2)) { + this[CONSUMECHUNK](chunk2); + } + }); + this[UNZIP].on("error", (er) => { + if (!this[ABORTED2]) { + this.abort(er); + } + }); this[UNZIP].on("end", () => { this[ENDED] = true; this[CONSUMECHUNK](); }); this[WRITING] = true; + this[COMPRESSEDBYTESREAD] += chunk.length; const ret2 = !!this[UNZIP][ended ? "end" : "write"](chunk); this[WRITING] = false; cb?.(); @@ -7794,6 +7910,7 @@ var init_parse = __esm({ } this[WRITING] = true; if (this[UNZIP]) { + this[COMPRESSEDBYTESREAD] += chunk.length; this[UNZIP].write(chunk); } else { this[CONSUMECHUNK](chunk); @@ -7815,7 +7932,7 @@ var init_parse = __esm({ if (this[ENDED] && !this[EMITTEDEND] && !this[ABORTED2] && !this[CONSUMING]) { this[EMITTEDEND] = true; const entry = this[WRITEENTRY]; - if (entry && entry.blockRemain) { + if (entry?.blockRemain) { const have = this[BUFFER2] ? this[BUFFER2].length : 0; this.warn("TAR_BAD_ARCHIVE", `Truncated input (needed ${entry.blockRemain} more bytes, only ${have} available)`, { entry }); if (this[BUFFER2]) { @@ -7895,8 +8012,10 @@ var init_parse = __esm({ this.once("finish", cb); if (!this[ABORTED2]) { if (this[UNZIP]) { - if (chunk) + if (chunk) { + this[COMPRESSEDBYTESREAD] += chunk.length; this[UNZIP].write(chunk); + } this[UNZIP].end(); } else { this[ENDED] = true; @@ -7954,14 +8073,19 @@ var init_list = __esm({ filesFilter = (opt, files) => { const map = new Map(files.map((f) => [stripTrailingSlashes(f), true])); const filter = opt.filter; - const mapHas = (file, r = "") => { + const MAX2 = 100; + const mapHas = (file, r = "", depth = 0) => { + if (depth >= MAX2) { + map.set(file, false); + return false; + } const root = r || (0, import_path2.parse)(file).root || "."; let ret; if (file === root) ret = false; else { const m = map.get(file); - ret = m !== void 0 ? m : mapHas((0, import_path2.dirname)(file), root); + ret = m !== void 0 ? m : mapHas((0, import_path2.dirname)(file), root, depth + 1); } map.set(file, ret); return ret; @@ -8660,7 +8784,7 @@ var init_unpack = __esm({ this.gid = void 0; this.setOwner = false; } - this.preserveOwner = opt.preserveOwner === void 0 && typeof opt.uid !== "number" ? !!(process.getuid && process.getuid() === 0) : !!opt.preserveOwner; + this.preserveOwner = opt.preserveOwner === void 0 && typeof opt.uid !== "number" ? !!(process.getuid?.() === 0) : !!opt.preserveOwner; this.processUid = (this.preserveOwner || this.setOwner) && process.getuid ? process.getuid() : void 0; this.processGid = (this.preserveOwner || this.setOwner) && process.getgid ? process.getgid() : void 0; this.maxDepth = typeof opt.maxDepth === "number" ? opt.maxDepth : DEFAULT_MAX_DEPTH; @@ -8819,7 +8943,7 @@ var init_unpack = __esm({ } } [MKDIR](dir, mode, cb) { - mkdir(normalizeWindowsPath(dir), { + void mkdir(normalizeWindowsPath(dir), { uid: this.uid, gid: this.gid, processUid: this.processUid, @@ -9574,8 +9698,8 @@ var require_v8_compile_cache = __commonJS({ } const dirname2 = typeof process.getuid === "function" ? "v8-compile-cache-" + process.getuid() : "v8-compile-cache"; const arch = process.arch; - const version2 = typeof process.versions.v8 === "string" ? process.versions.v8 : typeof process.versions.chakracore === "string" ? "chakracore-" + process.versions.chakracore : "node-" + process.version; - const cacheDir = path16.join(os3.tmpdir(), dirname2, arch, version2); + const version = typeof process.versions.v8 === "string" ? process.versions.v8 : typeof process.versions.chakracore === "string" ? "chakracore-" + process.versions.chakracore : "node-" + process.version; + const cacheDir = path16.join(os3.tmpdir(), dirname2, arch, version); return cacheDir; } function getMainName() { @@ -9613,13 +9737,13 @@ var require_satisfies = __commonJS({ "node_modules/semver/functions/satisfies.js"(exports2, module2) { "use strict"; var Range3 = require_range(); - var satisfies = (version2, range, options) => { + var satisfies = (version, range, options) => { try { range = new Range3(range, options); } catch (er) { return false; } - return range.test(version2); + return range.test(version); }; module2.exports = satisfies; } @@ -12003,7 +12127,6 @@ var init_pack = __esm({ init_esm(); init_esm3(); init_esm5(); - init_read_entry(); init_warn_method(); import_path10 = __toESM(require("path"), 1); init_normalize_windows_path(); @@ -12026,7 +12149,7 @@ var init_pack = __esm({ ONSTAT = /* @__PURE__ */ Symbol("onStat"); ENDED3 = /* @__PURE__ */ Symbol("ended"); QUEUE2 = /* @__PURE__ */ Symbol("queue"); - PENDINGLINKS = /* @__PURE__ */ Symbol("queue"); + PENDINGLINKS = /* @__PURE__ */ Symbol("pendingLinks"); CURRENT = /* @__PURE__ */ Symbol("current"); PROCESS2 = /* @__PURE__ */ Symbol("process"); PROCESSING = /* @__PURE__ */ Symbol("processing"); @@ -12175,10 +12298,10 @@ var init_pack = __esm({ if (this[ENDED3]) { throw new Error("write after end"); } - if (path16 instanceof ReadEntry) { - this[ADDTARENTRY](path16); - } else { + if (typeof path16 === "string") { this[ADDFSENTRY](path16); + } else { + this[ADDTARENTRY](path16); } return this.flowing; } @@ -12563,7 +12686,99 @@ module.exports = __toCommonJS(lib_exports2); var import_clipanion17 = __toESM(require_advanced()); // package.json -var version = "0.35.0"; +var package_default = { + name: "corepack", + version: "0.36.0", + homepage: "https://github.com/nodejs/corepack#readme", + bugs: { + url: "https://github.com/nodejs/corepack/issues" + }, + repository: { + type: "git", + url: "https://github.com/nodejs/corepack.git" + }, + engines: { + node: "^22.22.2 || ^24.15.0 || >=26.0.0" + }, + exports: { + "./package.json": "./package.json" + }, + license: "MIT", + packageManager: "yarn@4.18.0+sha224.5707fce90df5d8720fae4e85a07ab55e90aa20fded8914893e2ba225", + devDependencies: { + "@types/debug": "^4.1.5", + "@types/node": "^22.0.0", + "@types/proxy-from-env": "^1", + "@types/semver": "^7.1.0", + "@types/which": "^3.0.0", + "@yarnpkg/eslint-config": "^3.1.1", + "@yarnpkg/fslib": "^3.0.0-rc.48", + "@zkochan/cmd-shim": "^6.0.0", + clipanion: "patch:clipanion@npm%3A3.2.1#~/.yarn/patches/clipanion-npm-3.2.1-fc9187f56c.patch", + debug: "^4.1.1", + esbuild: "^0.28.0", + eslint: "^10.8.1", + semver: "^7.6.3", + "supports-color": "^11.0.0", + tar: "^7.5.11", + typescript: "^5.7.3", + "v8-compile-cache": "^2.3.0", + vitest: "^4.0.5", + which: "^7.0.0" + }, + dependenciesMeta: { + esbuild: { + built: true + } + }, + scripts: { + build: "run clean && run build:bundle && node ./mkshims.ts", + "build:bundle": "esbuild ./sources/_lib.ts --bundle --platform=node --target=node22.22.2 --external:corepack --outfile='./dist/lib/corepack.cjs' --resolve-extensions='.ts,.mjs,.js'", + clean: "run rimraf dist shims", + corepack: "node ./sources/_cli.ts", + lint: "eslint", + prepack: "yarn build", + postpack: "run clean", + rimraf: "node -e 'for(let i=2;i { - SupportedPackageManagers3["Npm"] = `npm`; - SupportedPackageManagers3["Pnpm"] = `pnpm`; - SupportedPackageManagers3["Yarn"] = `yarn`; - return SupportedPackageManagers3; -})(SupportedPackageManagers || {}); +var supportedPackageManagersList = [`npm`, `pnpm`, `yarn`]; var SupportedPackageManagerSet = new Set( - Object.values(SupportedPackageManagers) + supportedPackageManagersList ); var SupportedPackageManagerSetWithoutNpm = new Set( - Object.values(SupportedPackageManagers) + supportedPackageManagersList.filter((pm) => pm !== `npm`) ); -SupportedPackageManagerSetWithoutNpm.delete("npm" /* Npm */); function isSupportedPackageManager(value) { return SupportedPackageManagerSet.has(value); } @@ -13454,6 +13684,9 @@ function parseSpec(raw2, source, { enforceExactVersion = true } = {}) { range }; } +function devEnginesToDescriptor({ name: name2, version }) { + return { name: name2, range: version ?? `*` }; +} function warnOrThrow(errorMessage, onFail) { switch (onFail) { case `ignore`: @@ -13471,44 +13704,45 @@ function parsePackageJSON(packageJSONContent) { const { packageManager } = packageJSONContent.devEngines; if (typeof packageManager !== `object`) { console.warn(`! Corepack only supports objects as valid value for devEngines.packageManager. The current value (${JSON.stringify(packageManager)}) will be ignored.`); - return pm; + return { packageManagerField: pm }; } if (Array.isArray(packageManager)) { console.warn(`! Corepack does not currently support array values for devEngines.packageManager`); - return pm; + return { packageManagerField: pm }; } - const { name: name2, version: version2, onFail } = packageManager; + const { name: name2, version, onFail } = packageManager; if (typeof name2 !== `string` || name2.includes(`@`)) { warnOrThrow(`The value of devEngines.packageManager.name ${JSON.stringify(name2)} is not a supported string value`, onFail); - return pm; + return { packageManagerField: pm }; } - if (version2 != null && (typeof version2 !== `string` || !(0, import_valid2.default)(version2))) { - warnOrThrow(`The value of devEngines.packageManager.version ${JSON.stringify(version2)} is not a valid semver range`, onFail); - return pm; + if (version != null && (typeof version !== `string` || !(0, import_valid2.default)(version))) { + warnOrThrow(`The value of devEngines.packageManager.version ${JSON.stringify(version)} is not a valid semver range`, onFail); + return { packageManagerField: pm }; } - log(`devEngines.packageManager defines that ${name2}@${version2} is the local package manager`); + log(`devEngines.packageManager defines that ${name2}${version ? `@${version}` : ``} should be the local package manager`); if (pm) { - if (!pm.startsWith?.(`${name2}@`)) + if (!pm.startsWith?.(`${name2}@`)) { warnOrThrow(`"packageManager" field is set to ${JSON.stringify(pm)} which does not match the "devEngines.packageManager" field set to ${JSON.stringify(name2)}`, onFail); - else if (version2 != null && !(0, import_satisfies.default)(pm.slice(packageManager.name.length + 1), version2)) - warnOrThrow(`"packageManager" field is set to ${JSON.stringify(pm)} which does not match the value defined in "devEngines.packageManager" for ${JSON.stringify(name2)} of ${JSON.stringify(version2)}`, onFail); - return pm; + } else if (version != null && !(0, import_satisfies.default)(pm.slice(name2.length + 1), version)) { + warnOrThrow(`"packageManager" field is set to ${JSON.stringify(pm)} which does not match the value defined in "devEngines.packageManager" for ${JSON.stringify(name2)} of ${JSON.stringify(version)}`, onFail); + } } - return `${name2}@${version2 ?? `*`}`; + return { packageManagerField: pm, devEnginesPackageManager: { name: name2, version, onFail } }; } - return pm; + return { packageManagerField: pm }; } async function setLocalPackageManager(cwd, info) { - const lookup = await loadSpec(cwd); - const range = `range` in lookup && lookup.range; - if (range) { - if (info.locator.name !== range.name || !(0, import_satisfies.default)(info.locator.reference, range.range)) { - warnOrThrow(`The requested version of ${info.locator.name}@${info.locator.reference} does not match the devEngines specification (${range.name}@${range.range})`, range.onFail); + const lookup = await loadSpecAndEnv(cwd); + const projectFound = lookup.type !== `NoProject`; + const devEnginesValue = projectFound ? lookup.devEnginesValue : void 0; + if (devEnginesValue) { + if (info.locator.name !== devEnginesValue.name || devEnginesValue.version != null && !(0, import_satisfies.default)(info.locator.reference, devEnginesValue.version)) { + warnOrThrow(`The requested version of ${info.locator.name}@${info.locator.reference} does not match the devEngines specification (${devEnginesValue.name}@${devEnginesValue.version ?? `*`})`, devEnginesValue.onFail); } } - const content = lookup.type !== `NoProject` ? await import_fs5.default.promises.readFile(lookup.target, `utf8`) : ``; + const content = projectFound ? await import_fs5.default.promises.readFile(lookup.target, `utf8`) : ``; const { data, indent } = readPackageJson(content); - const previousPackageManager = data.packageManager ?? (range ? `${range.name}@${range.range}` : `unknown`); + const previousPackageManager = data.packageManager ?? (devEnginesValue ? `${devEnginesValue.name}@${devEnginesValue.version ?? `*`}` : `unknown`); data.packageManager = `${info.locator.name}@${info.locator.reference}`; const newContent = normalizeLineEndings(content, `${JSON.stringify(data, null, indent)} `); @@ -13517,15 +13751,43 @@ async function setLocalPackageManager(cwd, info) { previousPackageManager }; } -async function loadSpec(initialCwd) { +async function loadEnvFileIfExists(cwd) { + const envFilePath = import_path4.default.resolve(cwd, process.env.COREPACK_ENV_FILE ?? `.corepack.env`); + if (process.env.COREPACK_ENV_FILE == `0`) { + log(`Skipping env file as configured with COREPACK_ENV_FILE`); + return void 0; + } + log(`Checking ${envFilePath}`); + try { + const localEnv = { + ...Object.fromEntries(Object.entries((0, import_util.parseEnv)(await import_fs5.default.promises.readFile(envFilePath, `utf8`))).filter((e) => e[0].startsWith(`COREPACK_`))), + ...process.env + }; + log(`Successfully loaded env file found at ${envFilePath}`); + return { env: localEnv, path: envFilePath }; + } catch (err) { + if (err?.code !== `ENOENT`) + throw err; + log(`No env file found at ${envFilePath}`); + } + return void 0; +} +async function loadSpecAndEnv(initialCwd, { envOnly } = { envOnly: false }) { let nextCwd = initialCwd; let currCwd = ``; let selection = null; + let localEnv = void 0; while (nextCwd !== currCwd && (!selection || !selection.data.packageManager)) { currCwd = nextCwd; nextCwd = import_path4.default.dirname(currCwd); if (nodeModulesRegExp.test(currCwd)) continue; + if (process.env.COREPACK_ENV_FILE !== `0` && !localEnv) + localEnv = await loadEnvFileIfExists(currCwd); + if (envOnly) { + if (localEnv) break; + continue; + } const manifestPath = import_path4.default.join(currCwd, `package.json`); log(`Checking ${manifestPath}`); let content; @@ -13541,54 +13803,42 @@ async function loadSpec(initialCwd) { } catch { } if (typeof data !== `object` || data === null) - throw new import_clipanion4.UsageError(`Invalid package.json in ${import_path4.default.relative(initialCwd, manifestPath)}`); - let localEnv; - const envFilePath2 = import_path4.default.resolve(currCwd, process.env.COREPACK_ENV_FILE ?? `.corepack.env`); - if (process.env.COREPACK_ENV_FILE == `0`) { - log(`Skipping env file as configured with COREPACK_ENV_FILE`); - localEnv = process.env; - } else if (typeof import_util.parseEnv !== `function`) { - log(`Skipping env file as it is not supported by the current version of Node.js`); - localEnv = process.env; - } else { - log(`Checking ${envFilePath2}`); - try { - localEnv = { - ...Object.fromEntries(Object.entries((0, import_util.parseEnv)(await import_fs5.default.promises.readFile(envFilePath2, `utf8`))).filter((e) => e[0].startsWith(`COREPACK_`))), - ...process.env - }; - log(`Successfully loaded env file found at ${envFilePath2}`); - } catch (err) { - if (err?.code !== `ENOENT`) - throw err; - log(`No env file found at ${envFilePath2}`); - localEnv = process.env; - } - } - selection = { data, manifestPath, localEnv, envFilePath: envFilePath2 }; + throw new import_clipanion4.UsageError(`Invalid package.json in ${import_path4.default.relative(currCwd, manifestPath)}`); + selection = { data, manifestPath }; } + if (localEnv) + process.env = localEnv.env; if (selection === null) - return { type: `NoProject`, target: import_path4.default.join(initialCwd, `package.json`) }; - let envFilePath; - if (selection.localEnv !== process.env) { - envFilePath = selection.envFilePath; - process.env = selection.localEnv; - } - const rawPmSpec = parsePackageJSON(selection.data); - if (typeof rawPmSpec === `undefined`) - return { type: `NoSpec`, target: selection.manifestPath }; - log(`${selection.manifestPath} defines ${rawPmSpec} as local package manager`); + return { type: `NoProject`, target: import_path4.default.join(initialCwd, `package.json`), envFilePath: localEnv?.path }; + const { packageManagerField, devEnginesPackageManager } = parsePackageJSON(selection.data); + if (devEnginesPackageManager != null && !packageManagerField) { + const { name: name2, version } = devEnginesPackageManager; + if (!version || !(0, import_valid.default)(version)) { + log(`${selection.manifestPath} defines ${name2} as local package manager using devEngines.packageManager, without an exact version`); + return { type: `NoSpec`, target: selection.manifestPath, envFilePath: localEnv?.path, devEnginesValue: devEnginesPackageManager }; + } + log(`${selection.manifestPath} defines ${name2}@${version} as local package manager using devEngines.packageManager`); + return { + type: `Found`, + target: selection.manifestPath, + field: `devEngines.packageManager`, + envFilePath: localEnv?.path, + devEnginesValue: devEnginesPackageManager, + // Lazy-loading it so we do not throw errors on commands that do not need valid spec. + getSpec: ({ enforceExactVersion = true } = {}) => parseSpec(`${name2}@${version}`, import_path4.default.relative(initialCwd, selection.manifestPath), { enforceExactVersion }) + }; + } + if (packageManagerField === void 0) + return { type: `NoSpec`, target: selection.manifestPath, envFilePath: localEnv?.path }; + log(`${selection.manifestPath} defines ${packageManagerField} as local package manager using the packageManager field`); return { type: `Found`, target: selection.manifestPath, - envFilePath, - range: selection.data.devEngines?.packageManager?.version && { - name: selection.data.devEngines.packageManager.name, - range: selection.data.devEngines.packageManager.version, - onFail: selection.data.devEngines.packageManager.onFail - }, + field: `packageManager`, + envFilePath: localEnv?.path, + devEnginesValue: devEnginesPackageManager, // Lazy-loading it so we do not throw errors on commands that do not need valid spec. - getSpec: ({ enforceExactVersion = true } = {}) => parseSpec(rawPmSpec, import_path4.default.relative(initialCwd, selection.manifestPath), { enforceExactVersion }) + getSpec: ({ enforceExactVersion = true } = {}) => parseSpec(packageManagerField, import_path4.default.relative(initialCwd, selection.manifestPath), { enforceExactVersion }) }; } @@ -13652,10 +13902,10 @@ async function activatePackageManager(lastKnownGood, locator) { await createLastKnownGoodFile(lastKnownGood); } var Engine = class { + config; constructor(config = config_default) { this.config = config; } - config; getPackageManagerFor(binaryName) { for (const packageManager of SupportedPackageManagerSet) { for (const rangeDefinition of Object.values(this.config.definitions[packageManager].ranges)) { @@ -13782,7 +14032,7 @@ var Engine = class { if (import_process3.default.env.COREPACK_ENABLE_STRICT === `0`) transparent = true; while (true) { - const result = await loadSpec(initialCwd); + const result = await loadSpecAndEnv(initialCwd); switch (result.type) { case `NoProject`: { if (typeof locator.reference === `function`) @@ -13791,7 +14041,13 @@ var Engine = class { return fallbackDescriptor; } case `NoSpec`: { - if (typeof locator.reference === `function`) + const { devEnginesValue } = result; + const nameMatches = devEnginesValue != null && devEnginesValue.name === fallbackDescriptor.name; + if (devEnginesValue != null && !nameMatches && !transparent) + warnOrThrow(`This project is configured to use ${devEnginesValue.name} because ${result.target} has a "devEngines.packageManager" field`, devEnginesValue.onFail); + if (nameMatches && devEnginesValue.version) + fallbackDescriptor.range = devEnginesValue.version; + else if (typeof locator.reference === `function`) fallbackDescriptor.range = await locator.reference(); if (import_process3.default.env.COREPACK_ENABLE_AUTO_PIN === `1`) { const resolved = await this.resolveDescriptor(fallbackDescriptor, { allowTags: true }); @@ -13815,7 +14071,7 @@ var Engine = class { log(`Falling back to ${fallbackDescriptor.name}@${fallbackDescriptor.range} in a ${spec.name}@${spec.range} project`); return fallbackDescriptor; } else { - throw new import_clipanion5.UsageError(`This project is configured to use ${spec.name} because ${result.target} has a "packageManager" field`); + throw new import_clipanion5.UsageError(`This project is configured to use ${spec.name} because ${result.target} has a "${result.field}" field`); } } else { log(`Using ${spec.name}@${spec.range} as defined in project manifest ${result.target}`); @@ -13892,7 +14148,7 @@ var Engine = class { const packageManagerSpec = definition.ranges[range]; const registry = getRegistryFromPackageManagerSpec(packageManagerSpec); const versions2 = await fetchAvailableVersions2(registry); - return versions2.filter((version2) => satisfiesWithPrereleases(version2, finalDescriptor.range)); + return versions2.filter((version) => satisfiesWithPrereleases(version, finalDescriptor.range)); })); const highestVersion = [...new Set(versions.flat())].sort(import_rcompare.default); if (highestVersion.length === 0) @@ -14084,16 +14340,23 @@ var BaseCommand = class extends import_clipanion9.Command { async resolvePatternsToDescriptors({ patterns }) { const resolvedSpecs = patterns.map((pattern) => parseSpec(pattern, `CLI arguments`, { enforceExactVersion: false })); if (resolvedSpecs.length === 0) { - const lookup = await loadSpec(this.context.cwd); + const lookup = await loadSpecAndEnv(this.context.cwd); switch (lookup.type) { case `NoProject`: throw new import_clipanion9.UsageError(`Couldn't find a project in the local directory - please specify the package manager to pack, or run this command from a valid project`); - case `NoSpec`: - throw new import_clipanion9.UsageError(`The local project doesn't feature a 'packageManager' field nor a 'devEngines.packageManager' field - please specify the package manager to pack, or update the manifest to reference it`); + case `NoSpec`: { + const { devEnginesValue } = lookup; + if (devEnginesValue?.version) + return [devEnginesToDescriptor(devEnginesValue)]; + throw new import_clipanion9.UsageError(`The local project doesn't feature a 'packageManager' field ${devEnginesValue ? `` : `nor a 'devEngines.packageManager' field `}- please specify the package manager to pack, or update the manifest to reference it`); + } default: { - return [lookup.range ?? lookup.getSpec()]; + const { devEnginesValue } = lookup; + return [devEnginesValue?.version ? devEnginesToDescriptor(devEnginesValue) : lookup.getSpec()]; } } + } else { + await loadSpecAndEnv(this.context.cwd, { envOnly: true }); } return resolvedSpecs; } @@ -14457,16 +14720,24 @@ var PrepareCommand = class extends import_clipanion16.Command { const specs = this.specs; const installLocations = []; if (specs.length === 0) { - const lookup = await loadSpec(this.context.cwd); + const lookup = await loadSpecAndEnv(this.context.cwd); switch (lookup.type) { case `NoProject`: throw new import_clipanion16.UsageError(`Couldn't find a project in the local directory - please specify the package manager to pack, or run this command from a valid project`); - case `NoSpec`: - throw new import_clipanion16.UsageError(`The local project doesn't feature a 'packageManager' field - please specify the package manager to pack, or update the manifest to reference it`); + case `NoSpec`: { + const { devEnginesValue } = lookup; + if (devEnginesValue?.version) { + specs.push(devEnginesToDescriptor(devEnginesValue)); + break; + } + throw new import_clipanion16.UsageError(`The local project doesn't feature a 'packageManager' field ${devEnginesValue ? `` : `nor a 'devEngines.packageManager' field `}- please specify the package manager to pack, or update the manifest to reference it`); + } default: { specs.push(lookup.getSpec()); } } + } else { + await loadSpecAndEnv(this.context.cwd, { envOnly: true }); } for (const request of specs) { const spec = typeof request === `string` ? parseSpec(request, `CLI arguments`, { enforceExactVersion: false }) : request; @@ -14512,6 +14783,7 @@ var PrepareCommand = class extends import_clipanion16.Command { }; // sources/main.ts +var { version: corepackVersion } = package_default; function getPackageManagerRequestFromCli(parameter, engine) { if (!parameter) return null; @@ -14538,7 +14810,7 @@ async function runMain(argv) { const cli = new import_clipanion17.Cli({ binaryLabel: `Corepack`, binaryName: `corepack`, - binaryVersion: version + binaryVersion: corepackVersion }); cli.register(import_clipanion17.Builtins.HelpCommand); cli.register(import_clipanion17.Builtins.VersionCommand); diff --git a/deps/corepack/package.json b/deps/corepack/package.json index 279475fb9cec..170b48449fc7 100644 --- a/deps/corepack/package.json +++ b/deps/corepack/package.json @@ -1,6 +1,6 @@ { "name": "corepack", - "version": "0.35.0", + "version": "0.36.0", "homepage": "https://github.com/nodejs/corepack#readme", "bugs": { "url": "https://github.com/nodejs/corepack/issues" @@ -16,24 +16,23 @@ "./package.json": "./package.json" }, "license": "MIT", - "packageManager": "yarn@4.14.1+sha224.88b7a7244bbd9040380c417f7eb556d85c67640b651f113cb4c72113", + "packageManager": "yarn@4.18.0+sha224.5707fce90df5d8720fae4e85a07ab55e90aa20fded8914893e2ba225", "devDependencies": { "@types/debug": "^4.1.5", "@types/node": "^22.0.0", "@types/proxy-from-env": "^1", "@types/semver": "^7.1.0", "@types/which": "^3.0.0", - "@yarnpkg/eslint-config": "^3.0.0", + "@yarnpkg/eslint-config": "^3.1.1", "@yarnpkg/fslib": "^3.0.0-rc.48", "@zkochan/cmd-shim": "^6.0.0", "clipanion": "patch:clipanion@npm%3A3.2.1#~/.yarn/patches/clipanion-npm-3.2.1-fc9187f56c.patch", "debug": "^4.1.1", "esbuild": "^0.28.0", - "eslint": "^9.22.0", + "eslint": "^10.8.1", "semver": "^7.6.3", - "supports-color": "^10.0.0", + "supports-color": "^11.0.0", "tar": "^7.5.11", - "tsx": "^4.16.2", "typescript": "^5.7.3", "v8-compile-cache": "^2.3.0", "vitest": "^4.0.5", @@ -45,11 +44,11 @@ } }, "scripts": { - "build": "run clean && run build:bundle && tsx ./mkshims.ts", + "build": "run clean && run build:bundle && node ./mkshims.ts", "build:bundle": "esbuild ./sources/_lib.ts --bundle --platform=node --target=node22.22.2 --external:corepack --outfile='./dist/lib/corepack.cjs' --resolve-extensions='.ts,.mjs,.js'", "clean": "run rimraf dist shims", - "corepack": "tsx ./sources/_cli.ts", - "lint": "eslint .", + "corepack": "node ./sources/_cli.ts", + "lint": "eslint", "prepack": "yarn build", "postpack": "run clean", "rimraf": "node -e 'for(let i=2;i #include #include +#include #include #include "gtest/gtest-printers.h" @@ -543,9 +544,8 @@ Matcher : public internal::MatcherBase { Matcher(const char* s); // NOLINT }; -#if GTEST_INTERNAL_HAS_STRING_VIEW // The following two specializations allow the user to write str -// instead of Eq(str) and "foo" instead of Eq("foo") when a absl::string_view +// instead of Eq(str) and "foo" instead of Eq("foo") when a std::string_view // matcher is expected. template <> class GTEST_API_ [[nodiscard]] Matcher @@ -569,7 +569,7 @@ class GTEST_API_ [[nodiscard]] Matcher // Allows the user to write "foo" instead of Eq("foo") sometimes. Matcher(const char* s); // NOLINT - // Allows the user to pass absl::string_views or std::string_views directly. + // Allows the user to pass std::string_views directly. Matcher(internal::StringView s); // NOLINT }; @@ -596,10 +596,9 @@ class GTEST_API_ [[nodiscard]] Matcher // Allows the user to write "foo" instead of Eq("foo") sometimes. Matcher(const char* s); // NOLINT - // Allows the user to pass absl::string_views or std::string_views directly. + // Allows the user to pass std::string_views directly. Matcher(internal::StringView s); // NOLINT }; -#endif // GTEST_INTERNAL_HAS_STRING_VIEW // Prints a matcher in a human-readable format. template @@ -812,9 +811,26 @@ class [[nodiscard]] ImplicitCastEqMatcher { StoredRhs stored_rhs_; }; -template >> -using StringLike = T; +// Dummy function (never defined) whose return type evaluates to std::string if +// the given type is a string-like type that can be converted to std::string, +// either directly or through an intermediate std::string_view. +template +extern std::enable_if_t, std::string> +ResolveAsString(const void* /* preferred */); + +#if GTEST_HAS_STD_WSTRING +// Same as above, but for std::wstring. In cases where both conversions are +// possible, this overload takes lower priority. +template +extern std::enable_if_t, std::wstring> +ResolveAsString(... /* fallback */); +#endif + +// Evaluates to the std::basic_string type that the given string-like type can +// be converted to. Prefers std::string over std::wstring if both are possible. +// Fails in a SFINAE-friendly way if no conversion was viable. +template +using StringType = decltype(ResolveAsString(nullptr)); // Implements polymorphic matchers MatchesRegex(regex) and // ContainsRegex(regex), which can be used as a Matcher as long as @@ -824,12 +840,10 @@ class [[nodiscard]] MatchesRegexMatcher { MatchesRegexMatcher(const RE* regex, bool full_match) : regex_(regex), full_match_(full_match) {} -#if GTEST_INTERNAL_HAS_STRING_VIEW bool MatchAndExplain(const internal::StringView& s, MatchResultListener* listener) const { return MatchAndExplain(std::string(s), listener); } -#endif // GTEST_INTERNAL_HAS_STRING_VIEW // Accepts pointer types, particularly: // const char* @@ -844,7 +858,7 @@ class [[nodiscard]] MatchesRegexMatcher { // Matches anything that can convert to std::string. // // This is a template, not just a plain function with const std::string&, - // because absl::string_view has some interfering non-explicit constructors. + // because std::string_view has some interfering non-explicit constructors. template bool MatchAndExplain(const MatcheeStringType& s, MatchResultListener* /* listener */) const { @@ -877,9 +891,10 @@ inline PolymorphicMatcher MatchesRegex( return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, true)); } template -PolymorphicMatcher MatchesRegex( - const internal::StringLike& regex) { - return MatchesRegex(new internal::RE(std::string(regex))); +std::enable_if_t>, + PolymorphicMatcher> +MatchesRegex(const T& regex) { + return MatchesRegex(new internal::RE(internal::StringType(regex))); } // Matches a string that contains regular expression 'regex'. @@ -889,9 +904,10 @@ inline PolymorphicMatcher ContainsRegex( return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, false)); } template -PolymorphicMatcher ContainsRegex( - const internal::StringLike& regex) { - return ContainsRegex(new internal::RE(std::string(regex))); +std::enable_if_t>, + PolymorphicMatcher> +ContainsRegex(const T& regex) { + return ContainsRegex(new internal::RE(internal::StringType(regex))); } // Creates a polymorphic matcher that matches anything equal to x. diff --git a/deps/googletest/include/gtest/gtest-printers.h b/deps/googletest/include/gtest/gtest-printers.h index fc0913ff0094..69c9fec3ca95 100644 --- a/deps/googletest/include/gtest/gtest-printers.h +++ b/deps/googletest/include/gtest/gtest-printers.h @@ -291,11 +291,9 @@ struct ConvertibleToIntegerPrinter { }; struct ConvertibleToStringViewPrinter { -#if GTEST_INTERNAL_HAS_STRING_VIEW static void PrintValue(internal::StringView value, ::std::ostream* os) { internal::UniversalPrint(value, os); } -#endif }; #ifdef GTEST_HAS_ABSL @@ -703,12 +701,12 @@ void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { } } -// Overloads for ::std::string and ::std::string_view -GTEST_API_ void PrintStringTo(::std::string_view s, ::std::ostream* os); +// Overloads for ::std::string and std::string_view +GTEST_API_ void PrintStringTo(std::string_view s, ::std::ostream* os); inline void PrintTo(const ::std::string& s, ::std::ostream* os) { PrintStringTo(s, os); } -inline void PrintTo(::std::string_view s, ::std::ostream* os) { +inline void PrintTo(std::string_view s, ::std::ostream* os) { PrintStringTo(s, os); } @@ -752,16 +750,14 @@ inline void PrintTo(::std::wstring_view s, ::std::ostream* os) { } #endif // GTEST_HAS_STD_WSTRING -#if GTEST_INTERNAL_HAS_STRING_VIEW // Overload for internal::StringView. Needed for build configurations where // internal::StringView is an alias for absl::string_view, but absl::string_view // is a distinct type from std::string_view. template , int> = 0> + std::enable_if_t, int> = 0> inline void PrintTo(internal::StringView sp, ::std::ostream* os) { PrintStringTo(sp, os); } -#endif // GTEST_INTERNAL_HAS_STRING_VIEW inline void PrintTo(std::nullptr_t, ::std::ostream* os) { *os << "(nullptr)"; } @@ -1177,15 +1173,12 @@ class [[nodiscard]] UniversalTersePrinter { } } }; -#endif template <> -class [[nodiscard]] UniversalTersePrinter { - public: - static void Print(wchar_t* str, ::std::ostream* os) { - UniversalTersePrinter::Print(str, os); - } -}; +class [[nodiscard]] UniversalTersePrinter + : public UniversalTersePrinter {}; + +#endif // GTEST_HAS_STD_WSTRING template void UniversalTersePrint(const T& value, ::std::ostream* os) { diff --git a/deps/googletest/include/gtest/internal/gtest-death-test-internal.h b/deps/googletest/include/gtest/internal/gtest-death-test-internal.h index f88e2049c249..f0f93e520b7b 100644 --- a/deps/googletest/include/gtest/internal/gtest-death-test-internal.h +++ b/deps/googletest/include/gtest/internal/gtest-death-test-internal.h @@ -43,6 +43,7 @@ #include #include +#include #include "gtest/gtest-matchers.h" #include "gtest/internal/gtest-internal.h" @@ -63,6 +64,10 @@ inline Matcher MakeDeathTestMatcher( ::testing::internal::RE regex) { return ContainsRegex(regex.pattern()); } +inline Matcher MakeDeathTestMatcher( + std::string_view regex) { + return ContainsRegex(regex); +} inline Matcher MakeDeathTestMatcher(const char* regex) { return ContainsRegex(regex); } diff --git a/deps/googletest/include/gtest/internal/gtest-internal.h b/deps/googletest/include/gtest/internal/gtest-internal.h index 2b048c5dc098..55e9966720bf 100644 --- a/deps/googletest/include/gtest/internal/gtest-internal.h +++ b/deps/googletest/include/gtest/internal/gtest-internal.h @@ -1451,13 +1451,13 @@ class [[nodiscard]] NeverThrown { // Implements Boolean test assertions such as EXPECT_TRUE. expression can be // either a boolean expression or an AssertionResult. text is a textual // representation of expression as it was passed into the EXPECT_TRUE. -#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AssertionResultExpectation gtest_are_ = { \ - ::testing::AssertionResult(expression), expected}) \ - ; \ - else \ - fail(::testing::internal::GetBoolAssertionFailureMessage( \ +#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::internal::AssertionResultExpectation gtest_are_ = { \ + ::testing::AssertionResult(expression), expected}) \ + ; \ + else /* NOLINT */ \ + fail(::testing::internal::GetBoolAssertionFailureMessage( \ gtest_are_.assertion_result, text, #actual, #expected)) #define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ diff --git a/deps/googletest/include/gtest/internal/gtest-port.h b/deps/googletest/include/gtest/internal/gtest-port.h index 31654b09c1dc..051228553449 100644 --- a/deps/googletest/include/gtest/internal/gtest-port.h +++ b/deps/googletest/include/gtest/internal/gtest-port.h @@ -293,9 +293,10 @@ #include #include #include +// #include // Guarded by GTEST_IS_THREADSAFE below #include #include -// #include // Guarded by GTEST_IS_THREADSAFE below +#include #include #include #include @@ -499,22 +500,71 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; #endif // defined(_MSC_VER) || defined(__BORLANDC__) #endif // GTEST_HAS_EXCEPTIONS -#ifndef GTEST_HAS_STD_WSTRING -// The user didn't tell us whether ::std::wstring is available, so we need -// to figure it out. +// 1. Calculate default GTEST_HAS_STD_WSTRING values based on STL capabilities. +#if defined(_MSVC_STL_VERSION) +// Microsoft's STL implementation always supports ::std::wstring. +#define GTEST_HAS_STD_WSTRING_DEFAULT 1 + +#elif defined(_LIBCPP_VERSION) +// Modern libc++ always defines _LIBCPP_HAS_WIDE_CHARACTERS; its value +// determines whether wide characters are supported. +// Older libc++ omits a definition for _LIBCPP_HAS_NO_WIDE_CHARACTERS when wide +// characters are supported. +#if (defined(_LIBCPP_HAS_WIDE_CHARACTERS) && !_LIBCPP_HAS_WIDE_CHARACTERS) || \ + defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS) +#define GTEST_HAS_STD_WSTRING_DEFAULT 0 +#else +#define GTEST_HAS_STD_WSTRING_DEFAULT 1 +#endif + +#elif defined(__GLIBCXX__) +#if defined(_GLIBCXX_USE_WCHAR_T) && _GLIBCXX_USE_WCHAR_T +#define GTEST_HAS_STD_WSTRING_DEFAULT 1 +#else +#define GTEST_HAS_STD_WSTRING_DEFAULT 0 +#endif + +#else +// Unknown standard library implementation; fall back looking at the OS. +// +// Always let the user override the defaults in this case; they might have more +// information about what's supported than we do. +#if defined(GTEST_OS_LINUX_ANDROID) +// Android started supporting std::wstring with API Level 21 (Lollipop). +#define GTEST_HAS_STD_WSTRING_DEFAULT (__ANDROID_API__ >= 21) +// The following platforms are known not to support ::std::wstring; assume it's +// supported on all others. +// // Cygwin 1.7 and below doesn't support ::std::wstring. -// Solaris' libc++ doesn't support it either. Android has -// no support for it at least as recent as Froyo (2.2). -#if (!(defined(GTEST_OS_LINUX_ANDROID) || defined(GTEST_OS_CYGWIN) || \ - defined(GTEST_OS_SOLARIS) || defined(GTEST_OS_HAIKU) || \ - defined(GTEST_OS_ESP32) || defined(GTEST_OS_ESP8266) || \ - defined(GTEST_OS_XTENSA) || defined(GTEST_OS_QURT) || \ - defined(GTEST_OS_NXP_QN9090) || defined(GTEST_OS_NRF52))) -#define GTEST_HAS_STD_WSTRING 1 +// Solaris' libc++ doesn't support it either. +#elif defined(GTEST_OS_CYGWIN) || defined(GTEST_OS_SOLARIS) || \ + defined(GTEST_OS_HAIKU) || defined(GTEST_OS_ESP32) || \ + defined(GTEST_OS_ESP8266) || defined(GTEST_OS_XTENSA) || \ + defined(GTEST_OS_QURT) || defined(GTEST_OS_NXP_QN9090) || \ + defined(GTEST_OS_NRF52) +#define GTEST_HAS_STD_WSTRING_DEFAULT 0 #else -#define GTEST_HAS_STD_WSTRING 0 +#define GTEST_HAS_STD_WSTRING_DEFAULT 1 +#endif +#endif + +// 2. Validate explicit user overrides (if user passed -DGTEST_HAS_*=1) against +// what the standard library implementation tells us it supports. +#if defined(GTEST_HAS_STD_WSTRING) && GTEST_HAS_STD_WSTRING +#if defined(_LIBCPP_VERSION) && \ + ((defined(_LIBCPP_HAS_WIDE_CHARACTERS) && !_LIBCPP_HAS_WIDE_CHARACTERS) || \ + defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)) +#error Cannot explicitly enable GTEST_HAS_STD_WSTRING without libc++ wide character support. +#elif defined(__GLIBCXX__) && \ + !(defined(_GLIBCXX_USE_WCHAR_T) && _GLIBCXX_USE_WCHAR_T) +#error Cannot explicitly enable GTEST_HAS_STD_WSTRING without libstdc++ wide character support. +#endif +#endif + +// 3. Set final values if not explicitly overridden by user +#if !defined(GTEST_HAS_STD_WSTRING) +#define GTEST_HAS_STD_WSTRING GTEST_HAS_STD_WSTRING_DEFAULT #endif -#endif // GTEST_HAS_STD_WSTRING #ifndef GTEST_HAS_FILE_SYSTEM // Most platforms support a file system. @@ -949,21 +999,21 @@ GTEST_API_ bool IsTrue(bool condition); #ifdef GTEST_USES_RE2 // This is almost `using RE = ::RE2`, except it is copy-constructible, and it -// needs to disambiguate the `std::string`, `absl::string_view`, and `const +// needs to disambiguate the `std::string`, `std::string_view`, and `const // char*` constructors. class GTEST_API_ [[nodiscard]] RE { public: - RE(absl::string_view regex) : regex_(regex) {} // NOLINT - RE(const char* regex) : RE(absl::string_view(regex)) {} // NOLINT - RE(const std::string& regex) : RE(absl::string_view(regex)) {} // NOLINT + RE(std::string_view regex) : regex_(regex) {} // NOLINT + RE(const char* regex) : RE(std::string_view(regex)) {} // NOLINT + RE(const std::string& regex) : RE(std::string_view(regex)) {} // NOLINT RE(const RE& other) : RE(other.pattern()) {} const std::string& pattern() const { return regex_.pattern(); } - static bool FullMatch(absl::string_view str, const RE& re) { + static bool FullMatch(std::string_view str, const RE& re) { return RE2::FullMatch(str, re.regex_); } - static bool PartialMatch(absl::string_view str, const RE& re) { + static bool PartialMatch(std::string_view str, const RE& re) { return RE2::PartialMatch(str, re.regex_); } @@ -2396,7 +2446,6 @@ const char* StringFromGTestEnv(const char* flag, const char* default_val); #ifdef GTEST_HAS_ABSL // Always use absl::string_view for Matcher<> specializations if googletest // is built with absl support. -#define GTEST_INTERNAL_HAS_STRING_VIEW 1 #include "absl/strings/string_view.h" namespace testing { namespace internal { @@ -2404,26 +2453,15 @@ using StringView = ::absl::string_view; } // namespace internal } // namespace testing #else -#if defined(__cpp_lib_string_view) || \ - (GTEST_INTERNAL_HAS_INCLUDE() && \ - GTEST_INTERNAL_CPLUSPLUS_LANG >= 201703L) // Otherwise for C++17 and higher use std::string_view for Matcher<> // specializations. -#define GTEST_INTERNAL_HAS_STRING_VIEW 1 -#include namespace testing { namespace internal { -using StringView = ::std::string_view; +using StringView = std::string_view; } // namespace internal } // namespace testing -// The case where absl is configured NOT to alias std::string_view is not -// supported. -#endif // __cpp_lib_string_view #endif // GTEST_HAS_ABSL - -#ifndef GTEST_INTERNAL_HAS_STRING_VIEW -#define GTEST_INTERNAL_HAS_STRING_VIEW 0 -#endif +#define GTEST_INTERNAL_HAS_STRING_VIEW 1 #if defined(__cpp_lib_three_way_comparison) #define GTEST_INTERNAL_HAS_COMPARE_LIB 1 diff --git a/deps/googletest/src/gtest-matchers.cc b/deps/googletest/src/gtest-matchers.cc index 7e3bcc0cff38..626019e2389f 100644 --- a/deps/googletest/src/gtest-matchers.cc +++ b/deps/googletest/src/gtest-matchers.cc @@ -59,7 +59,6 @@ Matcher::Matcher(const std::string& s) { *this = Eq(s); } // s. Matcher::Matcher(const char* s) { *this = Eq(std::string(s)); } -#if GTEST_INTERNAL_HAS_STRING_VIEW // Constructs a matcher that matches a const StringView& whose value is // equal to s. Matcher::Matcher(const std::string& s) { @@ -93,6 +92,5 @@ Matcher::Matcher(const char* s) { Matcher::Matcher(internal::StringView s) { *this = Eq(std::string(s)); } -#endif // GTEST_INTERNAL_HAS_STRING_VIEW } // namespace testing diff --git a/deps/googletest/src/gtest-printers.cc b/deps/googletest/src/gtest-printers.cc index 6d1de6d9506f..975ebb829876 100644 --- a/deps/googletest/src/gtest-printers.cc +++ b/deps/googletest/src/gtest-printers.cc @@ -50,6 +50,7 @@ #include #include #include // NOLINT +#include #include #include @@ -422,6 +423,28 @@ void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) { namespace { +template +size_t GetLength(const Char* s) { + return std::char_traits::length(s); +} + +#if !GTEST_HAS_STD_WSTRING + +// If GTEST_HAS_STD_WSTRING is unset because the standard library has disabled +// wide character support, std::char_traits won't be defined, which +// will cause a compile error, even if user code never actually could print a +// wide cstring. In that case, instead use `wcslen` directly. +// +// If `libc` _also_ lacks wide character support, this (and a bunch of other +// calls to wc functions) will fail to link, but only if user code actually +// uses them. +template <> +size_t GetLength(const wchar_t* s) { + return wcslen(s); +} + +#endif // GTEST_HAS_STD_WSTRING + // Prints a null-terminated C-style string to the ostream. template void PrintCStringTo(const Char* s, ostream* os) { @@ -429,7 +452,7 @@ void PrintCStringTo(const Char* s, ostream* os) { *os << "NULL"; } else { *os << ImplicitCast_(s) << " pointing to "; - PrintCharsAsStringTo(s, std::char_traits::length(s), os); + PrintCharsAsStringTo(s, GetLength(s), os); } } @@ -515,13 +538,13 @@ bool IsValidUTF8(const char* str, size_t length) { void ConditionalPrintAsText(const char* str, size_t length, ostream* os) { if (!ContainsUnprintableControlCodes(str, length) && IsValidUTF8(str, length)) { - *os << "\n As Text: \"" << ::std::string_view(str, length) << "\""; + *os << "\n As Text: \"" << std::string_view(str, length) << "\""; } } } // anonymous namespace -void PrintStringTo(::std::string_view s, ostream* os) { +void PrintStringTo(std::string_view s, ostream* os) { if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) { if (GTEST_FLAG_GET(print_utf8)) { ConditionalPrintAsText(s.data(), s.size(), os); diff --git a/deps/googletest/src/gtest.cc b/deps/googletest/src/gtest.cc index 307ecc6f0b9c..3c855468268f 100644 --- a/deps/googletest/src/gtest.cc +++ b/deps/googletest/src/gtest.cc @@ -6930,7 +6930,7 @@ void ParseGoogleTestFlagsOnly(int* argc, char** argv) { std::vector positional_args; std::vector unrecognized_flags; absl::ParseAbseilFlagsOnly(*argc, argv, positional_args, unrecognized_flags); - absl::flat_hash_set unrecognized; + absl::flat_hash_set unrecognized; for (const auto& flag : unrecognized_flags) { unrecognized.insert(flag.flag_name); } diff --git a/deps/ncrypto/ncrypto.cc b/deps/ncrypto/ncrypto.cc index 9802153f6d16..b7bbaccfc3a5 100644 --- a/deps/ncrypto/ncrypto.cc +++ b/deps/ncrypto/ncrypto.cc @@ -4,23 +4,26 @@ #include #include #include +#include #include #include #include #if NCRYPTO_USE_BORINGSSL_EVP_DO_ALL_FALLBACK #include #include -#include #endif #include #include #include #include #include +#include #if OPENSSL_VERSION_MAJOR >= 3 #include #include #include +#include +#include #if OPENSSL_WITH_ARGON2 #include #endif @@ -76,6 +79,17 @@ using BignumCtxPointer = DeleteFnPtr; using BignumGenCallbackPointer = DeleteFnPtr; using NetscapeSPKIPointer = DeleteFnPtr; +#if NCRYPTO_USE_OPENSSL3_PROVIDER +using X509PubKeyPointer = DeleteFnPtr; +// OSSL_STORE_close() returns int, so it needs a void-returning adapter to be +// usable as a DeleteFnPtr deleter. +void CloseStoreCtx(OSSL_STORE_CTX* ctx) { + OSSL_STORE_close(ctx); +} +using StoreCtxPointer = DeleteFnPtr; +using UIMethodPointer = DeleteFnPtr; +#endif + const EVP_CIPHER* GetCipherCtxCipher(const EVP_CIPHER_CTX* ctx) { #if NCRYPTO_USE_OPENSSL3_PROVIDER return EVP_CIPHER_CTX_get0_cipher(ctx); @@ -332,7 +346,7 @@ ClearErrorOnReturn::~ClearErrorOnReturn() { ERR_clear_error(); } -int ClearErrorOnReturn::peekError() { +unsigned long ClearErrorOnReturn::peekError() { // NOLINT(runtime/int) return ERR_peek_error(); } @@ -346,7 +360,7 @@ MarkPopErrorOnReturn::~MarkPopErrorOnReturn() { ERR_pop_to_mark(); } -int MarkPopErrorOnReturn::peekError() { +unsigned long MarkPopErrorOnReturn::peekError() { // NOLINT(runtime/int) return ERR_peek_error(); } @@ -383,15 +397,7 @@ std::optional CryptoErrorList::pop_front() { // ============================================================================ DataPointer DataPointer::Alloc(size_t len) { -#ifdef OPENSSL_IS_BORINGSSL - // Boringssl does not implement OPENSSL_zalloc - auto ptr = OPENSSL_malloc(len); - if (ptr == nullptr) return {}; - memset(ptr, 0, len); - return DataPointer(ptr, len); -#else return DataPointer(OPENSSL_zalloc(len), len); -#endif } DataPointer DataPointer::SecureAlloc(size_t len) { @@ -414,18 +420,11 @@ DataPointer DataPointer::SecureAlloc(size_t len) { } size_t DataPointer::GetSecureHeapUsed() { -#ifndef OPENSSL_IS_BORINGSSL return CRYPTO_secure_malloc_initialized() ? CRYPTO_secure_used() : 0; -#else - // BoringSSL does not have the secure heap and therefore - // will always return 0. - return 0; -#endif } DataPointer::InitSecureHeapResult DataPointer::TryInitSecureHeap(size_t amount, size_t min) { -#ifndef OPENSSL_IS_BORINGSSL switch (CRYPTO_secure_malloc_init(amount, min)) { case 0: return InitSecureHeapResult::FAILED; @@ -436,10 +435,6 @@ DataPointer::InitSecureHeapResult DataPointer::TryInitSecureHeap(size_t amount, default: return InitSecureHeapResult::FAILED; } -#else - // BoringSSL does not actually support the secure heap - return InitSecureHeapResult::FAILED; -#endif } DataPointer DataPointer::Copy(const Buffer& buffer) { @@ -526,8 +521,7 @@ bool setFipsEnabled(bool enable, CryptoErrorList* errors) { if (isFipsEnabled() == enable) return true; ClearErrorOnReturn clearErrorOnReturn(errors); #if OPENSSL_VERSION_MAJOR >= 3 - return EVP_default_properties_enable_fips(nullptr, enable ? 1 : 0) == 1 && - EVP_default_properties_is_fips_enabled(nullptr); + return EVP_default_properties_enable_fips(nullptr, enable ? 1 : 0) == 1; #else return FIPS_mode_set(enable ? 1 : 0) == 1; #endif @@ -568,12 +562,7 @@ BignumPointer BignumPointer::New() { } BignumPointer BignumPointer::NewSecure() { -#ifdef OPENSSL_IS_BORINGSSL - // Boringssl does not implement BN_secure_new. - return New(); -#else return BignumPointer(BN_secure_new()); -#endif } BignumPointer& BignumPointer::operator=(BignumPointer&& other) noexcept { @@ -840,6 +829,7 @@ int NoPasswordCallback(char* buf, int size, int rwflag, void* u) { int PasswordCallback(char* buf, int size, int rwflag, void* u) { auto passphrase = static_cast*>(u); + if (size <= 0) return -1; if (passphrase != nullptr) { size_t buflen = static_cast(size); size_t len = passphrase->len; @@ -851,6 +841,31 @@ int PasswordCallback(char* buf, int size, int rwflag, void* u) { return -1; } +#if NCRYPTO_USE_OPENSSL3_PROVIDER +namespace { +struct StorePassphraseData { + Buffer passphrase{.data = nullptr, .len = 0}; + bool has_passphrase = false; + bool missing_passphrase = false; +}; + +int StorePasswordCallback(char* buf, int size, int rwflag, void* u) { + auto data = static_cast(u); + if (data == nullptr || !data->has_passphrase) { + if (data != nullptr) data->missing_passphrase = true; + return -1; + } + + if (size <= 0) return -1; + size_t buflen = static_cast(size); + size_t len = data->passphrase.len; + if (buflen < len) return -1; + memcpy(buf, reinterpret_cast(data->passphrase.data), len); + return len; +} +} // namespace +#endif + // Algorithm: http://howardhinnant.github.io/date_algorithms.html constexpr int days_from_epoch(int y, unsigned m, unsigned d) { y -= m <= 2; @@ -2238,14 +2253,11 @@ DHPointer::CheckPublicKeyResult DHPointer::checkPublicKey( if (DH_check_pub_key(dh_.get(), pub_key.get(), &codes) != 1) { return DHPointer::CheckPublicKeyResult::CHECK_FAILED; } -#ifndef OPENSSL_IS_BORINGSSL - // Boringssl does not define DH_CHECK_PUBKEY_TOO_SMALL or TOO_LARGE if (codes & DH_CHECK_PUBKEY_TOO_SMALL) { return DHPointer::CheckPublicKeyResult::TOO_SMALL; } else if (codes & DH_CHECK_PUBKEY_TOO_LARGE) { return DHPointer::CheckPublicKeyResult::TOO_LARGE; } -#endif if (codes != 0) { return DHPointer::CheckPublicKeyResult::INVALID; } @@ -3585,7 +3597,7 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePrivateKey( const Buffer& buffer) { static constexpr auto keyOrError = [](EVPKeyPointer pkey, bool had_passphrase = false) { - if (int err = ERR_peek_error()) { + if (unsigned long err = ERR_peek_error()) { // NOLINT(runtime/int) if (ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_BAD_PASSWORD_READ && !had_passphrase) { return ParseKeyResult(PKParseError::NEED_PASSPHRASE); @@ -3645,6 +3657,99 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePrivateKey( }; } +EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryLoadPrivateKeyFromStore( + const StorePrivateKeyConfig& config) { +#if !NCRYPTO_USE_OPENSSL3_PROVIDER + return ParseKeyResult(PKParseError::FAILED); +#else + // The error queue is left populated on failure so the caller can surface a + // `code` and an `opensslErrorStack`, matching TryParsePrivateKey(), and is + // cleared on success because decoders leave entries behind either way. + std::string uri_str(config.uri); + std::string properties_str; + const char* properties = nullptr; + if (config.properties.has_value() && !config.properties->empty()) { + properties_str.assign(config.properties->data(), config.properties->size()); + properties = properties_str.c_str(); + } + + // config.passphrase outlives this call, so no copy is needed. + Buffer passbuf{.data = nullptr, .len = 0}; + if (config.passphrase.has_value()) { + passbuf.data = const_cast(config.passphrase->data); + passbuf.len = config.passphrase->len; + } + StorePassphraseData passphrase_data{ + .passphrase = passbuf, + .has_passphrase = config.passphrase.has_value(), + }; + // Declared before ctx so that reverse destruction closes the store first; + // it holds both for its lifetime. + UIMethodPointer ui_method( + UI_UTIL_wrap_read_pem_callback(StorePasswordCallback, 0)); + if (!ui_method) return ParseKeyResult(PKParseError::FAILED); + + // Errors from loaders that declined the URI are retained oldest-first, so the + // newest entry is the loader that actually handled it. Must run before ctx is + // destroyed, since OSSL_STORE_close() can push errors of its own. + const auto failed = [&](bool missing_passphrase) { + if (missing_passphrase) + return ParseKeyResult(PKParseError::NEED_PASSPHRASE); + return ParseKeyResult(PKParseError::FAILED, ERR_peek_last_error()); + }; + + const OSSL_PARAM store_params[] = {OSSL_PARAM_END}; + StoreCtxPointer ctx(OSSL_STORE_open_ex(uri_str.c_str(), + nullptr, + properties, + ui_method.get(), + &passphrase_data, + store_params, + nullptr, + nullptr)); + if (!ctx) return failed(passphrase_data.missing_passphrase); + + if (!OSSL_STORE_expect(ctx.get(), OSSL_STORE_INFO_PKEY)) { + return failed(passphrase_data.missing_passphrase); + } + + EVPKeyPointer pkey; + bool store_error = false; + while (!OSSL_STORE_eof(ctx.get())) { + OSSL_STORE_INFO* info = OSSL_STORE_load(ctx.get()); + if (info == nullptr) { + if (OSSL_STORE_error(ctx.get())) { + store_error = true; + break; + } + continue; + } + if (OSSL_STORE_INFO_get_type(info) == OSSL_STORE_INFO_PKEY) { + EVP_PKEY* raw_pkey = OSSL_STORE_INFO_get1_PKEY(info); + if (raw_pkey != nullptr) { + pkey = EVPKeyPointer(raw_pkey); + } else { + store_error = true; + } + } + OSSL_STORE_INFO_free(info); + if (pkey || store_error) break; + } + + // missing_passphrase is sticky, so a key that loaded anyway wins over it. + if (pkey) { + ctx.reset(); + ERR_clear_error(); + return ParseKeyResult(std::move(pkey)); + } + + if (passphrase_data.missing_passphrase || store_error) { + return failed(passphrase_data.missing_passphrase); + } + return ParseKeyResult(PKParseError::NOT_RECOGNIZED); +#endif +} + Result EVPKeyPointer::writePrivateKey( const PrivateKeyEncodingConfig& config) const { if (config.format == PKFormatType::JWK) { @@ -3686,6 +3791,8 @@ Result EVPKeyPointer::writePrivateKey( #else RSA* rsa = EVP_PKEY_get0_RSA(get()); #endif + if (rsa == nullptr) return Result(false); + switch (config.format) { case PKFormatType::PEM: { err = PEM_write_bio_RSAPrivateKey( @@ -3761,6 +3868,8 @@ Result EVPKeyPointer::writePrivateKey( #else EC_KEY* ec = EVP_PKEY_get0_EC_KEY(get()); #endif + if (ec == nullptr) return Result(false); + switch (config.format) { case PKFormatType::PEM: { err = PEM_write_bio_ECPrivateKey( @@ -3827,6 +3936,8 @@ Result EVPKeyPointer::writePublicKey( #else RSA* rsa = EVP_PKEY_get0_RSA(get()); #endif + if (rsa == nullptr) return Result(false); + if (config.format == ncrypto::EVPKeyPointer::PKFormatType::PEM) { // Encode PKCS#1 as PEM. if (PEM_write_bio_RSAPublicKey(bio.get(), rsa) != 1) { @@ -3855,10 +3966,28 @@ Result EVPKeyPointer::writePublicKey( if (config.format == ncrypto::EVPKeyPointer::PKFormatType::PEM) { // Encode SPKI as PEM. +#if NCRYPTO_USE_OPENSSL3_PROVIDER + // Build the SubjectPublicKeyInfo wrapper explicitly before PEM encoding. + // Provider-backed keys can fail the direct PEM_write_bio_PUBKEY() path even + // when OpenSSL can materialize the public wrapper with X509_PUBKEY_set(). + X509_PUBKEY* pubkey = nullptr; + if (X509_PUBKEY_set(&pubkey, get()) != 1) { + X509_PUBKEY_free(pubkey); + return Result(false, + mark_pop_error_on_return.peekError()); + } + X509PubKeyPointer pubkey_ptr(pubkey); + if (PEM_write_bio_X509_PUBKEY(bio.get(), pubkey_ptr.get()) != 1) { + return Result(false, + mark_pop_error_on_return.peekError()); + } +#else + // Non-OpenSSL >= 3 builds do not all declare PEM_write_bio_X509_PUBKEY(). if (PEM_write_bio_PUBKEY(bio.get(), get()) != 1) { return Result(false, mark_pop_error_on_return.peekError()); } +#endif return bio; } @@ -3929,21 +4058,37 @@ std::optional EVPKeyPointer::getBytesOfRS() const { bits = BignumPointer::GetBitCount(q.get()); #else const DSA* dsa_key = EVP_PKEY_get0_DSA(get()); + bool has_bits = false; // Both r and s are computed mod q, so their width is limited by that of q. - bits = BignumPointer::GetBitCount(DSA_get0_q(dsa_key)); + if (dsa_key != nullptr) { + const BIGNUM* q = DSA_get0_q(dsa_key); + if (q != nullptr) { + bits = BignumPointer::GetBitCount(q); + has_bits = true; + } + } + if (!has_bits) return std::nullopt; #endif } else if (id == EVP_PKEY_EC) { #if NCRYPTO_USE_OPENSSL3_PROVIDER Ec ec(get()); if (!ec) return std::nullopt; - bits = EC_GROUP_order_bits(ec.getGroup()); + const EC_GROUP* group = ec.getGroup(); + if (group == nullptr) return std::nullopt; + bits = EC_GROUP_order_bits(group); #else - bits = EC_GROUP_order_bits(ECKeyPointer::GetGroup(*this)); + const EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(get()); + if (ec_key == nullptr) return std::nullopt; + const EC_GROUP* group = ECKeyPointer::GetGroup(ec_key); + if (group == nullptr) return std::nullopt; + bits = EC_GROUP_order_bits(group); #endif } else { return std::nullopt; } + if (bits <= 0) return std::nullopt; + return (bits + 7) / 8; } @@ -3982,12 +4127,12 @@ EVPKeyPointer::operator Dsa() const { bool EVPKeyPointer::validateDsaParameters() const { if (!pkey_) return false; - /* Validate DSA2 parameters from FIPS 186-4 */ #if OPENSSL_VERSION_MAJOR >= 3 if (EVP_default_properties_is_fips_enabled(nullptr) && EVP_PKEY_DSA == id()) { #else if (FIPS_mode() && EVP_PKEY_DSA == id()) { #endif + // Validate DSA2 parameters from FIPS 186-4. #if NCRYPTO_USE_OPENSSL3_PROVIDER DeleteFnPtr p; DeleteFnPtr q; @@ -3999,9 +4144,11 @@ bool EVPKeyPointer::validateDsaParameters() const { const BIGNUM* q_value = q.get(); #else const DSA* dsa = EVP_PKEY_get0_DSA(pkey_.get()); + if (dsa == nullptr) return false; const BIGNUM* p; const BIGNUM* q; DSA_get0_pqg(dsa, &p, &q, nullptr); + if (p == nullptr || q == nullptr) return false; const BIGNUM* p_value = p; const BIGNUM* q_value = q; #endif @@ -4115,59 +4262,6 @@ std::optional SSLPointer::verifyPeerCertificate() const { return std::nullopt; } -const char* SSLPointer::getClientHelloAlpn() const { - if (ssl_ == nullptr) return {}; -#ifndef OPENSSL_IS_BORINGSSL - const unsigned char* buf; - size_t len; - size_t rem; - - if (!SSL_client_hello_get0_ext( - get(), - TLSEXT_TYPE_application_layer_protocol_negotiation, - &buf, - &rem) || - rem < 2) { - return {}; - } - - len = (buf[0] << 8) | buf[1]; - if (len + 2 != rem) return {}; - return reinterpret_cast(buf + 3); -#else - // Boringssl doesn't have a public API for this. - return {}; -#endif -} - -const char* SSLPointer::getClientHelloServerName() const { - if (ssl_ == nullptr) return {}; -#ifndef OPENSSL_IS_BORINGSSL - const unsigned char* buf; - size_t len; - size_t rem; - - if (!SSL_client_hello_get0_ext(get(), TLSEXT_TYPE_server_name, &buf, &rem) || - rem <= 2) { - return {}; - } - - len = (*buf << 8) | *(buf + 1); - if (len + 2 != rem) return {}; - rem = len; - - if (rem == 0 || *(buf + 2) != TLSEXT_NAMETYPE_host_name) return {}; - rem--; - if (rem <= 2) return {}; - len = (*(buf + 3) << 8) | *(buf + 4); - if (len + 2 > rem) return {}; - return reinterpret_cast(buf + 5); -#else - // Boringssl doesn't have a public API for this. - return {}; -#endif -} - std::optional SSLPointer::GetServerName( const SSL* ssl) { if (ssl == nullptr) return std::nullopt; @@ -4213,6 +4307,13 @@ std::optional SSLPointer::getNegotiatedGroup() const { const char* group = SSL_get0_group_name(get()); if (group == nullptr) return std::nullopt; return group; +#elif defined(OPENSSL_IS_BORINGSSL) + if (!ssl_) return std::nullopt; + const int nid = SSL_get_negotiated_group(get()); + if (nid == NID_undef) return std::nullopt; + const char* group = OBJ_nid2sn(nid); + if (group == nullptr) return std::nullopt; + return group; #else return std::nullopt; #endif @@ -4237,19 +4338,17 @@ std::optional SSLPointer::getCipherVersion() const { } std::optional SSLPointer::getSecurityLevel() { -#ifndef OPENSSL_IS_BORINGSSL auto ctx = SSLCtxPointer::New(); if (!ctx) return std::nullopt; +#ifdef OPENSSL_IS_BORINGSSL + return SSL_CTX_get_security_level(ctx.get()); +#else auto ssl = SSLPointer::New(ctx); if (!ssl) return std::nullopt; return SSL_get_security_level(ssl); -#else - // OPENSSL_TLS_SECURITY_LEVEL is not defined in BoringSSL - // so assume it is the default OPENSSL_TLS_SECURITY_LEVEL value. - return 1; -#endif // OPENSSL_IS_BORINGSSL +#endif } SSLCtxPointer::SSLCtxPointer(SSL_CTX* ctx) : ctx_(ctx) {} @@ -6452,9 +6551,14 @@ DataPointer EVPMDCtxPointer::sign( bool EVPMDCtxPointer::verify(const Buffer& buf, const Buffer& sig) const { - if (!ctx_) return false; - int ret = EVP_DigestVerify(ctx_.get(), sig.data, sig.len, buf.data, buf.len); - return ret == 1; + return verifyOneShot(buf, sig) == 1; +} + +int EVPMDCtxPointer::verifyOneShot( + const Buffer& buf, + const Buffer& sig) const { + if (!ctx_) return -1; + return EVP_DigestVerify(ctx_.get(), sig.data, sig.len, buf.data, buf.len); } EVPMDCtxPointer EVPMDCtxPointer::New() { @@ -6801,6 +6905,9 @@ std::pair X509Name::Iterator::operator*() const { unsigned char* value_str; int value_str_size = ASN1_STRING_to_UTF8(&value_str, value); + if (value_str_size < 0) [[unlikely]] { + return {{}, {}}; + } std::string out(reinterpret_cast(value_str), value_str_size); OPENSSL_free(value_str); // free after copy diff --git a/deps/ncrypto/ncrypto.h b/deps/ncrypto/ncrypto.h index 6fb6b384fd4f..f0e1e7451e4f 100644 --- a/deps/ncrypto/ncrypto.h +++ b/deps/ncrypto/ncrypto.h @@ -284,7 +284,7 @@ class ClearErrorOnReturn final { NCRYPTO_DISALLOW_COPY_AND_MOVE(ClearErrorOnReturn) NCRYPTO_DISALLOW_NEW_DELETE() - int peekError(); + unsigned long peekError(); // NOLINT(runtime/int) private: CryptoErrorList* errors_; @@ -302,7 +302,7 @@ class MarkPopErrorOnReturn final { NCRYPTO_DISALLOW_COPY_AND_MOVE(MarkPopErrorOnReturn) NCRYPTO_DISALLOW_NEW_DELETE() - int peekError(); + unsigned long peekError(); // NOLINT(runtime/int) private: CryptoErrorList* errors_; @@ -315,9 +315,11 @@ struct Result final { const bool has_value; T value; std::optional error = std::nullopt; - std::optional openssl_error = std::nullopt; + // NOLINTNEXTLINE(runtime/int) -- matches ERR_peek_error() + std::optional openssl_error = std::nullopt; Result(T&& value) : has_value(true), value(std::move(value)) {} - Result(E&& error, std::optional openssl_error = std::nullopt) + // NOLINTNEXTLINE(runtime/int) -- matches ERR_peek_error() + Result(E&& error, std::optional openssl_error = std::nullopt) : has_value(false), error(std::move(error)), openssl_error(std::move(openssl_error)) {} @@ -1046,6 +1048,7 @@ class EVPKeyPointer final { RAW_PUBLIC, RAW_PRIVATE, RAW_SEED, + STORE, }; enum class PKParseError { NOT_RECOGNIZED, NEED_PASSPHRASE, FAILED }; @@ -1078,6 +1081,12 @@ class EVPKeyPointer final { PrivateKeyEncodingConfig& operator=(const PrivateKeyEncodingConfig&); }; + struct StorePrivateKeyConfig { + std::string_view uri; + std::optional properties = std::nullopt; + std::optional> passphrase = std::nullopt; + }; + static ParseKeyResult TryParsePublicKey( const PublicKeyEncodingConfig& config, const Buffer& buffer); @@ -1089,6 +1098,14 @@ class EVPKeyPointer final { const PrivateKeyEncodingConfig& config, const Buffer& buffer); + // Loads a private key through an OpenSSL STORE loader using the configured + // URI (e.g. "file:", a provider-backed scheme such as "pkcs11:"). The + // optional passphrase is used as the PIN/passphrase for encrypted or + // token-protected keys. + // Returns NOT_RECOGNIZED when no private key is found at the URI. + static ParseKeyResult TryLoadPrivateKeyFromStore( + const StorePrivateKeyConfig& config); + EVPKeyPointer() = default; explicit EVPKeyPointer(EVP_PKEY* pkey); EVPKeyPointer(EVPKeyPointer&& other) noexcept; @@ -1213,9 +1230,9 @@ class DHPointer final { UNABLE_TO_CHECK_GENERATOR = 0x04, NOT_SUITABLE_GENERATOR = 0x08, Q_NOT_PRIME = 0x10, -#ifndef OPENSSL_IS_BORINGSSL - // Boringssl does not define the DH_CHECK_INVALID_[Q or J]_VALUE INVALID_Q = 0x20, +#ifndef OPENSSL_IS_BORINGSSL + // BoringSSL does not define DH_CHECK_INVALID_J_VALUE. INVALID_J = 0x40, MODULUS_TOO_SMALL = 0x80, MODULUS_TOO_LARGE = 0x100, @@ -1226,14 +1243,9 @@ class DHPointer final { enum class CheckPublicKeyResult { NONE, -#ifndef OPENSSL_IS_BORINGSSL - // Boringssl does not define DH_R_CHECK_PUBKEY_TOO_SMALL or TOO_LARGE - TOO_SMALL = DH_R_CHECK_PUBKEY_TOO_SMALL, - TOO_LARGE = DH_R_CHECK_PUBKEY_TOO_LARGE, - INVALID = DH_R_CHECK_PUBKEY_INVALID, -#else - INVALID = DH_R_INVALID_PUBKEY, -#endif + TOO_SMALL, + TOO_LARGE, + INVALID, CHECK_FAILED = 512, }; // Check to see if the given public key is suitable for this DH instance. @@ -1328,9 +1340,6 @@ class SSLPointer final { bool setSession(const SSLSessionPointer& session); bool setSniContext(const SSLCtxPointer& ctx) const; - const char* getClientHelloAlpn() const; - const char* getClientHelloServerName() const; - std::optional getServerName() const; X509View getCertificate() const; EVPKeyPointer getPeerTempKey() const; @@ -1681,6 +1690,9 @@ class EVPMDCtxPointer final { DataPointer sign(const Buffer& buf) const; bool verify(const Buffer& buf, const Buffer& sig) const; + // Unlike verify(), preserves EVP_DigestVerify()'s three-way result. + int verifyOneShot(const Buffer& buf, + const Buffer& sig) const; const EVP_MD* getDigest() const; size_t getDigestSize() const; diff --git a/deps/openssl/config/archs/BSD-x86/asm/configdata.pm b/deps/openssl/config/archs/BSD-x86/asm/configdata.pm index 342baff185b4..794e2fbadfc0 100644 --- a/deps/openssl/config/archs/BSD-x86/asm/configdata.pm +++ b/deps/openssl/config/archs/BSD-x86/asm/configdata.pm @@ -171,7 +171,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -230,7 +230,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -289,11 +289,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "BSD-x86", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2255,6 +2255,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2291,6 +2294,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4949,6 +4955,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4985,6 +4994,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11310,6 +11322,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11346,6 +11361,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14004,6 +14022,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14040,6 +14061,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16437,6 +16461,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16449,6 +16474,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18560,6 +18586,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18572,6 +18599,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/BSD-x86/asm/crypto/buildinf.h b/deps/openssl/config/archs/BSD-x86/asm/crypto/buildinf.h index 8fb459eda8aa..ad498bcd8698 100644 --- a/deps/openssl/config/archs/BSD-x86/asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/BSD-x86/asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: BSD-x86" -#define DATE "built on: Wed Jun 17 17:24:13 2026 UTC" +#define DATE "built on: Tue Aug 25 12:44:29 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/BSD-x86/asm/include/openssl/opensslv.h b/deps/openssl/config/archs/BSD-x86/asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/BSD-x86/asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/BSD-x86/asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/BSD-x86/asm/include/openssl/ssl.h b/deps/openssl/config/archs/BSD-x86/asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/BSD-x86/asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/BSD-x86/asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/BSD-x86/asm_avx2/configdata.pm b/deps/openssl/config/archs/BSD-x86/asm_avx2/configdata.pm index 8da34b75ff22..6a5d9a71556e 100644 --- a/deps/openssl/config/archs/BSD-x86/asm_avx2/configdata.pm +++ b/deps/openssl/config/archs/BSD-x86/asm_avx2/configdata.pm @@ -171,7 +171,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -230,7 +230,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -289,11 +289,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "BSD-x86", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2255,6 +2255,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2291,6 +2294,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4949,6 +4955,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4985,6 +4994,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11310,6 +11322,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11346,6 +11361,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14004,6 +14022,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14040,6 +14061,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16437,6 +16461,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16449,6 +16474,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18560,6 +18586,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18572,6 +18599,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/BSD-x86/asm_avx2/crypto/buildinf.h b/deps/openssl/config/archs/BSD-x86/asm_avx2/crypto/buildinf.h index aaf1250c2eb9..886d18c40c7a 100644 --- a/deps/openssl/config/archs/BSD-x86/asm_avx2/crypto/buildinf.h +++ b/deps/openssl/config/archs/BSD-x86/asm_avx2/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: BSD-x86" -#define DATE "built on: Wed Jun 17 17:24:28 2026 UTC" +#define DATE "built on: Tue Aug 25 12:44:44 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/BSD-x86/asm_avx2/include/openssl/opensslv.h b/deps/openssl/config/archs/BSD-x86/asm_avx2/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/BSD-x86/asm_avx2/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/BSD-x86/asm_avx2/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/BSD-x86/asm_avx2/include/openssl/ssl.h b/deps/openssl/config/archs/BSD-x86/asm_avx2/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/BSD-x86/asm_avx2/include/openssl/ssl.h +++ b/deps/openssl/config/archs/BSD-x86/asm_avx2/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/BSD-x86/no-asm/configdata.pm b/deps/openssl/config/archs/BSD-x86/no-asm/configdata.pm index 1abbedbdd1f2..594e50c9e1dd 100644 --- a/deps/openssl/config/archs/BSD-x86/no-asm/configdata.pm +++ b/deps/openssl/config/archs/BSD-x86/no-asm/configdata.pm @@ -169,7 +169,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -229,7 +229,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-asm no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -289,11 +289,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "BSD-x86", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2197,6 +2197,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2233,6 +2236,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4891,6 +4897,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4927,6 +4936,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11230,6 +11242,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11266,6 +11281,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13924,6 +13942,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -13960,6 +13981,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16357,6 +16381,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16369,6 +16394,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18477,6 +18503,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18489,6 +18516,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/BSD-x86/no-asm/crypto/buildinf.h b/deps/openssl/config/archs/BSD-x86/no-asm/crypto/buildinf.h index 7194e465d77f..ffb93d229d90 100644 --- a/deps/openssl/config/archs/BSD-x86/no-asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/BSD-x86/no-asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: BSD-x86" -#define DATE "built on: Wed Jun 17 17:24:40 2026 UTC" +#define DATE "built on: Tue Aug 25 12:44:58 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/BSD-x86/no-asm/include/openssl/opensslv.h b/deps/openssl/config/archs/BSD-x86/no-asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/BSD-x86/no-asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/BSD-x86/no-asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/BSD-x86/no-asm/include/openssl/ssl.h b/deps/openssl/config/archs/BSD-x86/no-asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/BSD-x86/no-asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/BSD-x86/no-asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/BSD-x86_64/asm/configdata.pm b/deps/openssl/config/archs/BSD-x86_64/asm/configdata.pm index 85988b43ff28..419e74c894d5 100644 --- a/deps/openssl/config/archs/BSD-x86_64/asm/configdata.pm +++ b/deps/openssl/config/archs/BSD-x86_64/asm/configdata.pm @@ -171,7 +171,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -230,7 +230,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -289,11 +289,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "BSD-x86_64", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2262,6 +2262,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2298,6 +2301,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4956,6 +4962,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4992,6 +5001,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11367,6 +11379,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11403,6 +11418,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14061,6 +14079,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14097,6 +14118,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16494,6 +16518,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16506,6 +16531,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18617,6 +18643,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18629,6 +18656,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/BSD-x86_64/asm/crypto/buildinf.h b/deps/openssl/config/archs/BSD-x86_64/asm/crypto/buildinf.h index 90c939e43e74..53b792b74d2a 100644 --- a/deps/openssl/config/archs/BSD-x86_64/asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/BSD-x86_64/asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: BSD-x86_64" -#define DATE "built on: Wed Jun 17 17:24:50 2026 UTC" +#define DATE "built on: Tue Aug 25 12:45:12 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/BSD-x86_64/asm/include/openssl/opensslv.h b/deps/openssl/config/archs/BSD-x86_64/asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/BSD-x86_64/asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/BSD-x86_64/asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/BSD-x86_64/asm/include/openssl/ssl.h b/deps/openssl/config/archs/BSD-x86_64/asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/BSD-x86_64/asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/BSD-x86_64/asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/BSD-x86_64/asm_avx2/configdata.pm b/deps/openssl/config/archs/BSD-x86_64/asm_avx2/configdata.pm index 0a29d771007c..e9b4820b24d3 100644 --- a/deps/openssl/config/archs/BSD-x86_64/asm_avx2/configdata.pm +++ b/deps/openssl/config/archs/BSD-x86_64/asm_avx2/configdata.pm @@ -171,7 +171,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -230,7 +230,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -289,11 +289,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "BSD-x86_64", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2262,6 +2262,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2298,6 +2301,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4956,6 +4962,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4992,6 +5001,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11367,6 +11379,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11403,6 +11418,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14061,6 +14079,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14097,6 +14118,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16494,6 +16518,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16506,6 +16531,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18617,6 +18643,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18629,6 +18656,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/BSD-x86_64/asm_avx2/crypto/buildinf.h b/deps/openssl/config/archs/BSD-x86_64/asm_avx2/crypto/buildinf.h index 3844ec592bb9..9ead0cd60d51 100644 --- a/deps/openssl/config/archs/BSD-x86_64/asm_avx2/crypto/buildinf.h +++ b/deps/openssl/config/archs/BSD-x86_64/asm_avx2/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: BSD-x86_64" -#define DATE "built on: Wed Jun 17 17:25:05 2026 UTC" +#define DATE "built on: Tue Aug 25 12:45:34 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/BSD-x86_64/asm_avx2/include/openssl/opensslv.h b/deps/openssl/config/archs/BSD-x86_64/asm_avx2/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/BSD-x86_64/asm_avx2/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/BSD-x86_64/asm_avx2/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/BSD-x86_64/asm_avx2/include/openssl/ssl.h b/deps/openssl/config/archs/BSD-x86_64/asm_avx2/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/BSD-x86_64/asm_avx2/include/openssl/ssl.h +++ b/deps/openssl/config/archs/BSD-x86_64/asm_avx2/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/BSD-x86_64/no-asm/configdata.pm b/deps/openssl/config/archs/BSD-x86_64/no-asm/configdata.pm index 228a341abe41..22ca6435e306 100644 --- a/deps/openssl/config/archs/BSD-x86_64/no-asm/configdata.pm +++ b/deps/openssl/config/archs/BSD-x86_64/no-asm/configdata.pm @@ -169,7 +169,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -229,7 +229,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-asm no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -289,11 +289,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "BSD-x86_64", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2198,6 +2198,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2234,6 +2237,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4892,6 +4898,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4928,6 +4937,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11231,6 +11243,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11267,6 +11282,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13925,6 +13943,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -13961,6 +13982,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16358,6 +16382,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16370,6 +16395,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18478,6 +18504,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18490,6 +18517,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/BSD-x86_64/no-asm/crypto/buildinf.h b/deps/openssl/config/archs/BSD-x86_64/no-asm/crypto/buildinf.h index 12358c812fdd..10b8da56e43e 100644 --- a/deps/openssl/config/archs/BSD-x86_64/no-asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/BSD-x86_64/no-asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: BSD-x86_64" -#define DATE "built on: Wed Jun 17 17:25:17 2026 UTC" +#define DATE "built on: Tue Aug 25 12:45:51 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/BSD-x86_64/no-asm/include/openssl/opensslv.h b/deps/openssl/config/archs/BSD-x86_64/no-asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/BSD-x86_64/no-asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/BSD-x86_64/no-asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/BSD-x86_64/no-asm/include/openssl/ssl.h b/deps/openssl/config/archs/BSD-x86_64/no-asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/BSD-x86_64/no-asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/BSD-x86_64/no-asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/VC-WIN32/asm/configdata.pm b/deps/openssl/config/archs/VC-WIN32/asm/configdata.pm index 80bcccf1ac5f..878ab12b42ec 100644 --- a/deps/openssl/config/archs/VC-WIN32/asm/configdata.pm +++ b/deps/openssl/config/archs/VC-WIN32/asm/configdata.pm @@ -179,7 +179,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -241,7 +241,7 @@ our %config = ( ], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -300,11 +300,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "VC-WIN32", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "lib", @@ -319,7 +319,7 @@ our %target = ( "LDFLAGS" => "/nologo /debug", "MT" => "mt", "MTFLAGS" => "-nologo", - "RANLIB" => "CODE(0x562840350400)", + "RANLIB" => "CODE(0x557949e58080)", "RC" => "rc", "_conf_fname_int" => [ "Configurations/00-base-templates.conf", @@ -2297,6 +2297,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2333,6 +2336,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4991,6 +4997,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -5027,6 +5036,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11362,6 +11374,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11398,6 +11413,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14056,6 +14074,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14092,6 +14113,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16505,6 +16529,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16517,6 +16542,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18634,6 +18660,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18646,6 +18673,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/VC-WIN32/asm/crypto/buildinf.h b/deps/openssl/config/archs/VC-WIN32/asm/crypto/buildinf.h index b911d0bf0f48..7d155abc0f17 100644 --- a/deps/openssl/config/archs/VC-WIN32/asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/VC-WIN32/asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: " -#define DATE "built on: Wed Jun 17 17:32:43 2026 UTC" +#define DATE "built on: Tue Aug 25 12:57:17 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/VC-WIN32/asm/include/openssl/opensslv.h b/deps/openssl/config/archs/VC-WIN32/asm/include/openssl/opensslv.h index 2ffd28f17e80..5baff3e0aff8 100644 --- a/deps/openssl/config/archs/VC-WIN32/asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/VC-WIN32/asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/VC-WIN32/asm/include/openssl/ssl.h b/deps/openssl/config/archs/VC-WIN32/asm/include/openssl/ssl.h index 0e7eb9dfb947..0614d70ba587 100644 --- a/deps/openssl/config/archs/VC-WIN32/asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/VC-WIN32/asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/VC-WIN32/asm_avx2/configdata.pm b/deps/openssl/config/archs/VC-WIN32/asm_avx2/configdata.pm index 187188b3bbeb..1d364782e66c 100644 --- a/deps/openssl/config/archs/VC-WIN32/asm_avx2/configdata.pm +++ b/deps/openssl/config/archs/VC-WIN32/asm_avx2/configdata.pm @@ -179,7 +179,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -241,7 +241,7 @@ our %config = ( ], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -300,11 +300,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "VC-WIN32", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "lib", @@ -319,7 +319,7 @@ our %target = ( "LDFLAGS" => "/nologo /debug", "MT" => "mt", "MTFLAGS" => "-nologo", - "RANLIB" => "CODE(0x5cdb439ab740)", + "RANLIB" => "CODE(0x5638823c9d80)", "RC" => "rc", "_conf_fname_int" => [ "Configurations/00-base-templates.conf", @@ -2297,6 +2297,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2333,6 +2336,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4991,6 +4997,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -5027,6 +5036,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11362,6 +11374,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11398,6 +11413,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14056,6 +14074,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14092,6 +14113,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16505,6 +16529,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16517,6 +16542,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18634,6 +18660,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18646,6 +18673,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/VC-WIN32/asm_avx2/crypto/buildinf.h b/deps/openssl/config/archs/VC-WIN32/asm_avx2/crypto/buildinf.h index 75e1b25e955b..12162fc406ed 100644 --- a/deps/openssl/config/archs/VC-WIN32/asm_avx2/crypto/buildinf.h +++ b/deps/openssl/config/archs/VC-WIN32/asm_avx2/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: " -#define DATE "built on: Wed Jun 17 17:32:51 2026 UTC" +#define DATE "built on: Tue Aug 25 12:57:30 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/VC-WIN32/asm_avx2/include/openssl/opensslv.h b/deps/openssl/config/archs/VC-WIN32/asm_avx2/include/openssl/opensslv.h index 2ffd28f17e80..5baff3e0aff8 100644 --- a/deps/openssl/config/archs/VC-WIN32/asm_avx2/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/VC-WIN32/asm_avx2/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/VC-WIN32/asm_avx2/include/openssl/ssl.h b/deps/openssl/config/archs/VC-WIN32/asm_avx2/include/openssl/ssl.h index 0e7eb9dfb947..0614d70ba587 100644 --- a/deps/openssl/config/archs/VC-WIN32/asm_avx2/include/openssl/ssl.h +++ b/deps/openssl/config/archs/VC-WIN32/asm_avx2/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/VC-WIN32/no-asm/configdata.pm b/deps/openssl/config/archs/VC-WIN32/no-asm/configdata.pm index 008cef87f42b..6fbad93147c4 100644 --- a/deps/openssl/config/archs/VC-WIN32/no-asm/configdata.pm +++ b/deps/openssl/config/archs/VC-WIN32/no-asm/configdata.pm @@ -177,7 +177,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -240,7 +240,7 @@ our %config = ( ], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-asm no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -300,11 +300,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "VC-WIN32", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "lib", @@ -319,7 +319,7 @@ our %target = ( "LDFLAGS" => "/nologo /debug", "MT" => "mt", "MTFLAGS" => "-nologo", - "RANLIB" => "CODE(0x5d62f9217618)", + "RANLIB" => "CODE(0x5602eb82b768)", "RC" => "rc", "_conf_fname_int" => [ "Configurations/00-base-templates.conf", @@ -2239,6 +2239,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2275,6 +2278,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4933,6 +4939,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4969,6 +4978,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11282,6 +11294,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11318,6 +11333,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13976,6 +13994,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14012,6 +14033,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16425,6 +16449,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16437,6 +16462,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18551,6 +18577,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18563,6 +18590,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/VC-WIN32/no-asm/crypto/buildinf.h b/deps/openssl/config/archs/VC-WIN32/no-asm/crypto/buildinf.h index d1043a5a91ce..1076ee612fc8 100644 --- a/deps/openssl/config/archs/VC-WIN32/no-asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/VC-WIN32/no-asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: " -#define DATE "built on: Wed Jun 17 17:33:00 2026 UTC" +#define DATE "built on: Tue Aug 25 12:57:43 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/VC-WIN32/no-asm/include/openssl/opensslv.h b/deps/openssl/config/archs/VC-WIN32/no-asm/include/openssl/opensslv.h index 2ffd28f17e80..5baff3e0aff8 100644 --- a/deps/openssl/config/archs/VC-WIN32/no-asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/VC-WIN32/no-asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/VC-WIN32/no-asm/include/openssl/ssl.h b/deps/openssl/config/archs/VC-WIN32/no-asm/include/openssl/ssl.h index 0e7eb9dfb947..0614d70ba587 100644 --- a/deps/openssl/config/archs/VC-WIN32/no-asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/VC-WIN32/no-asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/VC-WIN64-ARM/no-asm/configdata.pm b/deps/openssl/config/archs/VC-WIN64-ARM/no-asm/configdata.pm index c141dc5f2515..f70c0340bbfc 100644 --- a/deps/openssl/config/archs/VC-WIN64-ARM/no-asm/configdata.pm +++ b/deps/openssl/config/archs/VC-WIN64-ARM/no-asm/configdata.pm @@ -177,7 +177,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -238,7 +238,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-asm no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -298,11 +298,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "VC-WIN64-ARM", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "lib", @@ -315,7 +315,7 @@ our %target = ( "LDFLAGS" => "/nologo /debug", "MT" => "mt", "MTFLAGS" => "-nologo", - "RANLIB" => "CODE(0x64360b888a98)", + "RANLIB" => "CODE(0x56183358b738)", "RC" => "rc", "_conf_fname_int" => [ "Configurations/00-base-templates.conf", @@ -2231,6 +2231,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2267,6 +2270,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4925,6 +4931,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4961,6 +4970,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11274,6 +11286,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11310,6 +11325,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13968,6 +13986,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14004,6 +14025,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16417,6 +16441,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16429,6 +16454,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18543,6 +18569,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18555,6 +18582,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/VC-WIN64-ARM/no-asm/crypto/buildinf.h b/deps/openssl/config/archs/VC-WIN64-ARM/no-asm/crypto/buildinf.h index b23392930c57..bfad73d12312 100644 --- a/deps/openssl/config/archs/VC-WIN64-ARM/no-asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/VC-WIN64-ARM/no-asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: VC-WIN64-ARM" -#define DATE "built on: Wed Jun 17 17:33:08 2026 UTC" +#define DATE "built on: Tue Aug 25 12:57:55 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/VC-WIN64-ARM/no-asm/include/openssl/opensslv.h b/deps/openssl/config/archs/VC-WIN64-ARM/no-asm/include/openssl/opensslv.h index 2ffd28f17e80..5baff3e0aff8 100644 --- a/deps/openssl/config/archs/VC-WIN64-ARM/no-asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/VC-WIN64-ARM/no-asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/VC-WIN64-ARM/no-asm/include/openssl/ssl.h b/deps/openssl/config/archs/VC-WIN64-ARM/no-asm/include/openssl/ssl.h index 0e7eb9dfb947..0614d70ba587 100644 --- a/deps/openssl/config/archs/VC-WIN64-ARM/no-asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/VC-WIN64-ARM/no-asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/VC-WIN64A/asm/configdata.pm b/deps/openssl/config/archs/VC-WIN64A/asm/configdata.pm index 3705788690f3..3134fb366bd3 100644 --- a/deps/openssl/config/archs/VC-WIN64A/asm/configdata.pm +++ b/deps/openssl/config/archs/VC-WIN64A/asm/configdata.pm @@ -181,7 +181,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -243,7 +243,7 @@ our %config = ( ], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -302,11 +302,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "VC-WIN64A", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "lib", @@ -321,7 +321,7 @@ our %target = ( "LDFLAGS" => "/nologo /debug", "MT" => "mt", "MTFLAGS" => "-nologo", - "RANLIB" => "CODE(0x5a2068d5ea10)", + "RANLIB" => "CODE(0x5592d548ade0)", "RC" => "rc", "_conf_fname_int" => [ "Configurations/00-base-templates.conf", @@ -2306,6 +2306,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2342,6 +2345,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -5000,6 +5006,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -5036,6 +5045,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11411,6 +11423,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11447,6 +11462,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14105,6 +14123,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14141,6 +14162,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16554,6 +16578,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16566,6 +16591,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18683,6 +18709,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18695,6 +18722,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/VC-WIN64A/asm/crypto/buildinf.h b/deps/openssl/config/archs/VC-WIN64A/asm/crypto/buildinf.h index 506df0c1ddd6..705ec9d68ae9 100644 --- a/deps/openssl/config/archs/VC-WIN64A/asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/VC-WIN64A/asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: " -#define DATE "built on: Wed Jun 17 17:32:08 2026 UTC" +#define DATE "built on: Tue Aug 25 12:56:25 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/VC-WIN64A/asm/include/openssl/opensslv.h b/deps/openssl/config/archs/VC-WIN64A/asm/include/openssl/opensslv.h index 2ffd28f17e80..5baff3e0aff8 100644 --- a/deps/openssl/config/archs/VC-WIN64A/asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/VC-WIN64A/asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/VC-WIN64A/asm/include/openssl/ssl.h b/deps/openssl/config/archs/VC-WIN64A/asm/include/openssl/ssl.h index 0e7eb9dfb947..0614d70ba587 100644 --- a/deps/openssl/config/archs/VC-WIN64A/asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/VC-WIN64A/asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/VC-WIN64A/asm_avx2/configdata.pm b/deps/openssl/config/archs/VC-WIN64A/asm_avx2/configdata.pm index cd968483272e..7d5bd45a75ea 100644 --- a/deps/openssl/config/archs/VC-WIN64A/asm_avx2/configdata.pm +++ b/deps/openssl/config/archs/VC-WIN64A/asm_avx2/configdata.pm @@ -181,7 +181,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -243,7 +243,7 @@ our %config = ( ], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -302,11 +302,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "VC-WIN64A", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "lib", @@ -321,7 +321,7 @@ our %target = ( "LDFLAGS" => "/nologo /debug", "MT" => "mt", "MTFLAGS" => "-nologo", - "RANLIB" => "CODE(0x5d5b7ba1e5b0)", + "RANLIB" => "CODE(0x55f18d21c250)", "RC" => "rc", "_conf_fname_int" => [ "Configurations/00-base-templates.conf", @@ -2306,6 +2306,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2342,6 +2345,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -5000,6 +5006,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -5036,6 +5045,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11411,6 +11423,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11447,6 +11462,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14105,6 +14123,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14141,6 +14162,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16554,6 +16578,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16566,6 +16591,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18683,6 +18709,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18695,6 +18722,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/VC-WIN64A/asm_avx2/crypto/buildinf.h b/deps/openssl/config/archs/VC-WIN64A/asm_avx2/crypto/buildinf.h index 4d7faba72e21..4de5fe8cb9d3 100644 --- a/deps/openssl/config/archs/VC-WIN64A/asm_avx2/crypto/buildinf.h +++ b/deps/openssl/config/archs/VC-WIN64A/asm_avx2/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: " -#define DATE "built on: Wed Jun 17 17:32:21 2026 UTC" +#define DATE "built on: Tue Aug 25 12:56:45 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/VC-WIN64A/asm_avx2/include/openssl/opensslv.h b/deps/openssl/config/archs/VC-WIN64A/asm_avx2/include/openssl/opensslv.h index 2ffd28f17e80..5baff3e0aff8 100644 --- a/deps/openssl/config/archs/VC-WIN64A/asm_avx2/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/VC-WIN64A/asm_avx2/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/VC-WIN64A/asm_avx2/include/openssl/ssl.h b/deps/openssl/config/archs/VC-WIN64A/asm_avx2/include/openssl/ssl.h index 0e7eb9dfb947..0614d70ba587 100644 --- a/deps/openssl/config/archs/VC-WIN64A/asm_avx2/include/openssl/ssl.h +++ b/deps/openssl/config/archs/VC-WIN64A/asm_avx2/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/VC-WIN64A/no-asm/configdata.pm b/deps/openssl/config/archs/VC-WIN64A/no-asm/configdata.pm index 492610f4d3a4..d59c1907066e 100644 --- a/deps/openssl/config/archs/VC-WIN64A/no-asm/configdata.pm +++ b/deps/openssl/config/archs/VC-WIN64A/no-asm/configdata.pm @@ -179,7 +179,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -242,7 +242,7 @@ our %config = ( ], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-asm no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -302,11 +302,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "VC-WIN64A", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "lib", @@ -321,7 +321,7 @@ our %target = ( "LDFLAGS" => "/nologo /debug", "MT" => "mt", "MTFLAGS" => "-nologo", - "RANLIB" => "CODE(0x604cad97f898)", + "RANLIB" => "CODE(0x562b96496f28)", "RC" => "rc", "_conf_fname_int" => [ "Configurations/00-base-templates.conf", @@ -2242,6 +2242,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2278,6 +2281,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4936,6 +4942,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4972,6 +4981,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11285,6 +11297,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11321,6 +11336,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13979,6 +13997,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14015,6 +14036,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16428,6 +16452,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16440,6 +16465,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18554,6 +18580,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18566,6 +18593,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/VC-WIN64A/no-asm/crypto/buildinf.h b/deps/openssl/config/archs/VC-WIN64A/no-asm/crypto/buildinf.h index 181d4009e5ba..501ff4ff3cea 100644 --- a/deps/openssl/config/archs/VC-WIN64A/no-asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/VC-WIN64A/no-asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: " -#define DATE "built on: Wed Jun 17 17:32:34 2026 UTC" +#define DATE "built on: Tue Aug 25 12:57:05 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/VC-WIN64A/no-asm/include/openssl/opensslv.h b/deps/openssl/config/archs/VC-WIN64A/no-asm/include/openssl/opensslv.h index 2ffd28f17e80..5baff3e0aff8 100644 --- a/deps/openssl/config/archs/VC-WIN64A/no-asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/VC-WIN64A/no-asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/VC-WIN64A/no-asm/include/openssl/ssl.h b/deps/openssl/config/archs/VC-WIN64A/no-asm/include/openssl/ssl.h index 0e7eb9dfb947..0614d70ba587 100644 --- a/deps/openssl/config/archs/VC-WIN64A/no-asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/VC-WIN64A/no-asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/aix64-gcc-as/asm/configdata.pm b/deps/openssl/config/archs/aix64-gcc-as/asm/configdata.pm index 68b9777e535f..1813e7209f1e 100644 --- a/deps/openssl/config/archs/aix64-gcc-as/asm/configdata.pm +++ b/deps/openssl/config/archs/aix64-gcc-as/asm/configdata.pm @@ -171,7 +171,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -233,7 +233,7 @@ our %config = ( ], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -292,11 +292,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "aix64-gcc-as", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar -X64", @@ -2238,6 +2238,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2274,6 +2277,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4932,6 +4938,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4968,6 +4977,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11310,6 +11322,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11346,6 +11361,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14004,6 +14022,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14040,6 +14061,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16437,6 +16461,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16449,6 +16474,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18560,6 +18586,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18572,6 +18599,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/aix64-gcc-as/asm/crypto/buildinf.h b/deps/openssl/config/archs/aix64-gcc-as/asm/crypto/buildinf.h index 49891a932261..450ad65f9999 100644 --- a/deps/openssl/config/archs/aix64-gcc-as/asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/aix64-gcc-as/asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: aix64-gcc-as" -#define DATE "built on: Wed Jun 17 17:23:40 2026 UTC" +#define DATE "built on: Tue Aug 25 12:43:47 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/aix64-gcc-as/asm/include/openssl/opensslv.h b/deps/openssl/config/archs/aix64-gcc-as/asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/aix64-gcc-as/asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/aix64-gcc-as/asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/aix64-gcc-as/asm/include/openssl/ssl.h b/deps/openssl/config/archs/aix64-gcc-as/asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/aix64-gcc-as/asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/aix64-gcc-as/asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/aix64-gcc-as/asm_avx2/configdata.pm b/deps/openssl/config/archs/aix64-gcc-as/asm_avx2/configdata.pm index 67f115d1e503..dd38a916ea8a 100644 --- a/deps/openssl/config/archs/aix64-gcc-as/asm_avx2/configdata.pm +++ b/deps/openssl/config/archs/aix64-gcc-as/asm_avx2/configdata.pm @@ -171,7 +171,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -233,7 +233,7 @@ our %config = ( ], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -292,11 +292,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "aix64-gcc-as", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar -X64", @@ -2238,6 +2238,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2274,6 +2277,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4932,6 +4938,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4968,6 +4977,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11310,6 +11322,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11346,6 +11361,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14004,6 +14022,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14040,6 +14061,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16437,6 +16461,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16449,6 +16474,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18560,6 +18586,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18572,6 +18599,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/aix64-gcc-as/asm_avx2/crypto/buildinf.h b/deps/openssl/config/archs/aix64-gcc-as/asm_avx2/crypto/buildinf.h index 2459c161c06b..40dc642f2c0a 100644 --- a/deps/openssl/config/archs/aix64-gcc-as/asm_avx2/crypto/buildinf.h +++ b/deps/openssl/config/archs/aix64-gcc-as/asm_avx2/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: aix64-gcc-as" -#define DATE "built on: Wed Jun 17 17:23:50 2026 UTC" +#define DATE "built on: Tue Aug 25 12:44:02 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/aix64-gcc-as/asm_avx2/include/openssl/opensslv.h b/deps/openssl/config/archs/aix64-gcc-as/asm_avx2/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/aix64-gcc-as/asm_avx2/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/aix64-gcc-as/asm_avx2/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/aix64-gcc-as/asm_avx2/include/openssl/ssl.h b/deps/openssl/config/archs/aix64-gcc-as/asm_avx2/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/aix64-gcc-as/asm_avx2/include/openssl/ssl.h +++ b/deps/openssl/config/archs/aix64-gcc-as/asm_avx2/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/aix64-gcc-as/no-asm/configdata.pm b/deps/openssl/config/archs/aix64-gcc-as/no-asm/configdata.pm index 7515010ba0f6..bf64eea2a7a4 100644 --- a/deps/openssl/config/archs/aix64-gcc-as/no-asm/configdata.pm +++ b/deps/openssl/config/archs/aix64-gcc-as/no-asm/configdata.pm @@ -169,7 +169,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -232,7 +232,7 @@ our %config = ( ], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-asm no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -292,11 +292,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "aix64-gcc-as", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar -X64", @@ -2201,6 +2201,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2237,6 +2240,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4895,6 +4901,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4931,6 +4940,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11233,6 +11245,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11269,6 +11284,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13927,6 +13945,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -13963,6 +13984,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16360,6 +16384,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16372,6 +16397,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18480,6 +18506,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18492,6 +18519,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/aix64-gcc-as/no-asm/crypto/buildinf.h b/deps/openssl/config/archs/aix64-gcc-as/no-asm/crypto/buildinf.h index 1de51d59c916..e709d7858d94 100644 --- a/deps/openssl/config/archs/aix64-gcc-as/no-asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/aix64-gcc-as/no-asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: aix64-gcc-as" -#define DATE "built on: Wed Jun 17 17:24:01 2026 UTC" +#define DATE "built on: Tue Aug 25 12:44:16 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/aix64-gcc-as/no-asm/include/openssl/opensslv.h b/deps/openssl/config/archs/aix64-gcc-as/no-asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/aix64-gcc-as/no-asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/aix64-gcc-as/no-asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/aix64-gcc-as/no-asm/include/openssl/ssl.h b/deps/openssl/config/archs/aix64-gcc-as/no-asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/aix64-gcc-as/no-asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/aix64-gcc-as/no-asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/darwin-i386-cc/asm/configdata.pm b/deps/openssl/config/archs/darwin-i386-cc/asm/configdata.pm index c68598a373e0..8fde2f3d2912 100644 --- a/deps/openssl/config/archs/darwin-i386-cc/asm/configdata.pm +++ b/deps/openssl/config/archs/darwin-i386-cc/asm/configdata.pm @@ -171,7 +171,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -233,7 +233,7 @@ our %config = ( ], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -292,11 +292,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "darwin-i386-cc", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2258,6 +2258,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2294,6 +2297,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4952,6 +4958,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4988,6 +4997,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11303,6 +11315,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11339,6 +11354,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13997,6 +14015,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14033,6 +14054,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16416,6 +16440,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16428,6 +16453,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18531,6 +18557,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18543,6 +18570,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/darwin-i386-cc/asm/crypto/buildinf.h b/deps/openssl/config/archs/darwin-i386-cc/asm/crypto/buildinf.h index 3015418c1d9b..488900f6e0de 100644 --- a/deps/openssl/config/archs/darwin-i386-cc/asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/darwin-i386-cc/asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: darwin-i386-cc" -#define DATE "built on: Wed Jun 17 17:26:03 2026 UTC" +#define DATE "built on: Tue Aug 25 12:46:57 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/darwin-i386-cc/asm/include/openssl/opensslv.h b/deps/openssl/config/archs/darwin-i386-cc/asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/darwin-i386-cc/asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/darwin-i386-cc/asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/darwin-i386-cc/asm/include/openssl/ssl.h b/deps/openssl/config/archs/darwin-i386-cc/asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/darwin-i386-cc/asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/darwin-i386-cc/asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/darwin-i386-cc/asm_avx2/configdata.pm b/deps/openssl/config/archs/darwin-i386-cc/asm_avx2/configdata.pm index 89949092c2ad..0541cb93d1be 100644 --- a/deps/openssl/config/archs/darwin-i386-cc/asm_avx2/configdata.pm +++ b/deps/openssl/config/archs/darwin-i386-cc/asm_avx2/configdata.pm @@ -171,7 +171,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -233,7 +233,7 @@ our %config = ( ], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -292,11 +292,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "darwin-i386-cc", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2258,6 +2258,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2294,6 +2297,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4952,6 +4958,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4988,6 +4997,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11303,6 +11315,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11339,6 +11354,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13997,6 +14015,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14033,6 +14054,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16416,6 +16440,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16428,6 +16453,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18531,6 +18557,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18543,6 +18570,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/darwin-i386-cc/asm_avx2/crypto/buildinf.h b/deps/openssl/config/archs/darwin-i386-cc/asm_avx2/crypto/buildinf.h index 674284362932..cfa0ce918396 100644 --- a/deps/openssl/config/archs/darwin-i386-cc/asm_avx2/crypto/buildinf.h +++ b/deps/openssl/config/archs/darwin-i386-cc/asm_avx2/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: darwin-i386-cc" -#define DATE "built on: Wed Jun 17 17:26:13 2026 UTC" +#define DATE "built on: Tue Aug 25 12:47:11 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/darwin-i386-cc/asm_avx2/include/openssl/opensslv.h b/deps/openssl/config/archs/darwin-i386-cc/asm_avx2/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/darwin-i386-cc/asm_avx2/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/darwin-i386-cc/asm_avx2/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/darwin-i386-cc/asm_avx2/include/openssl/ssl.h b/deps/openssl/config/archs/darwin-i386-cc/asm_avx2/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/darwin-i386-cc/asm_avx2/include/openssl/ssl.h +++ b/deps/openssl/config/archs/darwin-i386-cc/asm_avx2/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/darwin-i386-cc/no-asm/configdata.pm b/deps/openssl/config/archs/darwin-i386-cc/no-asm/configdata.pm index d367beb1611f..acc9d54be8c3 100644 --- a/deps/openssl/config/archs/darwin-i386-cc/no-asm/configdata.pm +++ b/deps/openssl/config/archs/darwin-i386-cc/no-asm/configdata.pm @@ -169,7 +169,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -232,7 +232,7 @@ our %config = ( ], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-asm no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -292,11 +292,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "darwin-i386-cc", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2200,6 +2200,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2236,6 +2239,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4894,6 +4900,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4930,6 +4939,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11223,6 +11235,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11259,6 +11274,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13917,6 +13935,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -13953,6 +13974,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16336,6 +16360,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16348,6 +16373,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18448,6 +18474,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18460,6 +18487,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/darwin-i386-cc/no-asm/crypto/buildinf.h b/deps/openssl/config/archs/darwin-i386-cc/no-asm/crypto/buildinf.h index 7fe0a213ae12..6971a07efd48 100644 --- a/deps/openssl/config/archs/darwin-i386-cc/no-asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/darwin-i386-cc/no-asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: darwin-i386-cc" -#define DATE "built on: Wed Jun 17 17:26:23 2026 UTC" +#define DATE "built on: Tue Aug 25 12:47:25 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/darwin-i386-cc/no-asm/include/openssl/opensslv.h b/deps/openssl/config/archs/darwin-i386-cc/no-asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/darwin-i386-cc/no-asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/darwin-i386-cc/no-asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/darwin-i386-cc/no-asm/include/openssl/ssl.h b/deps/openssl/config/archs/darwin-i386-cc/no-asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/darwin-i386-cc/no-asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/darwin-i386-cc/no-asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/darwin64-arm64-cc/asm/configdata.pm b/deps/openssl/config/archs/darwin64-arm64-cc/asm/configdata.pm index 18e72b570827..c7b46331864a 100644 --- a/deps/openssl/config/archs/darwin64-arm64-cc/asm/configdata.pm +++ b/deps/openssl/config/archs/darwin64-arm64-cc/asm/configdata.pm @@ -171,7 +171,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -233,7 +233,7 @@ our %config = ( ], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -292,11 +292,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "darwin64-arm64-cc", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2248,6 +2248,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2284,6 +2287,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4942,6 +4948,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4978,6 +4987,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11310,6 +11322,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11346,6 +11361,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14004,6 +14022,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14040,6 +14061,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16423,6 +16447,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16435,6 +16460,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18640,6 +18666,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18652,6 +18679,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/darwin64-arm64-cc/asm/crypto/buildinf.h b/deps/openssl/config/archs/darwin64-arm64-cc/asm/crypto/buildinf.h index d7ac04051dbb..e0599efb87c1 100644 --- a/deps/openssl/config/archs/darwin64-arm64-cc/asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/darwin64-arm64-cc/asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: darwin64-arm64-cc" -#define DATE "built on: Wed Jun 17 17:26:32 2026 UTC" +#define DATE "built on: Tue Aug 25 12:47:38 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/darwin64-arm64-cc/asm/include/openssl/opensslv.h b/deps/openssl/config/archs/darwin64-arm64-cc/asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/darwin64-arm64-cc/asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/darwin64-arm64-cc/asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/darwin64-arm64-cc/asm/include/openssl/ssl.h b/deps/openssl/config/archs/darwin64-arm64-cc/asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/darwin64-arm64-cc/asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/darwin64-arm64-cc/asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/darwin64-arm64-cc/asm_avx2/configdata.pm b/deps/openssl/config/archs/darwin64-arm64-cc/asm_avx2/configdata.pm index b1b88d9f599f..b730f8b849ec 100644 --- a/deps/openssl/config/archs/darwin64-arm64-cc/asm_avx2/configdata.pm +++ b/deps/openssl/config/archs/darwin64-arm64-cc/asm_avx2/configdata.pm @@ -171,7 +171,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -233,7 +233,7 @@ our %config = ( ], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -292,11 +292,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "darwin64-arm64-cc", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2248,6 +2248,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2284,6 +2287,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4942,6 +4948,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4978,6 +4987,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11310,6 +11322,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11346,6 +11361,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14004,6 +14022,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14040,6 +14061,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16423,6 +16447,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16435,6 +16460,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18640,6 +18666,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18652,6 +18679,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/darwin64-arm64-cc/asm_avx2/crypto/buildinf.h b/deps/openssl/config/archs/darwin64-arm64-cc/asm_avx2/crypto/buildinf.h index b7112ce03232..bf9b895cd76d 100644 --- a/deps/openssl/config/archs/darwin64-arm64-cc/asm_avx2/crypto/buildinf.h +++ b/deps/openssl/config/archs/darwin64-arm64-cc/asm_avx2/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: darwin64-arm64-cc" -#define DATE "built on: Wed Jun 17 17:26:43 2026 UTC" +#define DATE "built on: Tue Aug 25 12:47:53 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/darwin64-arm64-cc/asm_avx2/include/openssl/opensslv.h b/deps/openssl/config/archs/darwin64-arm64-cc/asm_avx2/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/darwin64-arm64-cc/asm_avx2/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/darwin64-arm64-cc/asm_avx2/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/darwin64-arm64-cc/asm_avx2/include/openssl/ssl.h b/deps/openssl/config/archs/darwin64-arm64-cc/asm_avx2/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/darwin64-arm64-cc/asm_avx2/include/openssl/ssl.h +++ b/deps/openssl/config/archs/darwin64-arm64-cc/asm_avx2/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/darwin64-arm64-cc/no-asm/configdata.pm b/deps/openssl/config/archs/darwin64-arm64-cc/no-asm/configdata.pm index ec97bafcbf5a..9711ee2febde 100644 --- a/deps/openssl/config/archs/darwin64-arm64-cc/no-asm/configdata.pm +++ b/deps/openssl/config/archs/darwin64-arm64-cc/no-asm/configdata.pm @@ -169,7 +169,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -232,7 +232,7 @@ our %config = ( ], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-asm no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -292,11 +292,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "darwin64-arm64-cc", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2200,6 +2200,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2236,6 +2239,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4894,6 +4900,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4930,6 +4939,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11223,6 +11235,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11259,6 +11274,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13917,6 +13935,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -13953,6 +13974,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16336,6 +16360,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16348,6 +16373,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18448,6 +18474,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18460,6 +18487,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/darwin64-arm64-cc/no-asm/crypto/buildinf.h b/deps/openssl/config/archs/darwin64-arm64-cc/no-asm/crypto/buildinf.h index 047c02b588f6..54a77bc2e6d1 100644 --- a/deps/openssl/config/archs/darwin64-arm64-cc/no-asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/darwin64-arm64-cc/no-asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: darwin64-arm64-cc" -#define DATE "built on: Wed Jun 17 17:26:53 2026 UTC" +#define DATE "built on: Tue Aug 25 12:48:08 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/darwin64-arm64-cc/no-asm/include/openssl/opensslv.h b/deps/openssl/config/archs/darwin64-arm64-cc/no-asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/darwin64-arm64-cc/no-asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/darwin64-arm64-cc/no-asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/darwin64-arm64-cc/no-asm/include/openssl/ssl.h b/deps/openssl/config/archs/darwin64-arm64-cc/no-asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/darwin64-arm64-cc/no-asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/darwin64-arm64-cc/no-asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/darwin64-x86_64-cc/asm/configdata.pm b/deps/openssl/config/archs/darwin64-x86_64-cc/asm/configdata.pm index 6d2119f88862..78fbe9eec829 100644 --- a/deps/openssl/config/archs/darwin64-x86_64-cc/asm/configdata.pm +++ b/deps/openssl/config/archs/darwin64-x86_64-cc/asm/configdata.pm @@ -171,7 +171,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -233,7 +233,7 @@ our %config = ( ], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -292,11 +292,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "darwin64-x86_64-cc", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2264,6 +2264,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2300,6 +2303,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4958,6 +4964,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4994,6 +5003,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11359,6 +11371,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11395,6 +11410,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14053,6 +14071,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14089,6 +14110,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16472,6 +16496,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16484,6 +16509,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18587,6 +18613,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18599,6 +18626,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/darwin64-x86_64-cc/asm/crypto/buildinf.h b/deps/openssl/config/archs/darwin64-x86_64-cc/asm/crypto/buildinf.h index 88213c33f1ee..ad100b5e3b1e 100644 --- a/deps/openssl/config/archs/darwin64-x86_64-cc/asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/darwin64-x86_64-cc/asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: darwin64-x86_64-cc" -#define DATE "built on: Wed Jun 17 17:25:26 2026 UTC" +#define DATE "built on: Tue Aug 25 12:46:05 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/darwin64-x86_64-cc/asm/include/openssl/opensslv.h b/deps/openssl/config/archs/darwin64-x86_64-cc/asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/darwin64-x86_64-cc/asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/darwin64-x86_64-cc/asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/darwin64-x86_64-cc/asm/include/openssl/ssl.h b/deps/openssl/config/archs/darwin64-x86_64-cc/asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/darwin64-x86_64-cc/asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/darwin64-x86_64-cc/asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/darwin64-x86_64-cc/asm_avx2/configdata.pm b/deps/openssl/config/archs/darwin64-x86_64-cc/asm_avx2/configdata.pm index ad77cb194c39..22291b6d0589 100644 --- a/deps/openssl/config/archs/darwin64-x86_64-cc/asm_avx2/configdata.pm +++ b/deps/openssl/config/archs/darwin64-x86_64-cc/asm_avx2/configdata.pm @@ -171,7 +171,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -233,7 +233,7 @@ our %config = ( ], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -292,11 +292,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "darwin64-x86_64-cc", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2264,6 +2264,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2300,6 +2303,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4958,6 +4964,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4994,6 +5003,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11359,6 +11371,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11395,6 +11410,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14053,6 +14071,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14089,6 +14110,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16472,6 +16496,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16484,6 +16509,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18587,6 +18613,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18599,6 +18626,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/darwin64-x86_64-cc/asm_avx2/crypto/buildinf.h b/deps/openssl/config/archs/darwin64-x86_64-cc/asm_avx2/crypto/buildinf.h index d90eb97468f8..877b8f3a9121 100644 --- a/deps/openssl/config/archs/darwin64-x86_64-cc/asm_avx2/crypto/buildinf.h +++ b/deps/openssl/config/archs/darwin64-x86_64-cc/asm_avx2/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: darwin64-x86_64-cc" -#define DATE "built on: Wed Jun 17 17:25:41 2026 UTC" +#define DATE "built on: Tue Aug 25 12:46:26 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/darwin64-x86_64-cc/asm_avx2/include/openssl/opensslv.h b/deps/openssl/config/archs/darwin64-x86_64-cc/asm_avx2/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/darwin64-x86_64-cc/asm_avx2/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/darwin64-x86_64-cc/asm_avx2/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/darwin64-x86_64-cc/asm_avx2/include/openssl/ssl.h b/deps/openssl/config/archs/darwin64-x86_64-cc/asm_avx2/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/darwin64-x86_64-cc/asm_avx2/include/openssl/ssl.h +++ b/deps/openssl/config/archs/darwin64-x86_64-cc/asm_avx2/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/darwin64-x86_64-cc/no-asm/configdata.pm b/deps/openssl/config/archs/darwin64-x86_64-cc/no-asm/configdata.pm index dda82537bfc0..72197afbd741 100644 --- a/deps/openssl/config/archs/darwin64-x86_64-cc/no-asm/configdata.pm +++ b/deps/openssl/config/archs/darwin64-x86_64-cc/no-asm/configdata.pm @@ -169,7 +169,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -232,7 +232,7 @@ our %config = ( ], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-asm no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -292,11 +292,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "darwin64-x86_64-cc", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2200,6 +2200,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2236,6 +2239,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4894,6 +4900,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4930,6 +4939,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11223,6 +11235,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11259,6 +11274,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13917,6 +13935,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -13953,6 +13974,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16336,6 +16360,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16348,6 +16373,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18448,6 +18474,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18460,6 +18487,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/darwin64-x86_64-cc/no-asm/crypto/buildinf.h b/deps/openssl/config/archs/darwin64-x86_64-cc/no-asm/crypto/buildinf.h index 6a5fce0c7151..3e9a7c66a960 100644 --- a/deps/openssl/config/archs/darwin64-x86_64-cc/no-asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/darwin64-x86_64-cc/no-asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: darwin64-x86_64-cc" -#define DATE "built on: Wed Jun 17 17:25:54 2026 UTC" +#define DATE "built on: Tue Aug 25 12:46:44 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/darwin64-x86_64-cc/no-asm/include/openssl/opensslv.h b/deps/openssl/config/archs/darwin64-x86_64-cc/no-asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/darwin64-x86_64-cc/no-asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/darwin64-x86_64-cc/no-asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/darwin64-x86_64-cc/no-asm/include/openssl/ssl.h b/deps/openssl/config/archs/darwin64-x86_64-cc/no-asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/darwin64-x86_64-cc/no-asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/darwin64-x86_64-cc/no-asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux-aarch64/asm/configdata.pm b/deps/openssl/config/archs/linux-aarch64/asm/configdata.pm index 53580a00c598..19517b687bd0 100644 --- a/deps/openssl/config/archs/linux-aarch64/asm/configdata.pm +++ b/deps/openssl/config/archs/linux-aarch64/asm/configdata.pm @@ -174,7 +174,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -234,7 +234,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux-aarch64", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2254,6 +2254,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2290,6 +2293,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4948,6 +4954,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4984,6 +4993,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11325,6 +11337,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11361,6 +11376,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14019,6 +14037,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14055,6 +14076,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16452,6 +16476,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16464,6 +16489,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18677,6 +18703,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18689,6 +18716,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux-aarch64/asm/crypto/buildinf.h b/deps/openssl/config/archs/linux-aarch64/asm/crypto/buildinf.h index 2c0d5e189850..76d4bb155478 100644 --- a/deps/openssl/config/archs/linux-aarch64/asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux-aarch64/asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux-aarch64" -#define DATE "built on: Wed Jun 17 17:27:02 2026 UTC" +#define DATE "built on: Tue Aug 25 12:48:21 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux-aarch64/asm/include/openssl/opensslv.h b/deps/openssl/config/archs/linux-aarch64/asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux-aarch64/asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux-aarch64/asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux-aarch64/asm/include/openssl/ssl.h b/deps/openssl/config/archs/linux-aarch64/asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux-aarch64/asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux-aarch64/asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux-aarch64/asm_avx2/configdata.pm b/deps/openssl/config/archs/linux-aarch64/asm_avx2/configdata.pm index 35e13b93a44a..0c9c2f5403d8 100644 --- a/deps/openssl/config/archs/linux-aarch64/asm_avx2/configdata.pm +++ b/deps/openssl/config/archs/linux-aarch64/asm_avx2/configdata.pm @@ -174,7 +174,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -234,7 +234,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux-aarch64", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2254,6 +2254,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2290,6 +2293,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4948,6 +4954,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4984,6 +4993,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11325,6 +11337,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11361,6 +11376,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14019,6 +14037,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14055,6 +14076,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16452,6 +16476,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16464,6 +16489,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18677,6 +18703,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18689,6 +18716,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux-aarch64/asm_avx2/crypto/buildinf.h b/deps/openssl/config/archs/linux-aarch64/asm_avx2/crypto/buildinf.h index 8ce8f7ee252d..edbc7ece42d0 100644 --- a/deps/openssl/config/archs/linux-aarch64/asm_avx2/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux-aarch64/asm_avx2/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux-aarch64" -#define DATE "built on: Wed Jun 17 17:27:13 2026 UTC" +#define DATE "built on: Tue Aug 25 12:48:36 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux-aarch64/asm_avx2/include/openssl/opensslv.h b/deps/openssl/config/archs/linux-aarch64/asm_avx2/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux-aarch64/asm_avx2/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux-aarch64/asm_avx2/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux-aarch64/asm_avx2/include/openssl/ssl.h b/deps/openssl/config/archs/linux-aarch64/asm_avx2/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux-aarch64/asm_avx2/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux-aarch64/asm_avx2/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux-aarch64/no-asm/configdata.pm b/deps/openssl/config/archs/linux-aarch64/no-asm/configdata.pm index 5bcdf446bc82..d133979cc3cc 100644 --- a/deps/openssl/config/archs/linux-aarch64/no-asm/configdata.pm +++ b/deps/openssl/config/archs/linux-aarch64/no-asm/configdata.pm @@ -172,7 +172,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -233,7 +233,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-asm no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux-aarch64", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2206,6 +2206,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2242,6 +2245,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4900,6 +4906,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4936,6 +4945,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11238,6 +11250,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11274,6 +11289,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13932,6 +13950,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -13968,6 +13989,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16365,6 +16389,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16377,6 +16402,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18485,6 +18511,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18497,6 +18524,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux-aarch64/no-asm/crypto/buildinf.h b/deps/openssl/config/archs/linux-aarch64/no-asm/crypto/buildinf.h index 9cc4269f8e23..a5b1c96dccdb 100644 --- a/deps/openssl/config/archs/linux-aarch64/no-asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux-aarch64/no-asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux-aarch64" -#define DATE "built on: Wed Jun 17 17:27:23 2026 UTC" +#define DATE "built on: Tue Aug 25 12:48:50 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux-aarch64/no-asm/include/openssl/opensslv.h b/deps/openssl/config/archs/linux-aarch64/no-asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux-aarch64/no-asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux-aarch64/no-asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux-aarch64/no-asm/include/openssl/ssl.h b/deps/openssl/config/archs/linux-aarch64/no-asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux-aarch64/no-asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux-aarch64/no-asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux-armv4/asm/configdata.pm b/deps/openssl/config/archs/linux-armv4/asm/configdata.pm index 1039d43c9ffd..3534d799e04e 100644 --- a/deps/openssl/config/archs/linux-armv4/asm/configdata.pm +++ b/deps/openssl/config/archs/linux-armv4/asm/configdata.pm @@ -174,7 +174,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -234,7 +234,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux-armv4", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2246,6 +2246,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2282,6 +2285,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4940,6 +4946,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4976,6 +4985,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11303,6 +11315,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11339,6 +11354,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13997,6 +14015,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14033,6 +14054,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16430,6 +16454,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16442,6 +16467,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18637,6 +18663,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18649,6 +18676,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux-armv4/asm/crypto/buildinf.h b/deps/openssl/config/archs/linux-armv4/asm/crypto/buildinf.h index 5b6eb7fc345d..0088f27d20aa 100644 --- a/deps/openssl/config/archs/linux-armv4/asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux-armv4/asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux-armv4" -#define DATE "built on: Wed Jun 17 17:27:32 2026 UTC" +#define DATE "built on: Tue Aug 25 12:49:04 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux-armv4/asm/include/openssl/opensslv.h b/deps/openssl/config/archs/linux-armv4/asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux-armv4/asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux-armv4/asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux-armv4/asm/include/openssl/ssl.h b/deps/openssl/config/archs/linux-armv4/asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux-armv4/asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux-armv4/asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux-armv4/asm_avx2/configdata.pm b/deps/openssl/config/archs/linux-armv4/asm_avx2/configdata.pm index b894c96a36ab..4382ec4ff6f8 100644 --- a/deps/openssl/config/archs/linux-armv4/asm_avx2/configdata.pm +++ b/deps/openssl/config/archs/linux-armv4/asm_avx2/configdata.pm @@ -174,7 +174,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -234,7 +234,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux-armv4", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2246,6 +2246,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2282,6 +2285,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4940,6 +4946,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4976,6 +4985,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11303,6 +11315,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11339,6 +11354,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13997,6 +14015,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14033,6 +14054,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16430,6 +16454,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16442,6 +16467,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18637,6 +18663,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18649,6 +18676,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux-armv4/asm_avx2/crypto/buildinf.h b/deps/openssl/config/archs/linux-armv4/asm_avx2/crypto/buildinf.h index bfca03890a51..694d5dd4bce1 100644 --- a/deps/openssl/config/archs/linux-armv4/asm_avx2/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux-armv4/asm_avx2/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux-armv4" -#define DATE "built on: Wed Jun 17 17:27:42 2026 UTC" +#define DATE "built on: Tue Aug 25 12:49:18 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux-armv4/asm_avx2/include/openssl/opensslv.h b/deps/openssl/config/archs/linux-armv4/asm_avx2/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux-armv4/asm_avx2/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux-armv4/asm_avx2/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux-armv4/asm_avx2/include/openssl/ssl.h b/deps/openssl/config/archs/linux-armv4/asm_avx2/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux-armv4/asm_avx2/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux-armv4/asm_avx2/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux-armv4/no-asm/configdata.pm b/deps/openssl/config/archs/linux-armv4/no-asm/configdata.pm index 965dcc5e2322..48297dc7b2ba 100644 --- a/deps/openssl/config/archs/linux-armv4/no-asm/configdata.pm +++ b/deps/openssl/config/archs/linux-armv4/no-asm/configdata.pm @@ -172,7 +172,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -233,7 +233,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-asm no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux-armv4", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2206,6 +2206,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2242,6 +2245,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4900,6 +4906,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4936,6 +4945,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11238,6 +11250,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11274,6 +11289,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13932,6 +13950,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -13968,6 +13989,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16365,6 +16389,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16377,6 +16402,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18485,6 +18511,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18497,6 +18524,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux-armv4/no-asm/crypto/buildinf.h b/deps/openssl/config/archs/linux-armv4/no-asm/crypto/buildinf.h index 87edc618bf22..70714ad7ccc9 100644 --- a/deps/openssl/config/archs/linux-armv4/no-asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux-armv4/no-asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux-armv4" -#define DATE "built on: Wed Jun 17 17:27:52 2026 UTC" +#define DATE "built on: Tue Aug 25 12:49:32 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux-armv4/no-asm/include/openssl/opensslv.h b/deps/openssl/config/archs/linux-armv4/no-asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux-armv4/no-asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux-armv4/no-asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux-armv4/no-asm/include/openssl/ssl.h b/deps/openssl/config/archs/linux-armv4/no-asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux-armv4/no-asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux-armv4/no-asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux-elf/asm/configdata.pm b/deps/openssl/config/archs/linux-elf/asm/configdata.pm index a0dc413841aa..bbf0dd64cf3a 100644 --- a/deps/openssl/config/archs/linux-elf/asm/configdata.pm +++ b/deps/openssl/config/archs/linux-elf/asm/configdata.pm @@ -174,7 +174,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -234,7 +234,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux-elf", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2263,6 +2263,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2299,6 +2302,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4957,6 +4963,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4993,6 +5002,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11317,6 +11329,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11353,6 +11368,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14011,6 +14029,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14047,6 +14068,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16444,6 +16468,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16456,6 +16481,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18567,6 +18593,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18579,6 +18606,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux-elf/asm/crypto/buildinf.h b/deps/openssl/config/archs/linux-elf/asm/crypto/buildinf.h index b36a4c6ed908..3060d629350a 100644 --- a/deps/openssl/config/archs/linux-elf/asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux-elf/asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux-elf" -#define DATE "built on: Wed Jun 17 17:28:02 2026 UTC" +#define DATE "built on: Tue Aug 25 12:49:45 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux-elf/asm/include/openssl/opensslv.h b/deps/openssl/config/archs/linux-elf/asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux-elf/asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux-elf/asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux-elf/asm/include/openssl/ssl.h b/deps/openssl/config/archs/linux-elf/asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux-elf/asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux-elf/asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux-elf/asm_avx2/configdata.pm b/deps/openssl/config/archs/linux-elf/asm_avx2/configdata.pm index a57f3f37e757..5acf92d026dc 100644 --- a/deps/openssl/config/archs/linux-elf/asm_avx2/configdata.pm +++ b/deps/openssl/config/archs/linux-elf/asm_avx2/configdata.pm @@ -174,7 +174,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -234,7 +234,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux-elf", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2263,6 +2263,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2299,6 +2302,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4957,6 +4963,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4993,6 +5002,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11317,6 +11329,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11353,6 +11368,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14011,6 +14029,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14047,6 +14068,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16444,6 +16468,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16456,6 +16481,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18567,6 +18593,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18579,6 +18606,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux-elf/asm_avx2/crypto/buildinf.h b/deps/openssl/config/archs/linux-elf/asm_avx2/crypto/buildinf.h index 0fbc959d01b0..e86d4f39b307 100644 --- a/deps/openssl/config/archs/linux-elf/asm_avx2/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux-elf/asm_avx2/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux-elf" -#define DATE "built on: Wed Jun 17 17:28:12 2026 UTC" +#define DATE "built on: Tue Aug 25 12:50:00 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux-elf/asm_avx2/include/openssl/opensslv.h b/deps/openssl/config/archs/linux-elf/asm_avx2/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux-elf/asm_avx2/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux-elf/asm_avx2/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux-elf/asm_avx2/include/openssl/ssl.h b/deps/openssl/config/archs/linux-elf/asm_avx2/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux-elf/asm_avx2/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux-elf/asm_avx2/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux-elf/no-asm/configdata.pm b/deps/openssl/config/archs/linux-elf/no-asm/configdata.pm index 249f67471a85..de38e67b0756 100644 --- a/deps/openssl/config/archs/linux-elf/no-asm/configdata.pm +++ b/deps/openssl/config/archs/linux-elf/no-asm/configdata.pm @@ -172,7 +172,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -233,7 +233,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-asm no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux-elf", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2205,6 +2205,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2241,6 +2244,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4899,6 +4905,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4935,6 +4944,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11237,6 +11249,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11273,6 +11288,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13931,6 +13949,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -13967,6 +13988,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16364,6 +16388,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16376,6 +16401,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18484,6 +18510,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18496,6 +18523,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux-elf/no-asm/crypto/buildinf.h b/deps/openssl/config/archs/linux-elf/no-asm/crypto/buildinf.h index 1bf2e2f40ee5..f47815f86eb1 100644 --- a/deps/openssl/config/archs/linux-elf/no-asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux-elf/no-asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux-elf" -#define DATE "built on: Wed Jun 17 17:28:23 2026 UTC" +#define DATE "built on: Tue Aug 25 12:50:14 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux-elf/no-asm/include/openssl/opensslv.h b/deps/openssl/config/archs/linux-elf/no-asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux-elf/no-asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux-elf/no-asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux-elf/no-asm/include/openssl/ssl.h b/deps/openssl/config/archs/linux-elf/no-asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux-elf/no-asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux-elf/no-asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux-ppc64le/asm/configdata.pm b/deps/openssl/config/archs/linux-ppc64le/asm/configdata.pm index 2bf558c9f1aa..863432756e7c 100644 --- a/deps/openssl/config/archs/linux-ppc64le/asm/configdata.pm +++ b/deps/openssl/config/archs/linux-ppc64le/asm/configdata.pm @@ -174,7 +174,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -234,7 +234,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux-ppc64le", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2243,6 +2243,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2279,6 +2282,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4937,6 +4943,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4973,6 +4982,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11318,6 +11330,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11354,6 +11369,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14012,6 +14030,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14048,6 +14069,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16445,6 +16469,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16457,6 +16482,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18568,6 +18594,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18580,6 +18607,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux-ppc64le/asm/crypto/buildinf.h b/deps/openssl/config/archs/linux-ppc64le/asm/crypto/buildinf.h index ca635890a4e8..ad73a66a551b 100644 --- a/deps/openssl/config/archs/linux-ppc64le/asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux-ppc64le/asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux-ppc64le" -#define DATE "built on: Wed Jun 17 17:29:08 2026 UTC" +#define DATE "built on: Tue Aug 25 12:51:20 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux-ppc64le/asm/include/openssl/opensslv.h b/deps/openssl/config/archs/linux-ppc64le/asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux-ppc64le/asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux-ppc64le/asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux-ppc64le/asm/include/openssl/ssl.h b/deps/openssl/config/archs/linux-ppc64le/asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux-ppc64le/asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux-ppc64le/asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux-ppc64le/asm_avx2/configdata.pm b/deps/openssl/config/archs/linux-ppc64le/asm_avx2/configdata.pm index 026b0728c464..e541e8d3eb5d 100644 --- a/deps/openssl/config/archs/linux-ppc64le/asm_avx2/configdata.pm +++ b/deps/openssl/config/archs/linux-ppc64le/asm_avx2/configdata.pm @@ -174,7 +174,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -234,7 +234,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux-ppc64le", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2243,6 +2243,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2279,6 +2282,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4937,6 +4943,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4973,6 +4982,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11318,6 +11330,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11354,6 +11369,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14012,6 +14030,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14048,6 +14069,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16445,6 +16469,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16457,6 +16482,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18568,6 +18594,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18580,6 +18607,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux-ppc64le/asm_avx2/crypto/buildinf.h b/deps/openssl/config/archs/linux-ppc64le/asm_avx2/crypto/buildinf.h index d9eab19ca46c..78b4fa43f2da 100644 --- a/deps/openssl/config/archs/linux-ppc64le/asm_avx2/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux-ppc64le/asm_avx2/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux-ppc64le" -#define DATE "built on: Wed Jun 17 17:29:18 2026 UTC" +#define DATE "built on: Tue Aug 25 12:51:35 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux-ppc64le/asm_avx2/include/openssl/opensslv.h b/deps/openssl/config/archs/linux-ppc64le/asm_avx2/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux-ppc64le/asm_avx2/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux-ppc64le/asm_avx2/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux-ppc64le/asm_avx2/include/openssl/ssl.h b/deps/openssl/config/archs/linux-ppc64le/asm_avx2/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux-ppc64le/asm_avx2/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux-ppc64le/asm_avx2/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux-ppc64le/no-asm/configdata.pm b/deps/openssl/config/archs/linux-ppc64le/no-asm/configdata.pm index cf9b991eb823..5a93fb38646e 100644 --- a/deps/openssl/config/archs/linux-ppc64le/no-asm/configdata.pm +++ b/deps/openssl/config/archs/linux-ppc64le/no-asm/configdata.pm @@ -172,7 +172,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -233,7 +233,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-asm no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux-ppc64le", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2206,6 +2206,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2242,6 +2245,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4900,6 +4906,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4936,6 +4945,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11238,6 +11250,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11274,6 +11289,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13932,6 +13950,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -13968,6 +13989,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16365,6 +16389,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16377,6 +16402,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18485,6 +18511,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18497,6 +18524,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux-ppc64le/no-asm/crypto/buildinf.h b/deps/openssl/config/archs/linux-ppc64le/no-asm/crypto/buildinf.h index f05cfd182212..7ac124b79570 100644 --- a/deps/openssl/config/archs/linux-ppc64le/no-asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux-ppc64le/no-asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux-ppc64le" -#define DATE "built on: Wed Jun 17 17:29:28 2026 UTC" +#define DATE "built on: Tue Aug 25 12:51:49 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux-ppc64le/no-asm/include/openssl/opensslv.h b/deps/openssl/config/archs/linux-ppc64le/no-asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux-ppc64le/no-asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux-ppc64le/no-asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux-ppc64le/no-asm/include/openssl/ssl.h b/deps/openssl/config/archs/linux-ppc64le/no-asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux-ppc64le/no-asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux-ppc64le/no-asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux-x86_64/asm/configdata.pm b/deps/openssl/config/archs/linux-x86_64/asm/configdata.pm index 62de96113048..f1817b2e9fdf 100644 --- a/deps/openssl/config/archs/linux-x86_64/asm/configdata.pm +++ b/deps/openssl/config/archs/linux-x86_64/asm/configdata.pm @@ -174,7 +174,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -234,7 +234,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux-x86_64", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2271,6 +2271,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2307,6 +2310,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4965,6 +4971,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -5001,6 +5010,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11375,6 +11387,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11411,6 +11426,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14069,6 +14087,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14105,6 +14126,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16502,6 +16526,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16514,6 +16539,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18625,6 +18651,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18637,6 +18664,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux-x86_64/asm/crypto/buildinf.h b/deps/openssl/config/archs/linux-x86_64/asm/crypto/buildinf.h index 1f31e3e4f1b3..c2e696451484 100644 --- a/deps/openssl/config/archs/linux-x86_64/asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux-x86_64/asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux-x86_64" -#define DATE "built on: Wed Jun 17 17:28:32 2026 UTC" +#define DATE "built on: Tue Aug 25 12:50:28 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux-x86_64/asm/include/openssl/opensslv.h b/deps/openssl/config/archs/linux-x86_64/asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux-x86_64/asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux-x86_64/asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux-x86_64/asm/include/openssl/ssl.h b/deps/openssl/config/archs/linux-x86_64/asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux-x86_64/asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux-x86_64/asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux-x86_64/asm_avx2/configdata.pm b/deps/openssl/config/archs/linux-x86_64/asm_avx2/configdata.pm index a52b4ec774f2..4b2823833816 100644 --- a/deps/openssl/config/archs/linux-x86_64/asm_avx2/configdata.pm +++ b/deps/openssl/config/archs/linux-x86_64/asm_avx2/configdata.pm @@ -174,7 +174,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -234,7 +234,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux-x86_64", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2271,6 +2271,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2307,6 +2310,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4965,6 +4971,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -5001,6 +5010,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11375,6 +11387,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11411,6 +11426,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14069,6 +14087,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14105,6 +14126,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16502,6 +16526,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16514,6 +16539,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18625,6 +18651,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18637,6 +18664,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux-x86_64/asm_avx2/crypto/buildinf.h b/deps/openssl/config/archs/linux-x86_64/asm_avx2/crypto/buildinf.h index 182f8f215900..73438ec9c159 100644 --- a/deps/openssl/config/archs/linux-x86_64/asm_avx2/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux-x86_64/asm_avx2/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux-x86_64" -#define DATE "built on: Wed Jun 17 17:28:47 2026 UTC" +#define DATE "built on: Tue Aug 25 12:50:50 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux-x86_64/asm_avx2/include/openssl/opensslv.h b/deps/openssl/config/archs/linux-x86_64/asm_avx2/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux-x86_64/asm_avx2/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux-x86_64/asm_avx2/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux-x86_64/asm_avx2/include/openssl/ssl.h b/deps/openssl/config/archs/linux-x86_64/asm_avx2/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux-x86_64/asm_avx2/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux-x86_64/asm_avx2/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux-x86_64/no-asm/configdata.pm b/deps/openssl/config/archs/linux-x86_64/no-asm/configdata.pm index b06017d24af8..0e809e3b15ca 100644 --- a/deps/openssl/config/archs/linux-x86_64/no-asm/configdata.pm +++ b/deps/openssl/config/archs/linux-x86_64/no-asm/configdata.pm @@ -172,7 +172,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -233,7 +233,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-asm no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux-x86_64", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2207,6 +2207,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2243,6 +2246,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4901,6 +4907,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4937,6 +4946,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11239,6 +11251,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11275,6 +11290,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13933,6 +13951,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -13969,6 +13990,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16366,6 +16390,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16378,6 +16403,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18486,6 +18512,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18498,6 +18525,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux-x86_64/no-asm/crypto/buildinf.h b/deps/openssl/config/archs/linux-x86_64/no-asm/crypto/buildinf.h index 484fde68a038..808eaf319cc3 100644 --- a/deps/openssl/config/archs/linux-x86_64/no-asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux-x86_64/no-asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux-x86_64" -#define DATE "built on: Wed Jun 17 17:28:59 2026 UTC" +#define DATE "built on: Tue Aug 25 12:51:07 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux-x86_64/no-asm/include/openssl/opensslv.h b/deps/openssl/config/archs/linux-x86_64/no-asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux-x86_64/no-asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux-x86_64/no-asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux-x86_64/no-asm/include/openssl/ssl.h b/deps/openssl/config/archs/linux-x86_64/no-asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux-x86_64/no-asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux-x86_64/no-asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux32-s390x/asm/configdata.pm b/deps/openssl/config/archs/linux32-s390x/asm/configdata.pm index 1ca1ae6b921f..a8198c6bb7e7 100644 --- a/deps/openssl/config/archs/linux32-s390x/asm/configdata.pm +++ b/deps/openssl/config/archs/linux32-s390x/asm/configdata.pm @@ -174,7 +174,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -234,7 +234,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux32-s390x", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2253,6 +2253,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2289,6 +2292,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4947,6 +4953,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4983,6 +4992,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11301,6 +11313,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11337,6 +11352,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13995,6 +14013,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14031,6 +14052,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16428,6 +16452,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16440,6 +16465,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18605,6 +18631,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18617,6 +18644,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux32-s390x/asm/crypto/buildinf.h b/deps/openssl/config/archs/linux32-s390x/asm/crypto/buildinf.h index f3dda714dde6..2aef9d8766f6 100644 --- a/deps/openssl/config/archs/linux32-s390x/asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux32-s390x/asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux32-s390x" -#define DATE "built on: Wed Jun 17 17:29:37 2026 UTC" +#define DATE "built on: Tue Aug 25 12:52:02 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux32-s390x/asm/include/openssl/opensslv.h b/deps/openssl/config/archs/linux32-s390x/asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux32-s390x/asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux32-s390x/asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux32-s390x/asm/include/openssl/ssl.h b/deps/openssl/config/archs/linux32-s390x/asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux32-s390x/asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux32-s390x/asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux32-s390x/asm_avx2/configdata.pm b/deps/openssl/config/archs/linux32-s390x/asm_avx2/configdata.pm index b3f1fb9ba076..0ff37a363aa6 100644 --- a/deps/openssl/config/archs/linux32-s390x/asm_avx2/configdata.pm +++ b/deps/openssl/config/archs/linux32-s390x/asm_avx2/configdata.pm @@ -174,7 +174,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -234,7 +234,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux32-s390x", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2253,6 +2253,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2289,6 +2292,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4947,6 +4953,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4983,6 +4992,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11301,6 +11313,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11337,6 +11352,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13995,6 +14013,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14031,6 +14052,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16428,6 +16452,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16440,6 +16465,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18605,6 +18631,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18617,6 +18644,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux32-s390x/asm_avx2/crypto/buildinf.h b/deps/openssl/config/archs/linux32-s390x/asm_avx2/crypto/buildinf.h index 068dfd372cef..0bae9c825baf 100644 --- a/deps/openssl/config/archs/linux32-s390x/asm_avx2/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux32-s390x/asm_avx2/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux32-s390x" -#define DATE "built on: Wed Jun 17 17:29:47 2026 UTC" +#define DATE "built on: Tue Aug 25 12:52:17 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux32-s390x/asm_avx2/include/openssl/opensslv.h b/deps/openssl/config/archs/linux32-s390x/asm_avx2/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux32-s390x/asm_avx2/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux32-s390x/asm_avx2/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux32-s390x/asm_avx2/include/openssl/ssl.h b/deps/openssl/config/archs/linux32-s390x/asm_avx2/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux32-s390x/asm_avx2/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux32-s390x/asm_avx2/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux32-s390x/no-asm/configdata.pm b/deps/openssl/config/archs/linux32-s390x/no-asm/configdata.pm index e4ce267208cc..5968eb75b569 100644 --- a/deps/openssl/config/archs/linux32-s390x/no-asm/configdata.pm +++ b/deps/openssl/config/archs/linux32-s390x/no-asm/configdata.pm @@ -172,7 +172,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -233,7 +233,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-asm no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux32-s390x", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2206,6 +2206,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2242,6 +2245,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4900,6 +4906,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4936,6 +4945,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11238,6 +11250,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11274,6 +11289,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13932,6 +13950,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -13968,6 +13989,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16365,6 +16389,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16377,6 +16402,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18485,6 +18511,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18497,6 +18524,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux32-s390x/no-asm/crypto/buildinf.h b/deps/openssl/config/archs/linux32-s390x/no-asm/crypto/buildinf.h index 38d1d5cc558f..3b7b6bb8692f 100644 --- a/deps/openssl/config/archs/linux32-s390x/no-asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux32-s390x/no-asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux32-s390x" -#define DATE "built on: Wed Jun 17 17:29:56 2026 UTC" +#define DATE "built on: Tue Aug 25 12:52:31 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux32-s390x/no-asm/include/openssl/opensslv.h b/deps/openssl/config/archs/linux32-s390x/no-asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux32-s390x/no-asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux32-s390x/no-asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux32-s390x/no-asm/include/openssl/ssl.h b/deps/openssl/config/archs/linux32-s390x/no-asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux32-s390x/no-asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux32-s390x/no-asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux64-loongarch64/no-asm/configdata.pm b/deps/openssl/config/archs/linux64-loongarch64/no-asm/configdata.pm index fd88a5822293..04b12ee98c38 100644 --- a/deps/openssl/config/archs/linux64-loongarch64/no-asm/configdata.pm +++ b/deps/openssl/config/archs/linux64-loongarch64/no-asm/configdata.pm @@ -172,7 +172,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -233,7 +233,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-asm no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux64-loongarch64", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2206,6 +2206,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2242,6 +2245,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4900,6 +4906,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4936,6 +4945,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11238,6 +11250,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11274,6 +11289,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13932,6 +13950,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -13968,6 +13989,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16365,6 +16389,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16377,6 +16402,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18485,6 +18511,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18497,6 +18524,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux64-loongarch64/no-asm/crypto/buildinf.h b/deps/openssl/config/archs/linux64-loongarch64/no-asm/crypto/buildinf.h index 5e6994fc6589..bd7564e8b5d2 100644 --- a/deps/openssl/config/archs/linux64-loongarch64/no-asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux64-loongarch64/no-asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux64-loongarch64" -#define DATE "built on: Wed Jun 17 17:33:25 2026 UTC" +#define DATE "built on: Tue Aug 25 12:58:07 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux64-loongarch64/no-asm/include/openssl/opensslv.h b/deps/openssl/config/archs/linux64-loongarch64/no-asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux64-loongarch64/no-asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux64-loongarch64/no-asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux64-loongarch64/no-asm/include/openssl/ssl.h b/deps/openssl/config/archs/linux64-loongarch64/no-asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux64-loongarch64/no-asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux64-loongarch64/no-asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux64-mips64/asm/configdata.pm b/deps/openssl/config/archs/linux64-mips64/asm/configdata.pm index 7e6e333b58fa..0afc617fcb7f 100644 --- a/deps/openssl/config/archs/linux64-mips64/asm/configdata.pm +++ b/deps/openssl/config/archs/linux64-mips64/asm/configdata.pm @@ -177,7 +177,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -237,7 +237,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -296,11 +296,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux64-mips64", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2231,6 +2231,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2267,6 +2270,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4925,6 +4931,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4961,6 +4970,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11272,6 +11284,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11308,6 +11323,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13966,6 +13984,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14002,6 +14023,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16399,6 +16423,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16411,6 +16436,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18561,6 +18587,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18573,6 +18600,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux64-mips64/asm/crypto/buildinf.h b/deps/openssl/config/archs/linux64-mips64/asm/crypto/buildinf.h index 933e0c3ad0f4..f8c3ede48432 100644 --- a/deps/openssl/config/archs/linux64-mips64/asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux64-mips64/asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux64-mips64" -#define DATE "built on: Wed Jun 17 17:30:34 2026 UTC" +#define DATE "built on: Tue Aug 25 12:53:26 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux64-mips64/asm/include/openssl/opensslv.h b/deps/openssl/config/archs/linux64-mips64/asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux64-mips64/asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux64-mips64/asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux64-mips64/asm/include/openssl/ssl.h b/deps/openssl/config/archs/linux64-mips64/asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux64-mips64/asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux64-mips64/asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux64-mips64/asm_avx2/configdata.pm b/deps/openssl/config/archs/linux64-mips64/asm_avx2/configdata.pm index 44828e7e436f..fd7c115b97c5 100644 --- a/deps/openssl/config/archs/linux64-mips64/asm_avx2/configdata.pm +++ b/deps/openssl/config/archs/linux64-mips64/asm_avx2/configdata.pm @@ -177,7 +177,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -237,7 +237,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -296,11 +296,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux64-mips64", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2231,6 +2231,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2267,6 +2270,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4925,6 +4931,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4961,6 +4970,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11272,6 +11284,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11308,6 +11323,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13966,6 +13984,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14002,6 +14023,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16399,6 +16423,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16411,6 +16436,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18561,6 +18587,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18573,6 +18600,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux64-mips64/asm_avx2/crypto/buildinf.h b/deps/openssl/config/archs/linux64-mips64/asm_avx2/crypto/buildinf.h index 0ce75e6089a5..1f69f13c454d 100644 --- a/deps/openssl/config/archs/linux64-mips64/asm_avx2/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux64-mips64/asm_avx2/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux64-mips64" -#define DATE "built on: Wed Jun 17 17:30:44 2026 UTC" +#define DATE "built on: Tue Aug 25 12:53:40 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux64-mips64/asm_avx2/include/openssl/opensslv.h b/deps/openssl/config/archs/linux64-mips64/asm_avx2/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux64-mips64/asm_avx2/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux64-mips64/asm_avx2/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux64-mips64/asm_avx2/include/openssl/ssl.h b/deps/openssl/config/archs/linux64-mips64/asm_avx2/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux64-mips64/asm_avx2/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux64-mips64/asm_avx2/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux64-mips64/no-asm/configdata.pm b/deps/openssl/config/archs/linux64-mips64/no-asm/configdata.pm index f5aff4b52e69..07db97ab6049 100644 --- a/deps/openssl/config/archs/linux64-mips64/no-asm/configdata.pm +++ b/deps/openssl/config/archs/linux64-mips64/no-asm/configdata.pm @@ -172,7 +172,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -233,7 +233,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-asm no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux64-mips64", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2207,6 +2207,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2243,6 +2246,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4901,6 +4907,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4937,6 +4946,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11239,6 +11251,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11275,6 +11290,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13933,6 +13951,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -13969,6 +13990,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16366,6 +16390,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16378,6 +16403,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18486,6 +18512,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18498,6 +18525,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux64-mips64/no-asm/crypto/buildinf.h b/deps/openssl/config/archs/linux64-mips64/no-asm/crypto/buildinf.h index 7ae8f2df59e6..6249246a84b4 100644 --- a/deps/openssl/config/archs/linux64-mips64/no-asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux64-mips64/no-asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux64-mips64" -#define DATE "built on: Wed Jun 17 17:30:53 2026 UTC" +#define DATE "built on: Tue Aug 25 12:53:53 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux64-mips64/no-asm/include/openssl/opensslv.h b/deps/openssl/config/archs/linux64-mips64/no-asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux64-mips64/no-asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux64-mips64/no-asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux64-mips64/no-asm/include/openssl/ssl.h b/deps/openssl/config/archs/linux64-mips64/no-asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux64-mips64/no-asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux64-mips64/no-asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux64-riscv64/asm/configdata.pm b/deps/openssl/config/archs/linux64-riscv64/asm/configdata.pm index 4431f75a1afd..f65899375e22 100644 --- a/deps/openssl/config/archs/linux64-riscv64/asm/configdata.pm +++ b/deps/openssl/config/archs/linux64-riscv64/asm/configdata.pm @@ -18,7 +18,6 @@ our %config = ( "ARFLAGS" => [ "qc" ], - "AS" => "as", "ASFLAGS" => [], "CC" => "gcc", "CFLAGS" => [ @@ -34,7 +33,6 @@ our %config = ( "FIPSKEY" => "f4556650ac31d35461610bac4ed81b1a181b2d8a43ea2854cbae22ca74560813", "FIPS_VENDOR" => "OpenSSL FIPS Provider", "HASHBANGPERL" => "/usr/bin/env perl", - "LD" => "ld", "LDFLAGS" => [], "LDLIBS" => [], "OBJCOPY" => "objcopy", @@ -176,7 +174,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -236,10 +234,10 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", - "perl_archname" => "x86_64-linux-thread-multi", + "patch" => "8", + "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", - "perl_version" => "5.42.2", + "perl_version" => "5.34.0", "perlargv" => [ "no-tests", "no-shared", @@ -255,9 +253,9 @@ our %config = ( "linux64-riscv64" ], "perlenv" => { - "AR" => "ar", + "AR" => undef, "ARFLAGS" => undef, - "AS" => "as", + "AS" => undef, "ASFLAGS" => undef, "BUILDFILE" => undef, "CC" => "gcc", @@ -267,18 +265,18 @@ our %config = ( "CPPFLAGS" => undef, "CPPINCLUDES" => undef, "CROSS_COMPILE" => undef, - "CXX" => "g++", + "CXX" => undef, "CXXFLAGS" => undef, "HASHBANGPERL" => undef, - "LD" => "ld", + "LD" => undef, "LDFLAGS" => undef, "LDLIBS" => undef, "MT" => undef, "MTFLAGS" => undef, - "OBJCOPY" => "objcopy", + "OBJCOPY" => undef, "OPENSSL_LOCAL_CONFIG_DIR" => undef, "PERL" => undef, - "RANLIB" => "ranlib", + "RANLIB" => undef, "RC" => undef, "RCFLAGS" => undef, "RM" => undef, @@ -295,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux64-riscv64", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2240,6 +2238,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2276,6 +2277,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4934,6 +4938,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4970,6 +4977,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11302,6 +11312,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11338,6 +11351,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13996,6 +14012,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14032,6 +14051,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16429,6 +16451,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16441,6 +16464,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18552,6 +18576,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18564,6 +18589,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux64-riscv64/asm/crypto/buildinf.h b/deps/openssl/config/archs/linux64-riscv64/asm/crypto/buildinf.h index 132867b95c47..6fd695965dc1 100644 --- a/deps/openssl/config/archs/linux64-riscv64/asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux64-riscv64/asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux64-riscv64" -#define DATE "built on: Tue Jun 30 04:15:54 2026 UTC" +#define DATE "built on: Tue Aug 25 12:54:06 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux64-riscv64/asm/include/openssl/opensslv.h b/deps/openssl/config/archs/linux64-riscv64/asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux64-riscv64/asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux64-riscv64/asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux64-riscv64/asm/include/openssl/ssl.h b/deps/openssl/config/archs/linux64-riscv64/asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux64-riscv64/asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux64-riscv64/asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux64-riscv64/asm_avx2/configdata.pm b/deps/openssl/config/archs/linux64-riscv64/asm_avx2/configdata.pm index 0063924e8a2a..9464ee908127 100644 --- a/deps/openssl/config/archs/linux64-riscv64/asm_avx2/configdata.pm +++ b/deps/openssl/config/archs/linux64-riscv64/asm_avx2/configdata.pm @@ -18,7 +18,6 @@ our %config = ( "ARFLAGS" => [ "qc" ], - "AS" => "as", "ASFLAGS" => [], "CC" => "../config/fake_gcc.pl", "CFLAGS" => [ @@ -34,7 +33,6 @@ our %config = ( "FIPSKEY" => "f4556650ac31d35461610bac4ed81b1a181b2d8a43ea2854cbae22ca74560813", "FIPS_VENDOR" => "OpenSSL FIPS Provider", "HASHBANGPERL" => "/usr/bin/env perl", - "LD" => "ld", "LDFLAGS" => [], "LDLIBS" => [], "OBJCOPY" => "objcopy", @@ -176,7 +174,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -236,10 +234,10 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", - "perl_archname" => "x86_64-linux-thread-multi", + "patch" => "8", + "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", - "perl_version" => "5.42.2", + "perl_version" => "5.34.0", "perlargv" => [ "no-tests", "no-shared", @@ -255,9 +253,9 @@ our %config = ( "linux64-riscv64" ], "perlenv" => { - "AR" => "ar", + "AR" => undef, "ARFLAGS" => undef, - "AS" => "as", + "AS" => undef, "ASFLAGS" => undef, "BUILDFILE" => undef, "CC" => "../config/fake_gcc.pl", @@ -267,18 +265,18 @@ our %config = ( "CPPFLAGS" => undef, "CPPINCLUDES" => undef, "CROSS_COMPILE" => undef, - "CXX" => "g++", + "CXX" => undef, "CXXFLAGS" => undef, "HASHBANGPERL" => undef, - "LD" => "ld", + "LD" => undef, "LDFLAGS" => undef, "LDLIBS" => undef, "MT" => undef, "MTFLAGS" => undef, - "OBJCOPY" => "objcopy", + "OBJCOPY" => undef, "OPENSSL_LOCAL_CONFIG_DIR" => undef, "PERL" => undef, - "RANLIB" => "ranlib", + "RANLIB" => undef, "RC" => undef, "RCFLAGS" => undef, "RM" => undef, @@ -295,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux64-riscv64", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2240,6 +2238,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2276,6 +2277,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4934,6 +4938,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4970,6 +4977,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11302,6 +11312,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11338,6 +11351,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13996,6 +14012,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14032,6 +14051,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16429,6 +16451,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16441,6 +16464,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18552,6 +18576,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18564,6 +18589,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux64-riscv64/asm_avx2/crypto/buildinf.h b/deps/openssl/config/archs/linux64-riscv64/asm_avx2/crypto/buildinf.h index 017783059eb5..b88360c4414d 100644 --- a/deps/openssl/config/archs/linux64-riscv64/asm_avx2/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux64-riscv64/asm_avx2/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux64-riscv64" -#define DATE "built on: Tue Jun 30 04:16:04 2026 UTC" +#define DATE "built on: Tue Aug 25 12:54:22 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux64-riscv64/asm_avx2/include/openssl/opensslv.h b/deps/openssl/config/archs/linux64-riscv64/asm_avx2/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux64-riscv64/asm_avx2/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux64-riscv64/asm_avx2/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux64-riscv64/asm_avx2/include/openssl/ssl.h b/deps/openssl/config/archs/linux64-riscv64/asm_avx2/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux64-riscv64/asm_avx2/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux64-riscv64/asm_avx2/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux64-riscv64/no-asm/configdata.pm b/deps/openssl/config/archs/linux64-riscv64/no-asm/configdata.pm index 0afb9fe32895..30d3a517c15a 100644 --- a/deps/openssl/config/archs/linux64-riscv64/no-asm/configdata.pm +++ b/deps/openssl/config/archs/linux64-riscv64/no-asm/configdata.pm @@ -172,7 +172,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -233,7 +233,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-asm no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux64-riscv64", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2206,6 +2206,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2242,6 +2245,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4900,6 +4906,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4936,6 +4945,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11238,6 +11250,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11274,6 +11289,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13932,6 +13950,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -13968,6 +13989,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16365,6 +16389,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16377,6 +16402,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18485,6 +18511,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18497,6 +18524,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux64-riscv64/no-asm/crypto/buildinf.h b/deps/openssl/config/archs/linux64-riscv64/no-asm/crypto/buildinf.h index 47ed00634a03..08f9dacf7afa 100644 --- a/deps/openssl/config/archs/linux64-riscv64/no-asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux64-riscv64/no-asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux64-riscv64" -#define DATE "built on: Wed Jun 17 17:33:16 2026 UTC" +#define DATE "built on: Tue Aug 25 12:54:36 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux64-riscv64/no-asm/include/openssl/opensslv.h b/deps/openssl/config/archs/linux64-riscv64/no-asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux64-riscv64/no-asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux64-riscv64/no-asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux64-riscv64/no-asm/include/openssl/ssl.h b/deps/openssl/config/archs/linux64-riscv64/no-asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux64-riscv64/no-asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux64-riscv64/no-asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux64-s390x/asm/configdata.pm b/deps/openssl/config/archs/linux64-s390x/asm/configdata.pm index bccf82d2ca5d..fde561ab9d43 100644 --- a/deps/openssl/config/archs/linux64-s390x/asm/configdata.pm +++ b/deps/openssl/config/archs/linux64-s390x/asm/configdata.pm @@ -174,7 +174,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -234,7 +234,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux64-s390x", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2258,6 +2258,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2294,6 +2297,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4952,6 +4958,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4988,6 +4997,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11320,6 +11332,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11356,6 +11371,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14014,6 +14032,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14050,6 +14071,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16447,6 +16471,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16459,6 +16484,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18624,6 +18650,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18636,6 +18663,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux64-s390x/asm/crypto/buildinf.h b/deps/openssl/config/archs/linux64-s390x/asm/crypto/buildinf.h index 9f290c153834..85fcac954888 100644 --- a/deps/openssl/config/archs/linux64-s390x/asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux64-s390x/asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux64-s390x" -#define DATE "built on: Wed Jun 17 17:30:06 2026 UTC" +#define DATE "built on: Tue Aug 25 12:52:44 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux64-s390x/asm/include/openssl/opensslv.h b/deps/openssl/config/archs/linux64-s390x/asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux64-s390x/asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux64-s390x/asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux64-s390x/asm/include/openssl/ssl.h b/deps/openssl/config/archs/linux64-s390x/asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux64-s390x/asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux64-s390x/asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux64-s390x/asm_avx2/configdata.pm b/deps/openssl/config/archs/linux64-s390x/asm_avx2/configdata.pm index 076ce08f1495..db711f1f371f 100644 --- a/deps/openssl/config/archs/linux64-s390x/asm_avx2/configdata.pm +++ b/deps/openssl/config/archs/linux64-s390x/asm_avx2/configdata.pm @@ -174,7 +174,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -234,7 +234,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux64-s390x", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2258,6 +2258,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2294,6 +2297,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4952,6 +4958,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4988,6 +4997,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11320,6 +11332,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11356,6 +11371,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14014,6 +14032,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14050,6 +14071,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16447,6 +16471,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16459,6 +16484,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18624,6 +18650,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18636,6 +18663,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux64-s390x/asm_avx2/crypto/buildinf.h b/deps/openssl/config/archs/linux64-s390x/asm_avx2/crypto/buildinf.h index a0807d918574..dc47544122a9 100644 --- a/deps/openssl/config/archs/linux64-s390x/asm_avx2/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux64-s390x/asm_avx2/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux64-s390x" -#define DATE "built on: Wed Jun 17 17:30:16 2026 UTC" +#define DATE "built on: Tue Aug 25 12:52:59 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux64-s390x/asm_avx2/include/openssl/opensslv.h b/deps/openssl/config/archs/linux64-s390x/asm_avx2/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux64-s390x/asm_avx2/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux64-s390x/asm_avx2/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux64-s390x/asm_avx2/include/openssl/ssl.h b/deps/openssl/config/archs/linux64-s390x/asm_avx2/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux64-s390x/asm_avx2/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux64-s390x/asm_avx2/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/linux64-s390x/no-asm/configdata.pm b/deps/openssl/config/archs/linux64-s390x/no-asm/configdata.pm index 0768ef4d8eab..28d575ff8d60 100644 --- a/deps/openssl/config/archs/linux64-s390x/no-asm/configdata.pm +++ b/deps/openssl/config/archs/linux64-s390x/no-asm/configdata.pm @@ -172,7 +172,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -233,7 +233,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-asm no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -293,11 +293,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned char", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "linux64-s390x", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2207,6 +2207,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2243,6 +2246,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4901,6 +4907,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4937,6 +4946,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11239,6 +11251,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11275,6 +11290,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13933,6 +13951,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -13969,6 +13990,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16366,6 +16390,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16378,6 +16403,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18486,6 +18512,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18498,6 +18525,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/linux64-s390x/no-asm/crypto/buildinf.h b/deps/openssl/config/archs/linux64-s390x/no-asm/crypto/buildinf.h index b3ac1f765fc1..8ebaa83c9019 100644 --- a/deps/openssl/config/archs/linux64-s390x/no-asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/linux64-s390x/no-asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: linux64-s390x" -#define DATE "built on: Wed Jun 17 17:30:25 2026 UTC" +#define DATE "built on: Tue Aug 25 12:53:13 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/linux64-s390x/no-asm/include/openssl/opensslv.h b/deps/openssl/config/archs/linux64-s390x/no-asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/linux64-s390x/no-asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/linux64-s390x/no-asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/linux64-s390x/no-asm/include/openssl/ssl.h b/deps/openssl/config/archs/linux64-s390x/no-asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/linux64-s390x/no-asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/linux64-s390x/no-asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/solaris-x86-gcc/asm/configdata.pm b/deps/openssl/config/archs/solaris-x86-gcc/asm/configdata.pm index 7b3aba3a639d..2825259eeac5 100644 --- a/deps/openssl/config/archs/solaris-x86-gcc/asm/configdata.pm +++ b/deps/openssl/config/archs/solaris-x86-gcc/asm/configdata.pm @@ -171,7 +171,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -231,7 +231,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -290,11 +290,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "solaris-x86-gcc", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2256,6 +2256,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2292,6 +2295,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4950,6 +4956,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4986,6 +4995,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11310,6 +11322,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11346,6 +11361,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14004,6 +14022,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14040,6 +14061,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16437,6 +16461,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16449,6 +16474,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18560,6 +18586,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18572,6 +18599,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/solaris-x86-gcc/asm/crypto/buildinf.h b/deps/openssl/config/archs/solaris-x86-gcc/asm/crypto/buildinf.h index cb7b0c149cfc..e8bb3e6e170d 100644 --- a/deps/openssl/config/archs/solaris-x86-gcc/asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/solaris-x86-gcc/asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: solaris-x86-gcc" -#define DATE "built on: Wed Jun 17 17:31:02 2026 UTC" +#define DATE "built on: Tue Aug 25 12:54:49 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/solaris-x86-gcc/asm/include/openssl/opensslv.h b/deps/openssl/config/archs/solaris-x86-gcc/asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/solaris-x86-gcc/asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/solaris-x86-gcc/asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/solaris-x86-gcc/asm/include/openssl/ssl.h b/deps/openssl/config/archs/solaris-x86-gcc/asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/solaris-x86-gcc/asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/solaris-x86-gcc/asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/solaris-x86-gcc/asm_avx2/configdata.pm b/deps/openssl/config/archs/solaris-x86-gcc/asm_avx2/configdata.pm index ee82a94dea37..1de2b1838d2d 100644 --- a/deps/openssl/config/archs/solaris-x86-gcc/asm_avx2/configdata.pm +++ b/deps/openssl/config/archs/solaris-x86-gcc/asm_avx2/configdata.pm @@ -171,7 +171,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -231,7 +231,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -290,11 +290,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "solaris-x86-gcc", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2256,6 +2256,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2292,6 +2295,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4950,6 +4956,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4986,6 +4995,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11310,6 +11322,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11346,6 +11361,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14004,6 +14022,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14040,6 +14061,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16437,6 +16461,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16449,6 +16474,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18560,6 +18586,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18572,6 +18599,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/solaris-x86-gcc/asm_avx2/crypto/buildinf.h b/deps/openssl/config/archs/solaris-x86-gcc/asm_avx2/crypto/buildinf.h index c536b621df14..79239580903c 100644 --- a/deps/openssl/config/archs/solaris-x86-gcc/asm_avx2/crypto/buildinf.h +++ b/deps/openssl/config/archs/solaris-x86-gcc/asm_avx2/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: solaris-x86-gcc" -#define DATE "built on: Wed Jun 17 17:31:13 2026 UTC" +#define DATE "built on: Tue Aug 25 12:55:04 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/solaris-x86-gcc/asm_avx2/include/openssl/opensslv.h b/deps/openssl/config/archs/solaris-x86-gcc/asm_avx2/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/solaris-x86-gcc/asm_avx2/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/solaris-x86-gcc/asm_avx2/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/solaris-x86-gcc/asm_avx2/include/openssl/ssl.h b/deps/openssl/config/archs/solaris-x86-gcc/asm_avx2/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/solaris-x86-gcc/asm_avx2/include/openssl/ssl.h +++ b/deps/openssl/config/archs/solaris-x86-gcc/asm_avx2/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/solaris-x86-gcc/no-asm/configdata.pm b/deps/openssl/config/archs/solaris-x86-gcc/no-asm/configdata.pm index 8f683123c4c5..cd239c07bc4e 100644 --- a/deps/openssl/config/archs/solaris-x86-gcc/no-asm/configdata.pm +++ b/deps/openssl/config/archs/solaris-x86-gcc/no-asm/configdata.pm @@ -169,7 +169,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -230,7 +230,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-asm no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -290,11 +290,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "solaris-x86-gcc", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2198,6 +2198,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2234,6 +2237,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4892,6 +4898,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4928,6 +4937,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11230,6 +11242,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11266,6 +11281,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13924,6 +13942,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -13960,6 +13981,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16357,6 +16381,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16369,6 +16394,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18477,6 +18503,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18489,6 +18516,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/solaris-x86-gcc/no-asm/crypto/buildinf.h b/deps/openssl/config/archs/solaris-x86-gcc/no-asm/crypto/buildinf.h index 3aa35283d231..17c1ed5f0bd2 100644 --- a/deps/openssl/config/archs/solaris-x86-gcc/no-asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/solaris-x86-gcc/no-asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: solaris-x86-gcc" -#define DATE "built on: Wed Jun 17 17:31:23 2026 UTC" +#define DATE "built on: Tue Aug 25 12:55:18 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/solaris-x86-gcc/no-asm/include/openssl/opensslv.h b/deps/openssl/config/archs/solaris-x86-gcc/no-asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/solaris-x86-gcc/no-asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/solaris-x86-gcc/no-asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/solaris-x86-gcc/no-asm/include/openssl/ssl.h b/deps/openssl/config/archs/solaris-x86-gcc/no-asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/solaris-x86-gcc/no-asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/solaris-x86-gcc/no-asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/solaris64-x86_64-gcc/asm/configdata.pm b/deps/openssl/config/archs/solaris64-x86_64-gcc/asm/configdata.pm index 2613cd196ae5..88b300eeeb7f 100644 --- a/deps/openssl/config/archs/solaris64-x86_64-gcc/asm/configdata.pm +++ b/deps/openssl/config/archs/solaris64-x86_64-gcc/asm/configdata.pm @@ -171,7 +171,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -231,7 +231,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -290,11 +290,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "solaris64-x86_64-gcc", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2263,6 +2263,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2299,6 +2302,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4957,6 +4963,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4993,6 +5002,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11367,6 +11379,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11403,6 +11418,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14061,6 +14079,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14097,6 +14118,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16494,6 +16518,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16506,6 +16531,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18617,6 +18643,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18629,6 +18656,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/solaris64-x86_64-gcc/asm/crypto/buildinf.h b/deps/openssl/config/archs/solaris64-x86_64-gcc/asm/crypto/buildinf.h index efe0be8ef0b3..32fc64cf8679 100644 --- a/deps/openssl/config/archs/solaris64-x86_64-gcc/asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/solaris64-x86_64-gcc/asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: solaris64-x86_64-gcc" -#define DATE "built on: Wed Jun 17 17:31:32 2026 UTC" +#define DATE "built on: Tue Aug 25 12:55:32 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/solaris64-x86_64-gcc/asm/include/openssl/opensslv.h b/deps/openssl/config/archs/solaris64-x86_64-gcc/asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/solaris64-x86_64-gcc/asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/solaris64-x86_64-gcc/asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/solaris64-x86_64-gcc/asm/include/openssl/ssl.h b/deps/openssl/config/archs/solaris64-x86_64-gcc/asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/solaris64-x86_64-gcc/asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/solaris64-x86_64-gcc/asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/solaris64-x86_64-gcc/asm_avx2/configdata.pm b/deps/openssl/config/archs/solaris64-x86_64-gcc/asm_avx2/configdata.pm index a627e26f0630..3ddd4e30f92d 100644 --- a/deps/openssl/config/archs/solaris64-x86_64-gcc/asm_avx2/configdata.pm +++ b/deps/openssl/config/archs/solaris64-x86_64-gcc/asm_avx2/configdata.pm @@ -171,7 +171,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -231,7 +231,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -290,11 +290,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "solaris64-x86_64-gcc", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2263,6 +2263,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2299,6 +2302,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4957,6 +4963,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4993,6 +5002,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11367,6 +11379,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11403,6 +11418,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -14061,6 +14079,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -14097,6 +14118,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16494,6 +16518,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16506,6 +16531,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18617,6 +18643,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18629,6 +18656,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/solaris64-x86_64-gcc/asm_avx2/crypto/buildinf.h b/deps/openssl/config/archs/solaris64-x86_64-gcc/asm_avx2/crypto/buildinf.h index 3877782d03bf..cc8735d5c63e 100644 --- a/deps/openssl/config/archs/solaris64-x86_64-gcc/asm_avx2/crypto/buildinf.h +++ b/deps/openssl/config/archs/solaris64-x86_64-gcc/asm_avx2/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: solaris64-x86_64-gcc" -#define DATE "built on: Wed Jun 17 17:31:47 2026 UTC" +#define DATE "built on: Tue Aug 25 12:55:54 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/solaris64-x86_64-gcc/asm_avx2/include/openssl/opensslv.h b/deps/openssl/config/archs/solaris64-x86_64-gcc/asm_avx2/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/solaris64-x86_64-gcc/asm_avx2/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/solaris64-x86_64-gcc/asm_avx2/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/solaris64-x86_64-gcc/asm_avx2/include/openssl/ssl.h b/deps/openssl/config/archs/solaris64-x86_64-gcc/asm_avx2/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/solaris64-x86_64-gcc/asm_avx2/include/openssl/ssl.h +++ b/deps/openssl/config/archs/solaris64-x86_64-gcc/asm_avx2/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/config/archs/solaris64-x86_64-gcc/no-asm/configdata.pm b/deps/openssl/config/archs/solaris64-x86_64-gcc/no-asm/configdata.pm index 81a40f0be536..09125eacfd1a 100644 --- a/deps/openssl/config/archs/solaris64-x86_64-gcc/no-asm/configdata.pm +++ b/deps/openssl/config/archs/solaris64-x86_64-gcc/no-asm/configdata.pm @@ -169,7 +169,7 @@ our %config = ( ], "dynamic_engines" => "0", "ex_libs" => [], - "full_version" => "3.5.7", + "full_version" => "3.5.8", "includes" => [], "lflags" => [], "lib_defines" => [ @@ -230,7 +230,7 @@ our %config = ( "openssl_sys_defines" => [], "openssldir" => "", "options" => "enable-ssl-trace enable-fips enable-zlib --with-zlib-include=../../zlib enable-brotli --with-brotli-include=../../brotli/c/include enable-zstd --with-zstd-include=../../zstd/lib no-afalgeng no-asan no-asm no-brotli-dynamic no-buildtest-c++ no-crypto-mdebug no-crypto-mdebug-backtrace no-demos no-devcryptoeng no-dynamic-engine no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fips-jitter no-fuzz-afl no-fuzz-libfuzzer no-h3demo no-hqinterop no-jitter no-ktls no-loadereng no-md2 no-msan no-pie no-rc5 no-sctp no-shared no-ssl3 no-ssl3-method no-sslkeylog no-tests no-tfo no-trace no-ubsan no-unit-test no-uplink no-weak-ssl-ciphers no-winstore no-zlib-dynamic no-zstd-dynamic", - "patch" => "7", + "patch" => "8", "perl_archname" => "x86_64-linux-gnu-thread-multi", "perl_cmd" => "/usr/bin/perl", "perl_version" => "5.34.0", @@ -290,11 +290,11 @@ our %config = ( "prerelease" => "", "processor" => "", "rc4_int" => "unsigned int", - "release_date" => "9 Jun 2026", + "release_date" => "25 Aug 2026", "shlib_version" => "3", "sourcedir" => ".", "target" => "solaris64-x86_64-gcc", - "version" => "3.5.7" + "version" => "3.5.8" ); our %target = ( "AR" => "ar", @@ -2199,6 +2199,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -2235,6 +2238,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -4893,6 +4899,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -4929,6 +4938,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -11231,6 +11243,9 @@ our %unified_info = ( "doc/html/man3/MDC2_Init.html" => [ "doc/man3/MDC2_Init.pod" ], + "doc/html/man3/NAME_CONSTRAINTS_check.html" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/html/man3/NCONF_new_ex.html" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -11267,6 +11282,9 @@ our %unified_info = ( "doc/html/man3/OPENSSL_LH_stats.html" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/html/man3/OPENSSL_armcap.html" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/html/man3/OPENSSL_config.html" => [ "doc/man3/OPENSSL_config.pod" ], @@ -13925,6 +13943,9 @@ our %unified_info = ( "doc/man/man3/MDC2_Init.3" => [ "doc/man3/MDC2_Init.pod" ], + "doc/man/man3/NAME_CONSTRAINTS_check.3" => [ + "doc/man3/NAME_CONSTRAINTS_check.pod" + ], "doc/man/man3/NCONF_new_ex.3" => [ "doc/man3/NCONF_new_ex.pod" ], @@ -13961,6 +13982,9 @@ our %unified_info = ( "doc/man/man3/OPENSSL_LH_stats.3" => [ "doc/man3/OPENSSL_LH_stats.pod" ], + "doc/man/man3/OPENSSL_armcap.3" => [ + "doc/man3/OPENSSL_armcap.pod" + ], "doc/man/man3/OPENSSL_config.3" => [ "doc/man3/OPENSSL_config.pod" ], @@ -16358,6 +16382,7 @@ our %unified_info = ( "doc/html/man3/HMAC.html", "doc/html/man3/MD5.html", "doc/html/man3/MDC2_Init.html", + "doc/html/man3/NAME_CONSTRAINTS_check.html", "doc/html/man3/NCONF_new_ex.html", "doc/html/man3/OBJ_nid2obj.html", "doc/html/man3/OCSP_REQUEST_new.html", @@ -16370,6 +16395,7 @@ our %unified_info = ( "doc/html/man3/OPENSSL_FILE.html", "doc/html/man3/OPENSSL_LH_COMPFUNC.html", "doc/html/man3/OPENSSL_LH_stats.html", + "doc/html/man3/OPENSSL_armcap.html", "doc/html/man3/OPENSSL_config.html", "doc/html/man3/OPENSSL_fork_prepare.html", "doc/html/man3/OPENSSL_gmtime.html", @@ -18478,6 +18504,7 @@ our %unified_info = ( "doc/man/man3/HMAC.3", "doc/man/man3/MD5.3", "doc/man/man3/MDC2_Init.3", + "doc/man/man3/NAME_CONSTRAINTS_check.3", "doc/man/man3/NCONF_new_ex.3", "doc/man/man3/OBJ_nid2obj.3", "doc/man/man3/OCSP_REQUEST_new.3", @@ -18490,6 +18517,7 @@ our %unified_info = ( "doc/man/man3/OPENSSL_FILE.3", "doc/man/man3/OPENSSL_LH_COMPFUNC.3", "doc/man/man3/OPENSSL_LH_stats.3", + "doc/man/man3/OPENSSL_armcap.3", "doc/man/man3/OPENSSL_config.3", "doc/man/man3/OPENSSL_fork_prepare.3", "doc/man/man3/OPENSSL_gmtime.3", diff --git a/deps/openssl/config/archs/solaris64-x86_64-gcc/no-asm/crypto/buildinf.h b/deps/openssl/config/archs/solaris64-x86_64-gcc/no-asm/crypto/buildinf.h index dcb67f8ce1fa..378b3b1efee2 100644 --- a/deps/openssl/config/archs/solaris64-x86_64-gcc/no-asm/crypto/buildinf.h +++ b/deps/openssl/config/archs/solaris64-x86_64-gcc/no-asm/crypto/buildinf.h @@ -11,7 +11,7 @@ */ #define PLATFORM "platform: solaris64-x86_64-gcc" -#define DATE "built on: Wed Jun 17 17:31:59 2026 UTC" +#define DATE "built on: Tue Aug 25 12:56:11 2026 UTC" /* * Generate compiler_flags as an array of individual characters. This is a diff --git a/deps/openssl/config/archs/solaris64-x86_64-gcc/no-asm/include/openssl/opensslv.h b/deps/openssl/config/archs/solaris64-x86_64-gcc/no-asm/include/openssl/opensslv.h index 8e9329bcc0dd..1555e59c04c6 100644 --- a/deps/openssl/config/archs/solaris64-x86_64-gcc/no-asm/include/openssl/opensslv.h +++ b/deps/openssl/config/archs/solaris64-x86_64-gcc/no-asm/include/openssl/opensslv.h @@ -34,7 +34,7 @@ extern "C" { # define OPENSSL_VERSION_MINOR 5 /* clang-format on */ /* clang-format off */ -# define OPENSSL_VERSION_PATCH 7 +# define OPENSSL_VERSION_PATCH 8 /* clang-format on */ /* @@ -87,10 +87,10 @@ extern "C" { * OPENSSL_VERSION_BUILD_METADATA_STR appended. */ /* clang-format off */ -# define OPENSSL_VERSION_STR "3.5.7" +# define OPENSSL_VERSION_STR "3.5.8" /* clang-format on */ /* clang-format off */ -# define OPENSSL_FULL_VERSION_STR "3.5.7" +# define OPENSSL_FULL_VERSION_STR "3.5.8" /* clang-format on */ /* @@ -99,7 +99,7 @@ extern "C" { * These strings are defined separately to allow them to be parsable. */ /* clang-format off */ -# define OPENSSL_RELEASE_DATE "9 Jun 2026" +# define OPENSSL_RELEASE_DATE "25 Aug 2026" /* clang-format on */ /* @@ -107,7 +107,7 @@ extern "C" { */ /* clang-format off */ -# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.7 9 Jun 2026" +# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.8 25 Aug 2026" /* clang-format on */ /* clang-format off */ diff --git a/deps/openssl/config/archs/solaris64-x86_64-gcc/no-asm/include/openssl/ssl.h b/deps/openssl/config/archs/solaris64-x86_64-gcc/no-asm/include/openssl/ssl.h index eaeeea7d10b4..4460f0493d6e 100644 --- a/deps/openssl/config/archs/solaris64-x86_64-gcc/no-asm/include/openssl/ssl.h +++ b/deps/openssl/config/archs/solaris64-x86_64-gcc/no-asm/include/openssl/ssl.h @@ -2488,6 +2488,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2735,8 +2736,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2775,12 +2786,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/openssl.gyp b/deps/openssl/openssl.gyp index 4e16412a0283..144085fd33df 100644 --- a/deps/openssl/openssl.gyp +++ b/deps/openssl/openssl.gyp @@ -36,7 +36,8 @@ # VC-WIN64-ARM inherits from VC-noCE-common that has no asms. 'includes': ['./openssl_no_asm.gypi'], }, 'gas_version and v(gas_version) >= v("2.26") or ' - 'nasm_version and v(nasm_version) >= v("2.11.8")', { + 'nasm_version and v(nasm_version) >= v("2.11.8") or ' + 'llvm_version and v(llvm_version) >= v("8.0")', { # Require AVX512IFMA supported. See # https://www.openssl.org/docs/man1.1.1/man3/OPENSSL_ia32cap.html # Currently crypto/poly1305/asm/poly1305-x86_64.pl requires AVX512IFMA. @@ -114,7 +115,8 @@ # VC-WIN64-ARM inherits from VC-noCE-common that has no asms. 'includes': ['./openssl-fips_no_asm.gypi'], }, 'gas_version and v(gas_version) >= v("2.26") or ' - 'nasm_version and v(nasm_version) >= v("2.11.8")', { + 'nasm_version and v(nasm_version) >= v("2.11.8") or ' + 'llvm_version and v(llvm_version) >= v("8.0")', { # Require AVX512IFMA supported. See # https://www.openssl.org/docs/man1.1.1/man3/OPENSSL_ia32cap.html # Currently crypto/poly1305/asm/poly1305-x86_64.pl requires AVX512IFMA. diff --git a/deps/openssl/openssl/CHANGES.md b/deps/openssl/openssl/CHANGES.md index c1c29eb55f04..b440f013313f 100644 --- a/deps/openssl/openssl/CHANGES.md +++ b/deps/openssl/openssl/CHANGES.md @@ -28,6 +28,237 @@ OpenSSL Releases OpenSSL 3.5 ----------- +### Changes between 3.5.7 and 3.5.8 [25 Aug 2026] + + * Fixed QUIC server being able to trigger double free when processing `INITIAL` + packet. + + Severity: Moderate + + Issue summary: QUIC server may double free QRX (QUIC record layer RX) object + when channel creation fails for initial packet. + + Impact summary: Double free leads to heap corruption, which typically results + in termination of QUIC server process, leading to a Denial of Service. + There is so far no evidence that this double free is exploitable for remote + code execution, thus it is considered highly improbable. + + Reported by: Fuzz0x (ZKSC Institute of Security Research), Emilio Galle, + and Feng Xue (ThreatBoon). + + ([CVE-2026-18798]) + + *Alexandr Nedvědický* + + * Fixed heap buffer overflow in CMS key unwrapping. + + Severity: Moderate + + Issue summary: OpenSSL CMS decryption sizes the key-unwrap output buffer + based on querying the unwrapped key size, but the AES-WRAP-PAD unwrap + primitive can write and cleanse more bytes than that query reports, causing + an 8-byte out-of-bounds heap write. + + Impact summary: An attacker who supplies a crafted CMS message can trigger + a deterministic 8-byte out-of-bounds heap write when the victim decrypts it + with `CMS_decrypt()`, corrupting the heap and typically resulting in a Denial + of Service. + + Reported by: Bhabani Sankar Das and Filipe Casal (Trail of Bits). + + ([CVE-2026-63072]) + + *Daniel Kubec* + + * Fixed invalid pointer dereference in CMP server via crafted `protectionAlg`. + + Severity: Moderate + + Issue Summary: The OpenSSL Certificate Management Protocol (CMP) + password-based protection verification only checks whether + the `protectionAlg` parameter was not NULL and not its ASN.1 type, + before treating it as a `PBMParameter`. A crafted message can contain + a parameter of a different type, which is then dereferenced as an invalid + pointer. + + Impact summary: A remote, unauthenticated attacker can crash an application + acting as a CMP server that accepts PBM-protected messages, or a CMP client + talking to a malicious or intercepted CMP server, resulting in a Denial + of Service. + + Reported by: Ying Dong and Bhabani Sankar Das. + + ([CVE-2026-63076]) + + *Daniel Kubec* + + * Fixed unbounded memory growth in QUIC server incoming channel queue. + + Severity: Low + + Issue summary: When an OpenSSL QUIC server (Listener SSL object) processes + valid QUIC Initial packets for unknown destination connection IDs, it can + allocate and queue new incoming channels without enforcing any limit. + + Impact summary: A remote peer that can make many `INITIAL` packets reach + the server listener faster than the application accepts connections can + cause the memory allocated to store the per-channel state to grow + without any limits, potentially making the QUIC listener unavailable + and causing a Denial of Service. + + Reported by: Filipe Casal (Trail of Bits) in collaboration with OpenAI. + + ([CVE-2026-14456]) + + + *Filipe Casal* + + * Fixed RPK server signature algorithm selection being able to dereference + a missing certificate. + + Severity: Low + + Issue summary: In a server or client configuration with [RFC 7250] Raw Public + Keys (RPKs) enabled, and only the private key (with no associated + certificate) configured locally, a NULL pointer dereference may occur + when the remote peer solicits raw public keys and also sends the typically + omitted `signature_algorithms_cert` TLS extension. + + Impact summary: The impact is limited to a possible Denial of Service + as a result of an application abort, no data disclosure or remote command + execution are possible. + + Reported by: Filipe Casal (Trail of Bits) in collaboration with OpenAI. + + ([CVE-2026-14457]) + + *Viktor Dukhovni* + + * Fixed excessive memory use buffering DTLS records for a future epoch. + + Severity: Low + + Issue summary: Receiving a DTLS record for a future epoch while a handshake + is in progress causes OpenSSL to buffer far more memory than the record + itself requires. + + Impact summary: A peer can use a small amount of network traffic to make + an OpenSSL DTLS endpoint retain a disproportionately large amount of memory, + which may lead to a Denial of Service. + + Reported by: Amazon Web Services. + + ([CVE-2026-54874]) + + *Matt Caswell* + + * Fixed untrusted Sender DN being used as a format string in CMP response + validation. + + Severity: Low + + Issue Summary: The OpenSSL Certificate Management Protocol (CMP) response + validation passed an unexpected response sender distinguished name directly + as the format string to `ERR_raise_data()`. + + Impact summary: A malicious or intercepted CMP endpoint can crash a CMP + client that enforces an expected sender or uses a pinned server certificate + whose subject becomes the default expected sender. + + Reported by: Filipe Casal (Trail of Bits) in collaboration with OpenAI, + Brandon Luo, and TrendAI Zero Day Initiative. + + ([CVE-2026-63073]) + + *Filipe Casal* + + * Fixed CMP indefinite cache growth of `extraCerts`. + + Severity: Low + + Issue Summary: The OpenSSL Certificate Management Protocol (CMP) caches + additional certificates (`extraCerts`) sent in a CMP message, but never + expunges them (for instance, if they are invalid). If a server reuses + an `OSSL_CMP_CTX` object frequently, this cache of `extraCerts` may grow + unboundedly, and a malicious client may flood a CMP server with requests + driving this growth. + + Impact Summary: Users utilizing a CMP server that reuses a single + `OSSL_CMP_CTX` object for the lifetime of a server process may observe + unbounded memory growth in the event a malicious client repeatedly sends + requests containing unique extra certificates, which may lead to OOM + conditions. + + Reported by: Pavol Zacik (Red Hat). + + ([CVE-2026-63074]) + + *Neil Horman* + + * Fixed QUIC ACK-only packet retention being able to cause memory exhaustion. + + Severity: Low + + Issue Summary: When OpenSSL processes QUIC traffic from a peer + that repeatedly sends ACK-eliciting packets while not acknowledging ACK-only + responses, the QUIC stack can retain ACK-only packet metadata + for the lifetime of the connection. + + Impact Summary: A remote peer that can complete a QUIC handshake can cause + connection-scoped memory growth, which may lead to a Denial of Service + through memory exhaustion, especially with sustained traffic or many + concurrent QUIC connections. + + Reported by: Opal Wright (Trail of Bits). + + ([CVE-2026-63075]) + + *Neil Horman* + + * Fixed possibility of AEAD forgeries with empty ciphertext when using + `EVP_Cipher()`. + + Severity: Low + + Issue summary: ChaCha20-Poly1305 and AES-OCB decryption with an empty + ciphertext can report success without verifying the supplied authentication + tag when the operation is finalized by calling the `EVP_Cipher()` function. + + Impact summary: Applications calling `EVP_Cipher()` on an empty ciphertext + and expecting the call to check the AEAD tag may accept forged messages. + + Reported by: Billy Brumley (Rochester Institute of Technology). + + ([CVE-2026-75803]) + + + *Billy Bob Brumley* + + * Added `OPENSSL_armcap(3)` documentation page. + + + *Paul Elliott* + + * Added support for selecting assembly code paths for LLVM-based Intel's `icx` + compiler. + + + *Wolfgang Beck* + + * Updated compliance with TLS 1.3 session ticket lifetime requirements. + TLS 1.3 clients now cap `ticket_lifetime_hint` to 7 days (604800 seconds) + when processing new session ticket messages, in accordance + with [RFC 8446 Section 4.6.1]. + + + *Abel Thomas* + + * Fixed checking of authentication tags for empty ciphertexts for AEAD ciphers + in CCM cipher mode. + + + *Mounir IDRASSI* + ### Changes between 3.5.6 and 3.5.7 [9 Jun 2026] * Fixed heap use-after-free in `PKCS7_verify()`. @@ -306,6 +537,21 @@ OpenSSL 3.5 *Dmitry Belyavskiy (Red Hat)* + * Fixed excessive allocation of the handshake message buffer (aka HollowByte). + + Previously, we would allocate a buffer large enough to hold the full size of + an incoming handshake message as advertised by the peer. This could be quite + large (although it is bounded, e.g. for ClientHello this is approximately + 128 KiB). If the peer then fails to send the full handshake message, then the + endpoint is left waiting for the remainder of the message to arrive and the + memory is still allocated (i.e. a Slowloris attack). To prevent this, we + incrementally grow the buffer as we receive the data. + + This issue was reported by Okta Red Team. + + + *Matt Caswell* + * Fixed TLS 1.3 server not sending `NewSessionTicket` message after ciphersuite mismatch. @@ -22260,6 +22506,9 @@ ndif [CVE-2026-2673]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-2673 [CVE-2026-7383]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-7383 [CVE-2026-9076]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-9076 +[CVE-2026-14456]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-14456 +[CVE-2026-14457]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-14457 +[CVE-2026-18798]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-18798 [CVE-2026-22795]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-22795 [CVE-2026-22796]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-22796 [CVE-2026-28387]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-28387 @@ -22281,9 +22530,18 @@ ndif [CVE-2026-45445]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-45445 [CVE-2026-45446]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-45446 [CVE-2026-45447]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-45447 +[CVE-2026-54874]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-54874 +[CVE-2026-63072]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-63072 +[CVE-2026-63073]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-63073 +[CVE-2026-63074]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-63074 +[CVE-2026-63075]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-63075 +[CVE-2026-63076]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-63076 +[CVE-2026-75803]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-75803 [ESV]: https://csrc.nist.gov/Projects/cryptographic-module-validation-program/entropy-validations [RFC 2578 (STD 58), section 3.5]: https://datatracker.ietf.org/doc/html/rfc2578#section-3.5 [RFC 3211]: https://datatracker.ietf.org/doc/html/rfc3211 [RFC 5297]: https://datatracker.ietf.org/doc/html/rfc5297 +[RFC 7250]: https://datatracker.ietf.org/doc/html/rfc7250 [RFC 8446]: https://datatracker.ietf.org/doc/html/rfc8446 +[RFC 8446 Section 4.6.1]: https://datatracker.ietf.org/doc/html/rfc8446#section-4.6.1 [RFC 8452]: https://datatracker.ietf.org/doc/html/rfc8452 diff --git a/deps/openssl/openssl/CONTRIBUTING.md b/deps/openssl/openssl/CONTRIBUTING.md index 06dfbaeff1fe..8a0d40524ddb 100644 --- a/deps/openssl/openssl/CONTRIBUTING.md +++ b/deps/openssl/openssl/CONTRIBUTING.md @@ -70,7 +70,37 @@ guidelines: git push -f [ []] ``` - 2. All source files should start with the following text (with + 2. Similarly, if a non-trivial portion of a contribution was created + using an AI tool, you must declare which agent and model were used. + This is done by adding `Assisted-by: {agent}:{model}` below the commit + message: + + ``` + One-line summary of change with AI-generated portions + + Assisted-by: Claude:claude-sonnet-4-6 + ``` + + Multiple Assisted-by trailers can be included if multiple tools were used: + + ``` + Assisted-by: Claude:claude-sonnet-4-6 + Assisted-by: ChatGPT:gpt-4o + Assisted-by: GitHub Copilot:gpt-4.1 + ``` + + You will need to have signed a v1.1 or later CLA in order to + include AI-generated content in your contribution. CLAs signed + after June 2026 will have the requisite clauses. + + Consult the [OpenSSL AI Code and Documentation Contribution + Policy] if an AI model assisted with the creation of your + contribution. + + [OpenSSL AI Code and Documentation Contribution + Policy]: + + 3. All source files should start with the following text (with appropriate comment characters at the start of each line and the year(s) updated): @@ -83,11 +113,11 @@ guidelines: https://www.openssl.org/source/license.html ``` - 3. Patches should be as current as possible; expect to have to rebase + 4. Patches should be as current as possible; expect to have to rebase often. We do not accept merge commits, you will have to remove them (usually by rebasing) before it will be acceptable. - 4. Code provided should follow our [coding style] and [documentation policy] + 5. Code provided should follow our [coding style] and [documentation policy] and compile without warnings. There is a [Perl tool](util/check-format.pl) that helps finding code formatting mistakes and other coding style nits. @@ -100,16 +130,16 @@ guidelines: [coding style]: https://openssl-library.org/policies/technical/coding-style/ [documentation policy]: https://openssl-library.org/policies/technical/documentation-policy/ - 5. When at all possible, code contributions should include tests. These can + 6. When at all possible, code contributions should include tests. These can either be added to an existing test, or completely new. Please see [test/README.md](test/README.md) for information on the test framework. - 6. New features or changed functionality must include + 7. New features or changed functionality must include documentation. Please look at the `.pod` files in `doc/man[1357]` for examples of our style. Run `make doc-nits` to make sure that your documentation changes are clean. - 7. For user visible changes (API changes, behaviour changes, ...), + 8. For user visible changes (API changes, behaviour changes, ...), consider adding a note in [CHANGES.md](CHANGES.md). This could be a summarising description of the change, and could explain the grander details. @@ -120,5 +150,5 @@ guidelines: with a specific release without having to sift through the higher noise ratio in git-log. - 8. Guidelines on how to integrate error output of new crypto library modules + 9. Guidelines on how to integrate error output of new crypto library modules can be found in [crypto/err/README.md](crypto/err/README.md). diff --git a/deps/openssl/openssl/NEWS.md b/deps/openssl/openssl/NEWS.md index 04d0bd72c7f5..329b1772c348 100644 --- a/deps/openssl/openssl/NEWS.md +++ b/deps/openssl/openssl/NEWS.md @@ -23,6 +23,50 @@ OpenSSL Releases OpenSSL 3.5 ----------- +### Major changes between OpenSSL 3.5.7 and OpenSSL 3.5.8 [25 Aug 2026] + +OpenSSL 3.5.8 is a security patch release. The most severe CVE fixed +in this release is Moderate. + +This release incorporates the following bug fixes and mitigations: + + * Fixed QUIC server being able to trigger double free when processing + `INITIAL` packet. + ([CVE-2026-18798]) + + * Fixed heap buffer overflow in CMS key unwrapping. + ([CVE-2026-63072]) + + * Fixed invalid pointer dereference in CMP server via crafted `protectionAlg`. + ([CVE-2026-63076]) + + * Fixed unbounded memory growth in QUIC server incoming channel queue. + ([CVE-2026-14456]) + + * Fixed RPK server signature algorithm selection being able to dereference + a missing certificate. + ([CVE-2026-14457]) + + * Fixed excessive memory use buffering DTLS records for a future epoch. + ([CVE-2026-54874]) + + * Fixed untrusted Sender DN being used as a format string in CMP response + validation. + ([CVE-2026-63073]) + + * Fixed CMP indefinite cache growth of `extraCerts`. + ([CVE-2026-63074]) + + * Fixed QUIC ACK-only packet retention being able to cause memory exhaustion. + ([CVE-2026-63075]) + + * Fixed possibility of AEAD forgeries with empty ciphertext when using + `EVP_Cipher()`. + ([CVE-2026-75803]) + + * Fixed checking of authentication tags for empty ciphertexts for AEAD ciphers + in CCM cipher mode. + ### Major changes between OpenSSL 3.5.6 and OpenSSL 3.5.7 [9 Jun 2026] OpenSSL 3.5.7 is a security patch release. The most severe CVE fixed @@ -78,6 +122,8 @@ This release incorporates the following bug fixes and mitigations: and AES-SIV modes. ([CVE-2026-45446]) + * Fixed excessive allocation of the handshake message buffer (aka HollowByte). + ### Major changes between OpenSSL 3.5.5 and OpenSSL 3.5.6 [7 Apr 2026] OpenSSL 3.5.6 is a security patch release. The most severe CVE fixed in this @@ -2267,6 +2313,9 @@ OpenSSL 0.9.x [CVE-2026-2673]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-2673 [CVE-2026-7383]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-7383 [CVE-2026-9076]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-9076 +[CVE-2026-14456]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-14456 +[CVE-2026-14457]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-14457 +[CVE-2026-18798]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-18798 [CVE-2026-22795]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-22795 [CVE-2026-22796]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-22796 [CVE-2026-28387]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-28387 @@ -2288,6 +2337,13 @@ OpenSSL 0.9.x [CVE-2026-45445]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-45445 [CVE-2026-45446]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-45446 [CVE-2026-45447]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-45447 +[CVE-2026-54874]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-54874 +[CVE-2026-63072]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-63072 +[CVE-2026-63073]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-63073 +[CVE-2026-63074]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-63074 +[CVE-2026-63075]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-63075 +[CVE-2026-63076]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-63076 +[CVE-2026-75803]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-75803 [ESV]: https://csrc.nist.gov/Projects/cryptographic-module-validation-program/entropy-validations [OpenSSL Guide]: https://www.openssl.org/docs/manmaster/man7/ossl-guide-introduction.html [README-QUIC.md]: ./README-QUIC.md diff --git a/deps/openssl/openssl/README-FIPS.md b/deps/openssl/openssl/README-FIPS.md index b31f8c65304b..feb6892a2c47 100644 --- a/deps/openssl/openssl/README-FIPS.md +++ b/deps/openssl/openssl/README-FIPS.md @@ -32,11 +32,15 @@ Installing the FIPS provider ============================ In order to be FIPS compliant you must only use FIPS validated source code. -Refer to for information related to +Refer to for information related to which versions are FIPS validated. The instructions given below build OpenSSL -just using the FIPS validated source code. Any FIPS validated version may be -used with any other openssl library. Please see -To determine which FIPS validated library version may be appropriate for you. +just using the FIPS validated source code. A FIPS provider built from any +validated version may be used together with an OpenSSL library built from any +supported release from OpenSSL 3.0 onwards; provider compatibility is +maintained backward and forward across these releases, including future major +release series, for as long as the module remains supported. Please see + +to determine which FIPS validated library version may be appropriate for you. If you want to use a validated FIPS provider, but also want to use the latest OpenSSL release to build everything else, then refer to the next section. diff --git a/deps/openssl/openssl/VERSION.dat b/deps/openssl/openssl/VERSION.dat index a297eee91e17..bf654c1a7713 100644 --- a/deps/openssl/openssl/VERSION.dat +++ b/deps/openssl/openssl/VERSION.dat @@ -1,7 +1,7 @@ MAJOR=3 MINOR=5 -PATCH=7 +PATCH=8 PRE_RELEASE_TAG= BUILD_METADATA= -RELEASE_DATE="9 Jun 2026" +RELEASE_DATE="25 Aug 2026" SHLIB_VERSION=3 diff --git a/deps/openssl/openssl/apps/lib/apps.c b/deps/openssl/openssl/apps/lib/apps.c index e5a2b162b4ef..29dd6514f6d9 100644 --- a/deps/openssl/openssl/apps/lib/apps.c +++ b/deps/openssl/openssl/apps/lib/apps.c @@ -1688,11 +1688,18 @@ CA_DB *load_index(const char *dbfile, DB_ATTR *db_attr) goto err; #ifndef OPENSSL_NO_POSIX_IO - BIO_get_fp(in, &dbfp); - if (fstat(fileno(dbfp), &dbst) == -1) { - ERR_raise_data(ERR_LIB_SYS, errno, - "calling fstat(%s)", dbfile); - goto err; + if (BIO_get_fp(in, &dbfp) > 0 && dbfp != NULL) { + if (fstat(fileno(dbfp), &dbst) == -1) { + ERR_raise_data(ERR_LIB_SYS, errno, + "calling fstat(%s)", dbfile); + goto err; + } + } else { + if (stat(dbfile, &dbst) == -1) { + ERR_raise_data(ERR_LIB_SYS, errno, + "calling stat(%s)", dbfile); + goto err; + } } #endif @@ -1722,8 +1729,14 @@ CA_DB *load_index(const char *dbfile, DB_ATTR *db_attr) } retdb->dbfname = OPENSSL_strdup(dbfile); - if (retdb->dbfname == NULL) + if (retdb->dbfname == NULL) { + TXT_DB_free(retdb->db); + retdb->db = NULL; + OPENSSL_free(retdb); + retdb = NULL; + ERR_raise_data(ERR_LIB_SYS, errno, "Out of memory while copying filename: %s", dbfile); goto err; + } #ifndef OPENSSL_NO_POSIX_IO retdb->dbst = dbst; diff --git a/deps/openssl/openssl/apps/lib/s_cb.c b/deps/openssl/openssl/apps/lib/s_cb.c index 80b5c6555424..760ad010988b 100644 --- a/deps/openssl/openssl/apps/lib/s_cb.c +++ b/deps/openssl/openssl/apps/lib/s_cb.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -1461,10 +1461,7 @@ static STRINT_PAIR callback_types[] = { { "Signature Algorithm mask", SSL_SECOP_SIGALG_MASK }, { "Certificate chain EE key", SSL_SECOP_EE_KEY }, { "Certificate chain CA key", SSL_SECOP_CA_KEY }, - { "Peer Chain EE key", SSL_SECOP_PEER_EE_KEY }, - { "Peer Chain CA key", SSL_SECOP_PEER_CA_KEY }, { "Certificate chain CA digest", SSL_SECOP_CA_MD }, - { "Peer chain CA digest", SSL_SECOP_PEER_CA_MD }, { "SSL compression", SSL_SECOP_COMPRESSION }, { "Session ticket", SSL_SECOP_TICKET }, { NULL } @@ -1498,7 +1495,6 @@ static int security_callback_debug(const SSL *s, const SSL_CTX *ctx, show_nm = 0; break; case SSL_SECOP_CA_MD: - case SSL_SECOP_PEER_CA_MD: cert_md = 1; break; case SSL_SECOP_SIGALG_SUPPORTED: diff --git a/deps/openssl/openssl/apps/lib/vms_term_sock.c b/deps/openssl/openssl/apps/lib/vms_term_sock.c index faceb05d0145..15bc6665694d 100644 --- a/deps/openssl/openssl/apps/lib/vms_term_sock.c +++ b/deps/openssl/openssl/apps/lib/vms_term_sock.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2026 The OpenSSL Project Authors. All Rights Reserved. * Copyright 2016 VMS Software, Inc. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use @@ -230,6 +230,7 @@ int TerminalSocket(int FunctionCode, int *ReturnSocket) LogMessage("TerminalSocket: SYS$QIO () - %08X", status); close(TerminalSocketPair[0]); close(TerminalSocketPair[1]); + sys$dassgn(TerminalDeviceChan); return TERM_SOCK_FAILURE; } @@ -248,6 +249,7 @@ int TerminalSocket(int FunctionCode, int *ReturnSocket) LogMessage("TerminalSocket: SYS$CANCEL () - %08X", status); close(TerminalSocketPair[0]); close(TerminalSocketPair[1]); + sys$dassgn(TerminalDeviceChan); return TERM_SOCK_FAILURE; } diff --git a/deps/openssl/openssl/apps/s_client.c b/deps/openssl/openssl/apps/s_client.c index 9b88d6dfbc86..b3f333a6993c 100644 --- a/deps/openssl/openssl/apps/s_client.c +++ b/deps/openssl/openssl/apps/s_client.c @@ -2846,11 +2846,9 @@ int s_client_main(int argc, char **argv) } /* * According to RFC 5804 § 2.2, response codes are case- - * insensitive, make it uppercase but preserve the response. + * insensitive. */ - strncpy(sbuf, mbuf, 2); - make_uppercase(sbuf); - if (!HAS_PREFIX(sbuf, "OK")) { + if (OPENSSL_strncasecmp(mbuf, "OK", 2) != 0) { BIO_printf(bio_err, "STARTTLS not supported: %s", mbuf); goto shut; } @@ -3349,29 +3347,32 @@ int s_client_main(int argc, char **argv) print_stuff(bio_c_out, con, full_log); do_ssl_shutdown(con); - /* - * If we ended with an alert being sent, but still with data in the - * network buffer to be read, then calling BIO_closesocket() will - * result in a TCP-RST being sent. On some platforms (notably - * Windows) then this will result in the peer immediately abandoning - * the connection including any buffered alert data before it has - * had a chance to be read. Shutting down the sending side first, - * and then closing the socket sends TCP-FIN first followed by - * TCP-RST. This seems to allow the peer to read the alert data. - */ - shutdown(SSL_get_fd(con), 1); /* SHUT_WR */ - /* - * We just said we have nothing else to say, but it doesn't mean that - * the other side has nothing. It's even recommended to consume incoming - * data. [In testing context this ensures that alerts are passed on...] - */ - timeout.tv_sec = 0; - timeout.tv_usec = 500000; /* some extreme round-trip */ - do { - FD_ZERO(&readfds); - openssl_fdset(sock, &readfds); - } while (select(sock + 1, &readfds, NULL, NULL, &timeout) > 0 - && BIO_read(sbio, sbuf, BUFSIZZ) > 0); + /* The following half-close/drain workaround is TCP-specific. */ + if (!isdtls && !isquic) { + /* + * If we ended with an alert being sent, but still with data in the + * network buffer to be read, then calling BIO_closesocket() will + * result in a TCP-RST being sent. On some platforms (notably + * Windows) then this will result in the peer immediately abandoning + * the connection including any buffered alert data before it has + * had a chance to be read. Shutting down the sending side first, + * and then closing the socket sends TCP-FIN first followed by + * TCP-RST. This seems to allow the peer to read the alert data. + */ + shutdown(SSL_get_fd(con), 1); /* SHUT_WR */ + /* + * We just said we have nothing else to say, but it doesn't mean that + * the other side has nothing. It's even recommended to consume incoming + * data. [In testing context this ensures that alerts are passed on...] + */ + timeout.tv_sec = 0; + timeout.tv_usec = 500000; /* some extreme round-trip */ + do { + FD_ZERO(&readfds); + openssl_fdset(sock, &readfds); + } while (select(sock + 1, &readfds, NULL, NULL, &timeout) > 0 + && BIO_read(sbio, sbuf, BUFSIZZ) > 0); + } BIO_closesocket(SSL_get_fd(con)); end: diff --git a/deps/openssl/openssl/crypto/aes/aes_x86core.c b/deps/openssl/openssl/crypto/aes/aes_x86core.c deleted file mode 100644 index 0fa994871b27..000000000000 --- a/deps/openssl/openssl/crypto/aes/aes_x86core.c +++ /dev/null @@ -1,867 +0,0 @@ -/* - * Copyright 2006-2016 The OpenSSL Project Authors. All Rights Reserved. - * - * Licensed under the Apache License 2.0 (the "License"). You may not use - * this file except in compliance with the License. You can obtain a copy - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -/* - * This is experimental x86[_64] derivative. It assumes little-endian - * byte order and expects CPU to sustain unaligned memory references. - * It is used as playground for cache-time attack mitigations and - * serves as reference C implementation for x86[_64] as well as some - * other assembly modules. - */ - -/** - * rijndael-alg-fst.c - * - * @version 3.0 (December 2000) - * - * Optimised ANSI C code for the Rijndael cipher (now AES) - * - * @author Vincent Rijmen - * @author Antoon Bosselaers - * @author Paulo Barreto - * - * This code is hereby placed in the public domain. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#include -#include -#include "aes_local.h" - -/* - * These two parameters control which table, 256-byte or 2KB, is - * referenced in outer and respectively inner rounds. - */ -#define AES_COMPACT_IN_OUTER_ROUNDS -#ifdef AES_COMPACT_IN_OUTER_ROUNDS -/* AES_COMPACT_IN_OUTER_ROUNDS costs ~30% in performance, while - * adding AES_COMPACT_IN_INNER_ROUNDS reduces benchmark *further* - * by factor of ~2. */ -#undef AES_COMPACT_IN_INNER_ROUNDS -#endif - -#if 1 -static void prefetch256(const void *table) -{ - volatile unsigned long *t = (void *)table, ret; - unsigned long sum; - int i; - - /* 32 is common least cache-line size */ - for (sum = 0, i = 0; i < 256 / sizeof(t[0]); i += 32 / sizeof(t[0])) - sum ^= t[i]; - - ret = sum; -} -#else -#define prefetch256(t) -#endif - -#undef GETU32 -#define GETU32(p) (*((u32 *)(p))) - -#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__) -#define U64(C) C##UI64 -#elif defined(__arch64__) -#define U64(C) C##UL -#else -#define U64(C) C##ULL -#endif - -#undef ROTATE -#if defined(_MSC_VER) -#define ROTATE(a, n) _lrotl(a, n) -#elif defined(__ICC) -#define ROTATE(a, n) _rotl(a, n) -#elif defined(__GNUC__) && __GNUC__ >= 2 -#if defined(__i386) || defined(__i386__) || defined(__x86_64) || defined(__x86_64__) -#define ROTATE(a, n) ({ \ - register unsigned int ret; \ - asm( \ - "roll %1,%0" \ - : "=r"(ret) \ - : "I"(n), "0"(a) \ - : "cc"); \ - ret; \ -}) -#endif -#endif -/*- -Te [x] = S [x].[02, 01, 01, 03, 02, 01, 01, 03]; -Te0[x] = S [x].[02, 01, 01, 03]; -Te1[x] = S [x].[03, 02, 01, 01]; -Te2[x] = S [x].[01, 03, 02, 01]; -Te3[x] = S [x].[01, 01, 03, 02]; -*/ -#define Te0 (u32)((u64 *)((u8 *)Te + 0)) -#define Te1 (u32)((u64 *)((u8 *)Te + 3)) -#define Te2 (u32)((u64 *)((u8 *)Te + 2)) -#define Te3 (u32)((u64 *)((u8 *)Te + 1)) -/*- -Td [x] = Si[x].[0e, 09, 0d, 0b, 0e, 09, 0d, 0b]; -Td0[x] = Si[x].[0e, 09, 0d, 0b]; -Td1[x] = Si[x].[0b, 0e, 09, 0d]; -Td2[x] = Si[x].[0d, 0b, 0e, 09]; -Td3[x] = Si[x].[09, 0d, 0b, 0e]; -Td4[x] = Si[x].[01]; -*/ -#define Td0 (u32)((u64 *)((u8 *)Td + 0)) -#define Td1 (u32)((u64 *)((u8 *)Td + 3)) -#define Td2 (u32)((u64 *)((u8 *)Td + 2)) -#define Td3 (u32)((u64 *)((u8 *)Td + 1)) - -static const u64 Te[256] = { - U64(0xa56363c6a56363c6), U64(0x847c7cf8847c7cf8), - U64(0x997777ee997777ee), U64(0x8d7b7bf68d7b7bf6), - U64(0x0df2f2ff0df2f2ff), U64(0xbd6b6bd6bd6b6bd6), - U64(0xb16f6fdeb16f6fde), U64(0x54c5c59154c5c591), - U64(0x5030306050303060), U64(0x0301010203010102), - U64(0xa96767cea96767ce), U64(0x7d2b2b567d2b2b56), - U64(0x19fefee719fefee7), U64(0x62d7d7b562d7d7b5), - U64(0xe6abab4de6abab4d), U64(0x9a7676ec9a7676ec), - U64(0x45caca8f45caca8f), U64(0x9d82821f9d82821f), - U64(0x40c9c98940c9c989), U64(0x877d7dfa877d7dfa), - U64(0x15fafaef15fafaef), U64(0xeb5959b2eb5959b2), - U64(0xc947478ec947478e), U64(0x0bf0f0fb0bf0f0fb), - U64(0xecadad41ecadad41), U64(0x67d4d4b367d4d4b3), - U64(0xfda2a25ffda2a25f), U64(0xeaafaf45eaafaf45), - U64(0xbf9c9c23bf9c9c23), U64(0xf7a4a453f7a4a453), - U64(0x967272e4967272e4), U64(0x5bc0c09b5bc0c09b), - U64(0xc2b7b775c2b7b775), U64(0x1cfdfde11cfdfde1), - U64(0xae93933dae93933d), U64(0x6a26264c6a26264c), - U64(0x5a36366c5a36366c), U64(0x413f3f7e413f3f7e), - U64(0x02f7f7f502f7f7f5), U64(0x4fcccc834fcccc83), - U64(0x5c3434685c343468), U64(0xf4a5a551f4a5a551), - U64(0x34e5e5d134e5e5d1), U64(0x08f1f1f908f1f1f9), - U64(0x937171e2937171e2), U64(0x73d8d8ab73d8d8ab), - U64(0x5331316253313162), U64(0x3f15152a3f15152a), - U64(0x0c0404080c040408), U64(0x52c7c79552c7c795), - U64(0x6523234665232346), U64(0x5ec3c39d5ec3c39d), - U64(0x2818183028181830), U64(0xa1969637a1969637), - U64(0x0f05050a0f05050a), U64(0xb59a9a2fb59a9a2f), - U64(0x0907070e0907070e), U64(0x3612122436121224), - U64(0x9b80801b9b80801b), U64(0x3de2e2df3de2e2df), - U64(0x26ebebcd26ebebcd), U64(0x6927274e6927274e), - U64(0xcdb2b27fcdb2b27f), U64(0x9f7575ea9f7575ea), - U64(0x1b0909121b090912), U64(0x9e83831d9e83831d), - U64(0x742c2c58742c2c58), U64(0x2e1a1a342e1a1a34), - U64(0x2d1b1b362d1b1b36), U64(0xb26e6edcb26e6edc), - U64(0xee5a5ab4ee5a5ab4), U64(0xfba0a05bfba0a05b), - U64(0xf65252a4f65252a4), U64(0x4d3b3b764d3b3b76), - U64(0x61d6d6b761d6d6b7), U64(0xceb3b37dceb3b37d), - U64(0x7b2929527b292952), U64(0x3ee3e3dd3ee3e3dd), - U64(0x712f2f5e712f2f5e), U64(0x9784841397848413), - U64(0xf55353a6f55353a6), U64(0x68d1d1b968d1d1b9), - U64(0x0000000000000000), U64(0x2cededc12cededc1), - U64(0x6020204060202040), U64(0x1ffcfce31ffcfce3), - U64(0xc8b1b179c8b1b179), U64(0xed5b5bb6ed5b5bb6), - U64(0xbe6a6ad4be6a6ad4), U64(0x46cbcb8d46cbcb8d), - U64(0xd9bebe67d9bebe67), U64(0x4b3939724b393972), - U64(0xde4a4a94de4a4a94), U64(0xd44c4c98d44c4c98), - U64(0xe85858b0e85858b0), U64(0x4acfcf854acfcf85), - U64(0x6bd0d0bb6bd0d0bb), U64(0x2aefefc52aefefc5), - U64(0xe5aaaa4fe5aaaa4f), U64(0x16fbfbed16fbfbed), - U64(0xc5434386c5434386), U64(0xd74d4d9ad74d4d9a), - U64(0x5533336655333366), U64(0x9485851194858511), - U64(0xcf45458acf45458a), U64(0x10f9f9e910f9f9e9), - U64(0x0602020406020204), U64(0x817f7ffe817f7ffe), - U64(0xf05050a0f05050a0), U64(0x443c3c78443c3c78), - U64(0xba9f9f25ba9f9f25), U64(0xe3a8a84be3a8a84b), - U64(0xf35151a2f35151a2), U64(0xfea3a35dfea3a35d), - U64(0xc0404080c0404080), U64(0x8a8f8f058a8f8f05), - U64(0xad92923fad92923f), U64(0xbc9d9d21bc9d9d21), - U64(0x4838387048383870), U64(0x04f5f5f104f5f5f1), - U64(0xdfbcbc63dfbcbc63), U64(0xc1b6b677c1b6b677), - U64(0x75dadaaf75dadaaf), U64(0x6321214263212142), - U64(0x3010102030101020), U64(0x1affffe51affffe5), - U64(0x0ef3f3fd0ef3f3fd), U64(0x6dd2d2bf6dd2d2bf), - U64(0x4ccdcd814ccdcd81), U64(0x140c0c18140c0c18), - U64(0x3513132635131326), U64(0x2fececc32fececc3), - U64(0xe15f5fbee15f5fbe), U64(0xa2979735a2979735), - U64(0xcc444488cc444488), U64(0x3917172e3917172e), - U64(0x57c4c49357c4c493), U64(0xf2a7a755f2a7a755), - U64(0x827e7efc827e7efc), U64(0x473d3d7a473d3d7a), - U64(0xac6464c8ac6464c8), U64(0xe75d5dbae75d5dba), - U64(0x2b1919322b191932), U64(0x957373e6957373e6), - U64(0xa06060c0a06060c0), U64(0x9881811998818119), - U64(0xd14f4f9ed14f4f9e), U64(0x7fdcdca37fdcdca3), - U64(0x6622224466222244), U64(0x7e2a2a547e2a2a54), - U64(0xab90903bab90903b), U64(0x8388880b8388880b), - U64(0xca46468cca46468c), U64(0x29eeeec729eeeec7), - U64(0xd3b8b86bd3b8b86b), U64(0x3c1414283c141428), - U64(0x79dedea779dedea7), U64(0xe25e5ebce25e5ebc), - U64(0x1d0b0b161d0b0b16), U64(0x76dbdbad76dbdbad), - U64(0x3be0e0db3be0e0db), U64(0x5632326456323264), - U64(0x4e3a3a744e3a3a74), U64(0x1e0a0a141e0a0a14), - U64(0xdb494992db494992), U64(0x0a06060c0a06060c), - U64(0x6c2424486c242448), U64(0xe45c5cb8e45c5cb8), - U64(0x5dc2c29f5dc2c29f), U64(0x6ed3d3bd6ed3d3bd), - U64(0xefacac43efacac43), U64(0xa66262c4a66262c4), - U64(0xa8919139a8919139), U64(0xa4959531a4959531), - U64(0x37e4e4d337e4e4d3), U64(0x8b7979f28b7979f2), - U64(0x32e7e7d532e7e7d5), U64(0x43c8c88b43c8c88b), - U64(0x5937376e5937376e), U64(0xb76d6ddab76d6dda), - U64(0x8c8d8d018c8d8d01), U64(0x64d5d5b164d5d5b1), - U64(0xd24e4e9cd24e4e9c), U64(0xe0a9a949e0a9a949), - U64(0xb46c6cd8b46c6cd8), U64(0xfa5656acfa5656ac), - U64(0x07f4f4f307f4f4f3), U64(0x25eaeacf25eaeacf), - U64(0xaf6565caaf6565ca), U64(0x8e7a7af48e7a7af4), - U64(0xe9aeae47e9aeae47), U64(0x1808081018080810), - U64(0xd5baba6fd5baba6f), U64(0x887878f0887878f0), - U64(0x6f25254a6f25254a), U64(0x722e2e5c722e2e5c), - U64(0x241c1c38241c1c38), U64(0xf1a6a657f1a6a657), - U64(0xc7b4b473c7b4b473), U64(0x51c6c69751c6c697), - U64(0x23e8e8cb23e8e8cb), U64(0x7cdddda17cdddda1), - U64(0x9c7474e89c7474e8), U64(0x211f1f3e211f1f3e), - U64(0xdd4b4b96dd4b4b96), U64(0xdcbdbd61dcbdbd61), - U64(0x868b8b0d868b8b0d), U64(0x858a8a0f858a8a0f), - U64(0x907070e0907070e0), U64(0x423e3e7c423e3e7c), - U64(0xc4b5b571c4b5b571), U64(0xaa6666ccaa6666cc), - U64(0xd8484890d8484890), U64(0x0503030605030306), - U64(0x01f6f6f701f6f6f7), U64(0x120e0e1c120e0e1c), - U64(0xa36161c2a36161c2), U64(0x5f35356a5f35356a), - U64(0xf95757aef95757ae), U64(0xd0b9b969d0b9b969), - U64(0x9186861791868617), U64(0x58c1c19958c1c199), - U64(0x271d1d3a271d1d3a), U64(0xb99e9e27b99e9e27), - U64(0x38e1e1d938e1e1d9), U64(0x13f8f8eb13f8f8eb), - U64(0xb398982bb398982b), U64(0x3311112233111122), - U64(0xbb6969d2bb6969d2), U64(0x70d9d9a970d9d9a9), - U64(0x898e8e07898e8e07), U64(0xa7949433a7949433), - U64(0xb69b9b2db69b9b2d), U64(0x221e1e3c221e1e3c), - U64(0x9287871592878715), U64(0x20e9e9c920e9e9c9), - U64(0x49cece8749cece87), U64(0xff5555aaff5555aa), - U64(0x7828285078282850), U64(0x7adfdfa57adfdfa5), - U64(0x8f8c8c038f8c8c03), U64(0xf8a1a159f8a1a159), - U64(0x8089890980898909), U64(0x170d0d1a170d0d1a), - U64(0xdabfbf65dabfbf65), U64(0x31e6e6d731e6e6d7), - U64(0xc6424284c6424284), U64(0xb86868d0b86868d0), - U64(0xc3414182c3414182), U64(0xb0999929b0999929), - U64(0x772d2d5a772d2d5a), U64(0x110f0f1e110f0f1e), - U64(0xcbb0b07bcbb0b07b), U64(0xfc5454a8fc5454a8), - U64(0xd6bbbb6dd6bbbb6d), U64(0x3a16162c3a16162c) -}; - -static const u8 Te4[256] = { - 0x63U, 0x7cU, 0x77U, 0x7bU, 0xf2U, 0x6bU, 0x6fU, 0xc5U, - 0x30U, 0x01U, 0x67U, 0x2bU, 0xfeU, 0xd7U, 0xabU, 0x76U, - 0xcaU, 0x82U, 0xc9U, 0x7dU, 0xfaU, 0x59U, 0x47U, 0xf0U, - 0xadU, 0xd4U, 0xa2U, 0xafU, 0x9cU, 0xa4U, 0x72U, 0xc0U, - 0xb7U, 0xfdU, 0x93U, 0x26U, 0x36U, 0x3fU, 0xf7U, 0xccU, - 0x34U, 0xa5U, 0xe5U, 0xf1U, 0x71U, 0xd8U, 0x31U, 0x15U, - 0x04U, 0xc7U, 0x23U, 0xc3U, 0x18U, 0x96U, 0x05U, 0x9aU, - 0x07U, 0x12U, 0x80U, 0xe2U, 0xebU, 0x27U, 0xb2U, 0x75U, - 0x09U, 0x83U, 0x2cU, 0x1aU, 0x1bU, 0x6eU, 0x5aU, 0xa0U, - 0x52U, 0x3bU, 0xd6U, 0xb3U, 0x29U, 0xe3U, 0x2fU, 0x84U, - 0x53U, 0xd1U, 0x00U, 0xedU, 0x20U, 0xfcU, 0xb1U, 0x5bU, - 0x6aU, 0xcbU, 0xbeU, 0x39U, 0x4aU, 0x4cU, 0x58U, 0xcfU, - 0xd0U, 0xefU, 0xaaU, 0xfbU, 0x43U, 0x4dU, 0x33U, 0x85U, - 0x45U, 0xf9U, 0x02U, 0x7fU, 0x50U, 0x3cU, 0x9fU, 0xa8U, - 0x51U, 0xa3U, 0x40U, 0x8fU, 0x92U, 0x9dU, 0x38U, 0xf5U, - 0xbcU, 0xb6U, 0xdaU, 0x21U, 0x10U, 0xffU, 0xf3U, 0xd2U, - 0xcdU, 0x0cU, 0x13U, 0xecU, 0x5fU, 0x97U, 0x44U, 0x17U, - 0xc4U, 0xa7U, 0x7eU, 0x3dU, 0x64U, 0x5dU, 0x19U, 0x73U, - 0x60U, 0x81U, 0x4fU, 0xdcU, 0x22U, 0x2aU, 0x90U, 0x88U, - 0x46U, 0xeeU, 0xb8U, 0x14U, 0xdeU, 0x5eU, 0x0bU, 0xdbU, - 0xe0U, 0x32U, 0x3aU, 0x0aU, 0x49U, 0x06U, 0x24U, 0x5cU, - 0xc2U, 0xd3U, 0xacU, 0x62U, 0x91U, 0x95U, 0xe4U, 0x79U, - 0xe7U, 0xc8U, 0x37U, 0x6dU, 0x8dU, 0xd5U, 0x4eU, 0xa9U, - 0x6cU, 0x56U, 0xf4U, 0xeaU, 0x65U, 0x7aU, 0xaeU, 0x08U, - 0xbaU, 0x78U, 0x25U, 0x2eU, 0x1cU, 0xa6U, 0xb4U, 0xc6U, - 0xe8U, 0xddU, 0x74U, 0x1fU, 0x4bU, 0xbdU, 0x8bU, 0x8aU, - 0x70U, 0x3eU, 0xb5U, 0x66U, 0x48U, 0x03U, 0xf6U, 0x0eU, - 0x61U, 0x35U, 0x57U, 0xb9U, 0x86U, 0xc1U, 0x1dU, 0x9eU, - 0xe1U, 0xf8U, 0x98U, 0x11U, 0x69U, 0xd9U, 0x8eU, 0x94U, - 0x9bU, 0x1eU, 0x87U, 0xe9U, 0xceU, 0x55U, 0x28U, 0xdfU, - 0x8cU, 0xa1U, 0x89U, 0x0dU, 0xbfU, 0xe6U, 0x42U, 0x68U, - 0x41U, 0x99U, 0x2dU, 0x0fU, 0xb0U, 0x54U, 0xbbU, 0x16U -}; - -static const u64 Td[256] = { - U64(0x50a7f45150a7f451), U64(0x5365417e5365417e), - U64(0xc3a4171ac3a4171a), U64(0x965e273a965e273a), - U64(0xcb6bab3bcb6bab3b), U64(0xf1459d1ff1459d1f), - U64(0xab58faacab58faac), U64(0x9303e34b9303e34b), - U64(0x55fa302055fa3020), U64(0xf66d76adf66d76ad), - U64(0x9176cc889176cc88), U64(0x254c02f5254c02f5), - U64(0xfcd7e54ffcd7e54f), U64(0xd7cb2ac5d7cb2ac5), - U64(0x8044352680443526), U64(0x8fa362b58fa362b5), - U64(0x495ab1de495ab1de), U64(0x671bba25671bba25), - U64(0x980eea45980eea45), U64(0xe1c0fe5de1c0fe5d), - U64(0x02752fc302752fc3), U64(0x12f04c8112f04c81), - U64(0xa397468da397468d), U64(0xc6f9d36bc6f9d36b), - U64(0xe75f8f03e75f8f03), U64(0x959c9215959c9215), - U64(0xeb7a6dbfeb7a6dbf), U64(0xda595295da595295), - U64(0x2d83bed42d83bed4), U64(0xd3217458d3217458), - U64(0x2969e0492969e049), U64(0x44c8c98e44c8c98e), - U64(0x6a89c2756a89c275), U64(0x78798ef478798ef4), - U64(0x6b3e58996b3e5899), U64(0xdd71b927dd71b927), - U64(0xb64fe1beb64fe1be), U64(0x17ad88f017ad88f0), - U64(0x66ac20c966ac20c9), U64(0xb43ace7db43ace7d), - U64(0x184adf63184adf63), U64(0x82311ae582311ae5), - U64(0x6033519760335197), U64(0x457f5362457f5362), - U64(0xe07764b1e07764b1), U64(0x84ae6bbb84ae6bbb), - U64(0x1ca081fe1ca081fe), U64(0x942b08f9942b08f9), - U64(0x5868487058684870), U64(0x19fd458f19fd458f), - U64(0x876cde94876cde94), U64(0xb7f87b52b7f87b52), - U64(0x23d373ab23d373ab), U64(0xe2024b72e2024b72), - U64(0x578f1fe3578f1fe3), U64(0x2aab55662aab5566), - U64(0x0728ebb20728ebb2), U64(0x03c2b52f03c2b52f), - U64(0x9a7bc5869a7bc586), U64(0xa50837d3a50837d3), - U64(0xf2872830f2872830), U64(0xb2a5bf23b2a5bf23), - U64(0xba6a0302ba6a0302), U64(0x5c8216ed5c8216ed), - U64(0x2b1ccf8a2b1ccf8a), U64(0x92b479a792b479a7), - U64(0xf0f207f3f0f207f3), U64(0xa1e2694ea1e2694e), - U64(0xcdf4da65cdf4da65), U64(0xd5be0506d5be0506), - U64(0x1f6234d11f6234d1), U64(0x8afea6c48afea6c4), - U64(0x9d532e349d532e34), U64(0xa055f3a2a055f3a2), - U64(0x32e18a0532e18a05), U64(0x75ebf6a475ebf6a4), - U64(0x39ec830b39ec830b), U64(0xaaef6040aaef6040), - U64(0x069f715e069f715e), U64(0x51106ebd51106ebd), - U64(0xf98a213ef98a213e), U64(0x3d06dd963d06dd96), - U64(0xae053eddae053edd), U64(0x46bde64d46bde64d), - U64(0xb58d5491b58d5491), U64(0x055dc471055dc471), - U64(0x6fd406046fd40604), U64(0xff155060ff155060), - U64(0x24fb981924fb9819), U64(0x97e9bdd697e9bdd6), - U64(0xcc434089cc434089), U64(0x779ed967779ed967), - U64(0xbd42e8b0bd42e8b0), U64(0x888b8907888b8907), - U64(0x385b19e7385b19e7), U64(0xdbeec879dbeec879), - U64(0x470a7ca1470a7ca1), U64(0xe90f427ce90f427c), - U64(0xc91e84f8c91e84f8), U64(0x0000000000000000), - U64(0x8386800983868009), U64(0x48ed2b3248ed2b32), - U64(0xac70111eac70111e), U64(0x4e725a6c4e725a6c), - U64(0xfbff0efdfbff0efd), U64(0x5638850f5638850f), - U64(0x1ed5ae3d1ed5ae3d), U64(0x27392d3627392d36), - U64(0x64d90f0a64d90f0a), U64(0x21a65c6821a65c68), - U64(0xd1545b9bd1545b9b), U64(0x3a2e36243a2e3624), - U64(0xb1670a0cb1670a0c), U64(0x0fe757930fe75793), - U64(0xd296eeb4d296eeb4), U64(0x9e919b1b9e919b1b), - U64(0x4fc5c0804fc5c080), U64(0xa220dc61a220dc61), - U64(0x694b775a694b775a), U64(0x161a121c161a121c), - U64(0x0aba93e20aba93e2), U64(0xe52aa0c0e52aa0c0), - U64(0x43e0223c43e0223c), U64(0x1d171b121d171b12), - U64(0x0b0d090e0b0d090e), U64(0xadc78bf2adc78bf2), - U64(0xb9a8b62db9a8b62d), U64(0xc8a91e14c8a91e14), - U64(0x8519f1578519f157), U64(0x4c0775af4c0775af), - U64(0xbbdd99eebbdd99ee), U64(0xfd607fa3fd607fa3), - U64(0x9f2601f79f2601f7), U64(0xbcf5725cbcf5725c), - U64(0xc53b6644c53b6644), U64(0x347efb5b347efb5b), - U64(0x7629438b7629438b), U64(0xdcc623cbdcc623cb), - U64(0x68fcedb668fcedb6), U64(0x63f1e4b863f1e4b8), - U64(0xcadc31d7cadc31d7), U64(0x1085634210856342), - U64(0x4022971340229713), U64(0x2011c6842011c684), - U64(0x7d244a857d244a85), U64(0xf83dbbd2f83dbbd2), - U64(0x1132f9ae1132f9ae), U64(0x6da129c76da129c7), - U64(0x4b2f9e1d4b2f9e1d), U64(0xf330b2dcf330b2dc), - U64(0xec52860dec52860d), U64(0xd0e3c177d0e3c177), - U64(0x6c16b32b6c16b32b), U64(0x99b970a999b970a9), - U64(0xfa489411fa489411), U64(0x2264e9472264e947), - U64(0xc48cfca8c48cfca8), U64(0x1a3ff0a01a3ff0a0), - U64(0xd82c7d56d82c7d56), U64(0xef903322ef903322), - U64(0xc74e4987c74e4987), U64(0xc1d138d9c1d138d9), - U64(0xfea2ca8cfea2ca8c), U64(0x360bd498360bd498), - U64(0xcf81f5a6cf81f5a6), U64(0x28de7aa528de7aa5), - U64(0x268eb7da268eb7da), U64(0xa4bfad3fa4bfad3f), - U64(0xe49d3a2ce49d3a2c), U64(0x0d9278500d927850), - U64(0x9bcc5f6a9bcc5f6a), U64(0x62467e5462467e54), - U64(0xc2138df6c2138df6), U64(0xe8b8d890e8b8d890), - U64(0x5ef7392e5ef7392e), U64(0xf5afc382f5afc382), - U64(0xbe805d9fbe805d9f), U64(0x7c93d0697c93d069), - U64(0xa92dd56fa92dd56f), U64(0xb31225cfb31225cf), - U64(0x3b99acc83b99acc8), U64(0xa77d1810a77d1810), - U64(0x6e639ce86e639ce8), U64(0x7bbb3bdb7bbb3bdb), - U64(0x097826cd097826cd), U64(0xf418596ef418596e), - U64(0x01b79aec01b79aec), U64(0xa89a4f83a89a4f83), - U64(0x656e95e6656e95e6), U64(0x7ee6ffaa7ee6ffaa), - U64(0x08cfbc2108cfbc21), U64(0xe6e815efe6e815ef), - U64(0xd99be7bad99be7ba), U64(0xce366f4ace366f4a), - U64(0xd4099fead4099fea), U64(0xd67cb029d67cb029), - U64(0xafb2a431afb2a431), U64(0x31233f2a31233f2a), - U64(0x3094a5c63094a5c6), U64(0xc066a235c066a235), - U64(0x37bc4e7437bc4e74), U64(0xa6ca82fca6ca82fc), - U64(0xb0d090e0b0d090e0), U64(0x15d8a73315d8a733), - U64(0x4a9804f14a9804f1), U64(0xf7daec41f7daec41), - U64(0x0e50cd7f0e50cd7f), U64(0x2ff691172ff69117), - U64(0x8dd64d768dd64d76), U64(0x4db0ef434db0ef43), - U64(0x544daacc544daacc), U64(0xdf0496e4df0496e4), - U64(0xe3b5d19ee3b5d19e), U64(0x1b886a4c1b886a4c), - U64(0xb81f2cc1b81f2cc1), U64(0x7f5165467f516546), - U64(0x04ea5e9d04ea5e9d), U64(0x5d358c015d358c01), - U64(0x737487fa737487fa), U64(0x2e410bfb2e410bfb), - U64(0x5a1d67b35a1d67b3), U64(0x52d2db9252d2db92), - U64(0x335610e9335610e9), U64(0x1347d66d1347d66d), - U64(0x8c61d79a8c61d79a), U64(0x7a0ca1377a0ca137), - U64(0x8e14f8598e14f859), U64(0x893c13eb893c13eb), - U64(0xee27a9ceee27a9ce), U64(0x35c961b735c961b7), - U64(0xede51ce1ede51ce1), U64(0x3cb1477a3cb1477a), - U64(0x59dfd29c59dfd29c), U64(0x3f73f2553f73f255), - U64(0x79ce141879ce1418), U64(0xbf37c773bf37c773), - U64(0xeacdf753eacdf753), U64(0x5baafd5f5baafd5f), - U64(0x146f3ddf146f3ddf), U64(0x86db447886db4478), - U64(0x81f3afca81f3afca), U64(0x3ec468b93ec468b9), - U64(0x2c3424382c342438), U64(0x5f40a3c25f40a3c2), - U64(0x72c31d1672c31d16), U64(0x0c25e2bc0c25e2bc), - U64(0x8b493c288b493c28), U64(0x41950dff41950dff), - U64(0x7101a8397101a839), U64(0xdeb30c08deb30c08), - U64(0x9ce4b4d89ce4b4d8), U64(0x90c1566490c15664), - U64(0x6184cb7b6184cb7b), U64(0x70b632d570b632d5), - U64(0x745c6c48745c6c48), U64(0x4257b8d04257b8d0) -}; -static const u8 Td4[256] = { - 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, - 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, - 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, - 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, - 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, - 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU, - 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U, - 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, - 0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, - 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U, - 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, - 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, - 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, - 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U, - 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, - 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, - 0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU, - 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U, - 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, - 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU, - 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U, - 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, - 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, - 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, - 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U, - 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, - 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, - 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU, - 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U, - 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, - 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, - 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU -}; - -static const u32 rcon[] = { - 0x00000001U, - 0x00000002U, - 0x00000004U, - 0x00000008U, - 0x00000010U, - 0x00000020U, - 0x00000040U, - 0x00000080U, - 0x0000001bU, - 0x00000036U, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ -}; - -/** - * Expand the cipher key into the encryption key schedule. - */ -int AES_set_encrypt_key(const unsigned char *userKey, const int bits, - AES_KEY *key) -{ - - u32 *rk; - int i = 0; - u32 temp; - - if (!userKey || !key) - return -1; - if (bits != 128 && bits != 192 && bits != 256) - return -2; - - rk = key->rd_key; - - if (bits == 128) - key->rounds = 10; - else if (bits == 192) - key->rounds = 12; - else - key->rounds = 14; - - rk[0] = GETU32(userKey); - rk[1] = GETU32(userKey + 4); - rk[2] = GETU32(userKey + 8); - rk[3] = GETU32(userKey + 12); - if (bits == 128) { - while (1) { - temp = rk[3]; - rk[4] = rk[0] ^ ((u32)Te4[(temp >> 8) & 0xff]) ^ ((u32)Te4[(temp >> 16) & 0xff] << 8) ^ ((u32)Te4[(temp >> 24)] << 16) ^ ((u32)Te4[(temp) & 0xff] << 24) ^ rcon[i]; - rk[5] = rk[1] ^ rk[4]; - rk[6] = rk[2] ^ rk[5]; - rk[7] = rk[3] ^ rk[6]; - if (++i == 10) { - return 0; - } - rk += 4; - } - } - rk[4] = GETU32(userKey + 16); - rk[5] = GETU32(userKey + 20); - if (bits == 192) { - while (1) { - temp = rk[5]; - rk[6] = rk[0] ^ ((u32)Te4[(temp >> 8) & 0xff]) ^ ((u32)Te4[(temp >> 16) & 0xff] << 8) ^ ((u32)Te4[(temp >> 24)] << 16) ^ ((u32)Te4[(temp) & 0xff] << 24) ^ rcon[i]; - rk[7] = rk[1] ^ rk[6]; - rk[8] = rk[2] ^ rk[7]; - rk[9] = rk[3] ^ rk[8]; - if (++i == 8) { - return 0; - } - rk[10] = rk[4] ^ rk[9]; - rk[11] = rk[5] ^ rk[10]; - rk += 6; - } - } - rk[6] = GETU32(userKey + 24); - rk[7] = GETU32(userKey + 28); - if (bits == 256) { - while (1) { - temp = rk[7]; - rk[8] = rk[0] ^ ((u32)Te4[(temp >> 8) & 0xff]) ^ ((u32)Te4[(temp >> 16) & 0xff] << 8) ^ ((u32)Te4[(temp >> 24)] << 16) ^ ((u32)Te4[(temp) & 0xff] << 24) ^ rcon[i]; - rk[9] = rk[1] ^ rk[8]; - rk[10] = rk[2] ^ rk[9]; - rk[11] = rk[3] ^ rk[10]; - if (++i == 7) { - return 0; - } - temp = rk[11]; - rk[12] = rk[4] ^ ((u32)Te4[(temp) & 0xff]) ^ ((u32)Te4[(temp >> 8) & 0xff] << 8) ^ ((u32)Te4[(temp >> 16) & 0xff] << 16) ^ ((u32)Te4[(temp >> 24)] << 24); - rk[13] = rk[5] ^ rk[12]; - rk[14] = rk[6] ^ rk[13]; - rk[15] = rk[7] ^ rk[14]; - - rk += 8; - } - } - return 0; -} - -/** - * Expand the cipher key into the decryption key schedule. - */ -int AES_set_decrypt_key(const unsigned char *userKey, const int bits, - AES_KEY *key) -{ - - u32 *rk; - int i, j, status; - u32 temp; - - /* first, start with an encryption schedule */ - status = AES_set_encrypt_key(userKey, bits, key); - if (status < 0) - return status; - - rk = key->rd_key; - - /* invert the order of the round keys: */ - for (i = 0, j = 4 * (key->rounds); i < j; i += 4, j -= 4) { - temp = rk[i]; - rk[i] = rk[j]; - rk[j] = temp; - temp = rk[i + 1]; - rk[i + 1] = rk[j + 1]; - rk[j + 1] = temp; - temp = rk[i + 2]; - rk[i + 2] = rk[j + 2]; - rk[j + 2] = temp; - temp = rk[i + 3]; - rk[i + 3] = rk[j + 3]; - rk[j + 3] = temp; - } - /* apply the inverse MixColumn transform to all round keys but the first and the last: */ - for (i = 1; i < (key->rounds); i++) { - rk += 4; -#if 1 - for (j = 0; j < 4; j++) { - u32 tp1, tp2, tp4, tp8, tp9, tpb, tpd, tpe, m; - - tp1 = rk[j]; - m = tp1 & 0x80808080; - tp2 = ((tp1 & 0x7f7f7f7f) << 1) ^ ((m - (m >> 7)) & 0x1b1b1b1b); - m = tp2 & 0x80808080; - tp4 = ((tp2 & 0x7f7f7f7f) << 1) ^ ((m - (m >> 7)) & 0x1b1b1b1b); - m = tp4 & 0x80808080; - tp8 = ((tp4 & 0x7f7f7f7f) << 1) ^ ((m - (m >> 7)) & 0x1b1b1b1b); - tp9 = tp8 ^ tp1; - tpb = tp9 ^ tp2; - tpd = tp9 ^ tp4; - tpe = tp8 ^ tp4 ^ tp2; -#if defined(ROTATE) - rk[j] = tpe ^ ROTATE(tpd, 16) ^ ROTATE(tp9, 8) ^ ROTATE(tpb, 24); -#else - rk[j] = tpe ^ (tpd >> 16) ^ (tpd << 16) ^ (tp9 >> 24) ^ (tp9 << 8) ^ (tpb >> 8) ^ (tpb << 24); -#endif - } -#else - rk[0] = Td0[Te2[(rk[0]) & 0xff] & 0xff] ^ Td1[Te2[(rk[0] >> 8) & 0xff] & 0xff] ^ Td2[Te2[(rk[0] >> 16) & 0xff] & 0xff] ^ Td3[Te2[(rk[0] >> 24)] & 0xff]; - rk[1] = Td0[Te2[(rk[1]) & 0xff] & 0xff] ^ Td1[Te2[(rk[1] >> 8) & 0xff] & 0xff] ^ Td2[Te2[(rk[1] >> 16) & 0xff] & 0xff] ^ Td3[Te2[(rk[1] >> 24)] & 0xff]; - rk[2] = Td0[Te2[(rk[2]) & 0xff] & 0xff] ^ Td1[Te2[(rk[2] >> 8) & 0xff] & 0xff] ^ Td2[Te2[(rk[2] >> 16) & 0xff] & 0xff] ^ Td3[Te2[(rk[2] >> 24)] & 0xff]; - rk[3] = Td0[Te2[(rk[3]) & 0xff] & 0xff] ^ Td1[Te2[(rk[3] >> 8) & 0xff] & 0xff] ^ Td2[Te2[(rk[3] >> 16) & 0xff] & 0xff] ^ Td3[Te2[(rk[3] >> 24)] & 0xff]; -#endif - } - return 0; -} - -/* - * Encrypt a single block - * in and out can overlap - */ -void AES_encrypt(const unsigned char *in, unsigned char *out, - const AES_KEY *key) -{ - - const u32 *rk; - u32 s0, s1, s2, s3, t[4]; - int r; - - assert(in && out && key); - rk = key->rd_key; - - /* - * map byte array block to cipher state - * and add initial round key: - */ - s0 = GETU32(in) ^ rk[0]; - s1 = GETU32(in + 4) ^ rk[1]; - s2 = GETU32(in + 8) ^ rk[2]; - s3 = GETU32(in + 12) ^ rk[3]; - -#if defined(AES_COMPACT_IN_OUTER_ROUNDS) - prefetch256(Te4); - - t[0] = (u32)Te4[(s0) & 0xff] ^ (u32)Te4[(s1 >> 8) & 0xff] << 8 ^ (u32)Te4[(s2 >> 16) & 0xff] << 16 ^ (u32)Te4[(s3 >> 24)] << 24; - t[1] = (u32)Te4[(s1) & 0xff] ^ (u32)Te4[(s2 >> 8) & 0xff] << 8 ^ (u32)Te4[(s3 >> 16) & 0xff] << 16 ^ (u32)Te4[(s0 >> 24)] << 24; - t[2] = (u32)Te4[(s2) & 0xff] ^ (u32)Te4[(s3 >> 8) & 0xff] << 8 ^ (u32)Te4[(s0 >> 16) & 0xff] << 16 ^ (u32)Te4[(s1 >> 24)] << 24; - t[3] = (u32)Te4[(s3) & 0xff] ^ (u32)Te4[(s0 >> 8) & 0xff] << 8 ^ (u32)Te4[(s1 >> 16) & 0xff] << 16 ^ (u32)Te4[(s2 >> 24)] << 24; - - /* now do the linear transform using words */ - { - int i; - u32 r0, r1, r2; - - for (i = 0; i < 4; i++) { - r0 = t[i]; - r1 = r0 & 0x80808080; - r2 = ((r0 & 0x7f7f7f7f) << 1) ^ ((r1 - (r1 >> 7)) & 0x1b1b1b1b); -#if defined(ROTATE) - t[i] = r2 ^ ROTATE(r2, 24) ^ ROTATE(r0, 24) ^ ROTATE(r0, 16) ^ ROTATE(r0, 8); -#else - t[i] = r2 ^ ((r2 ^ r0) << 24) ^ ((r2 ^ r0) >> 8) ^ (r0 << 16) ^ (r0 >> 16) ^ (r0 << 8) ^ (r0 >> 24); -#endif - t[i] ^= rk[4 + i]; - } - } -#else - t[0] = Te0[(s0) & 0xff] ^ Te1[(s1 >> 8) & 0xff] ^ Te2[(s2 >> 16) & 0xff] ^ Te3[(s3 >> 24)] ^ rk[4]; - t[1] = Te0[(s1) & 0xff] ^ Te1[(s2 >> 8) & 0xff] ^ Te2[(s3 >> 16) & 0xff] ^ Te3[(s0 >> 24)] ^ rk[5]; - t[2] = Te0[(s2) & 0xff] ^ Te1[(s3 >> 8) & 0xff] ^ Te2[(s0 >> 16) & 0xff] ^ Te3[(s1 >> 24)] ^ rk[6]; - t[3] = Te0[(s3) & 0xff] ^ Te1[(s0 >> 8) & 0xff] ^ Te2[(s1 >> 16) & 0xff] ^ Te3[(s2 >> 24)] ^ rk[7]; -#endif - s0 = t[0]; - s1 = t[1]; - s2 = t[2]; - s3 = t[3]; - - /* - * Nr - 2 full rounds: - */ - for (rk += 8, r = key->rounds - 2; r > 0; rk += 4, r--) { -#if defined(AES_COMPACT_IN_INNER_ROUNDS) - t[0] = (u32)Te4[(s0) & 0xff] ^ (u32)Te4[(s1 >> 8) & 0xff] << 8 ^ (u32)Te4[(s2 >> 16) & 0xff] << 16 ^ (u32)Te4[(s3 >> 24)] << 24; - t[1] = (u32)Te4[(s1) & 0xff] ^ (u32)Te4[(s2 >> 8) & 0xff] << 8 ^ (u32)Te4[(s3 >> 16) & 0xff] << 16 ^ (u32)Te4[(s0 >> 24)] << 24; - t[2] = (u32)Te4[(s2) & 0xff] ^ (u32)Te4[(s3 >> 8) & 0xff] << 8 ^ (u32)Te4[(s0 >> 16) & 0xff] << 16 ^ (u32)Te4[(s1 >> 24)] << 24; - t[3] = (u32)Te4[(s3) & 0xff] ^ (u32)Te4[(s0 >> 8) & 0xff] << 8 ^ (u32)Te4[(s1 >> 16) & 0xff] << 16 ^ (u32)Te4[(s2 >> 24)] << 24; - - /* now do the linear transform using words */ - { - int i; - u32 r0, r1, r2; - - for (i = 0; i < 4; i++) { - r0 = t[i]; - r1 = r0 & 0x80808080; - r2 = ((r0 & 0x7f7f7f7f) << 1) ^ ((r1 - (r1 >> 7)) & 0x1b1b1b1b); -#if defined(ROTATE) - t[i] = r2 ^ ROTATE(r2, 24) ^ ROTATE(r0, 24) ^ ROTATE(r0, 16) ^ ROTATE(r0, 8); -#else - t[i] = r2 ^ ((r2 ^ r0) << 24) ^ ((r2 ^ r0) >> 8) ^ (r0 << 16) ^ (r0 >> 16) ^ (r0 << 8) ^ (r0 >> 24); -#endif - t[i] ^= rk[i]; - } - } -#else - t[0] = Te0[(s0) & 0xff] ^ Te1[(s1 >> 8) & 0xff] ^ Te2[(s2 >> 16) & 0xff] ^ Te3[(s3 >> 24)] ^ rk[0]; - t[1] = Te0[(s1) & 0xff] ^ Te1[(s2 >> 8) & 0xff] ^ Te2[(s3 >> 16) & 0xff] ^ Te3[(s0 >> 24)] ^ rk[1]; - t[2] = Te0[(s2) & 0xff] ^ Te1[(s3 >> 8) & 0xff] ^ Te2[(s0 >> 16) & 0xff] ^ Te3[(s1 >> 24)] ^ rk[2]; - t[3] = Te0[(s3) & 0xff] ^ Te1[(s0 >> 8) & 0xff] ^ Te2[(s1 >> 16) & 0xff] ^ Te3[(s2 >> 24)] ^ rk[3]; -#endif - s0 = t[0]; - s1 = t[1]; - s2 = t[2]; - s3 = t[3]; - } - /* - * apply last round and - * map cipher state to byte array block: - */ -#if defined(AES_COMPACT_IN_OUTER_ROUNDS) - prefetch256(Te4); - - *(u32 *)(out + 0) = (u32)Te4[(s0) & 0xff] ^ (u32)Te4[(s1 >> 8) & 0xff] << 8 ^ (u32)Te4[(s2 >> 16) & 0xff] << 16 ^ (u32)Te4[(s3 >> 24)] << 24 ^ rk[0]; - *(u32 *)(out + 4) = (u32)Te4[(s1) & 0xff] ^ (u32)Te4[(s2 >> 8) & 0xff] << 8 ^ (u32)Te4[(s3 >> 16) & 0xff] << 16 ^ (u32)Te4[(s0 >> 24)] << 24 ^ rk[1]; - *(u32 *)(out + 8) = (u32)Te4[(s2) & 0xff] ^ (u32)Te4[(s3 >> 8) & 0xff] << 8 ^ (u32)Te4[(s0 >> 16) & 0xff] << 16 ^ (u32)Te4[(s1 >> 24)] << 24 ^ rk[2]; - *(u32 *)(out + 12) = (u32)Te4[(s3) & 0xff] ^ (u32)Te4[(s0 >> 8) & 0xff] << 8 ^ (u32)Te4[(s1 >> 16) & 0xff] << 16 ^ (u32)Te4[(s2 >> 24)] << 24 ^ rk[3]; -#else - *(u32 *)(out + 0) = (Te2[(s0) & 0xff] & 0x000000ffU) ^ (Te3[(s1 >> 8) & 0xff] & 0x0000ff00U) ^ (Te0[(s2 >> 16) & 0xff] & 0x00ff0000U) ^ (Te1[(s3 >> 24)] & 0xff000000U) ^ rk[0]; - *(u32 *)(out + 4) = (Te2[(s1) & 0xff] & 0x000000ffU) ^ (Te3[(s2 >> 8) & 0xff] & 0x0000ff00U) ^ (Te0[(s3 >> 16) & 0xff] & 0x00ff0000U) ^ (Te1[(s0 >> 24)] & 0xff000000U) ^ rk[1]; - *(u32 *)(out + 8) = (Te2[(s2) & 0xff] & 0x000000ffU) ^ (Te3[(s3 >> 8) & 0xff] & 0x0000ff00U) ^ (Te0[(s0 >> 16) & 0xff] & 0x00ff0000U) ^ (Te1[(s1 >> 24)] & 0xff000000U) ^ rk[2]; - *(u32 *)(out + 12) = (Te2[(s3) & 0xff] & 0x000000ffU) ^ (Te3[(s0 >> 8) & 0xff] & 0x0000ff00U) ^ (Te0[(s1 >> 16) & 0xff] & 0x00ff0000U) ^ (Te1[(s2 >> 24)] & 0xff000000U) ^ rk[3]; -#endif -} - -/* - * Decrypt a single block - * in and out can overlap - */ -void AES_decrypt(const unsigned char *in, unsigned char *out, - const AES_KEY *key) -{ - - const u32 *rk; - u32 s0, s1, s2, s3, t[4]; - int r; - - assert(in && out && key); - rk = key->rd_key; - - /* - * map byte array block to cipher state - * and add initial round key: - */ - s0 = GETU32(in) ^ rk[0]; - s1 = GETU32(in + 4) ^ rk[1]; - s2 = GETU32(in + 8) ^ rk[2]; - s3 = GETU32(in + 12) ^ rk[3]; - -#if defined(AES_COMPACT_IN_OUTER_ROUNDS) - prefetch256(Td4); - - t[0] = (u32)Td4[(s0) & 0xff] ^ (u32)Td4[(s3 >> 8) & 0xff] << 8 ^ (u32)Td4[(s2 >> 16) & 0xff] << 16 ^ (u32)Td4[(s1 >> 24)] << 24; - t[1] = (u32)Td4[(s1) & 0xff] ^ (u32)Td4[(s0 >> 8) & 0xff] << 8 ^ (u32)Td4[(s3 >> 16) & 0xff] << 16 ^ (u32)Td4[(s2 >> 24)] << 24; - t[2] = (u32)Td4[(s2) & 0xff] ^ (u32)Td4[(s1 >> 8) & 0xff] << 8 ^ (u32)Td4[(s0 >> 16) & 0xff] << 16 ^ (u32)Td4[(s3 >> 24)] << 24; - t[3] = (u32)Td4[(s3) & 0xff] ^ (u32)Td4[(s2 >> 8) & 0xff] << 8 ^ (u32)Td4[(s1 >> 16) & 0xff] << 16 ^ (u32)Td4[(s0 >> 24)] << 24; - - /* now do the linear transform using words */ - { - int i; - u32 tp1, tp2, tp4, tp8, tp9, tpb, tpd, tpe, m; - - for (i = 0; i < 4; i++) { - tp1 = t[i]; - m = tp1 & 0x80808080; - tp2 = ((tp1 & 0x7f7f7f7f) << 1) ^ ((m - (m >> 7)) & 0x1b1b1b1b); - m = tp2 & 0x80808080; - tp4 = ((tp2 & 0x7f7f7f7f) << 1) ^ ((m - (m >> 7)) & 0x1b1b1b1b); - m = tp4 & 0x80808080; - tp8 = ((tp4 & 0x7f7f7f7f) << 1) ^ ((m - (m >> 7)) & 0x1b1b1b1b); - tp9 = tp8 ^ tp1; - tpb = tp9 ^ tp2; - tpd = tp9 ^ tp4; - tpe = tp8 ^ tp4 ^ tp2; -#if defined(ROTATE) - t[i] = tpe ^ ROTATE(tpd, 16) ^ ROTATE(tp9, 8) ^ ROTATE(tpb, 24); -#else - t[i] = tpe ^ (tpd >> 16) ^ (tpd << 16) ^ (tp9 >> 24) ^ (tp9 << 8) ^ (tpb >> 8) ^ (tpb << 24); -#endif - t[i] ^= rk[4 + i]; - } - } -#else - t[0] = Td0[(s0) & 0xff] ^ Td1[(s3 >> 8) & 0xff] ^ Td2[(s2 >> 16) & 0xff] ^ Td3[(s1 >> 24)] ^ rk[4]; - t[1] = Td0[(s1) & 0xff] ^ Td1[(s0 >> 8) & 0xff] ^ Td2[(s3 >> 16) & 0xff] ^ Td3[(s2 >> 24)] ^ rk[5]; - t[2] = Td0[(s2) & 0xff] ^ Td1[(s1 >> 8) & 0xff] ^ Td2[(s0 >> 16) & 0xff] ^ Td3[(s3 >> 24)] ^ rk[6]; - t[3] = Td0[(s3) & 0xff] ^ Td1[(s2 >> 8) & 0xff] ^ Td2[(s1 >> 16) & 0xff] ^ Td3[(s0 >> 24)] ^ rk[7]; -#endif - s0 = t[0]; - s1 = t[1]; - s2 = t[2]; - s3 = t[3]; - - /* - * Nr - 2 full rounds: - */ - for (rk += 8, r = key->rounds - 2; r > 0; rk += 4, r--) { -#if defined(AES_COMPACT_IN_INNER_ROUNDS) - t[0] = (u32)Td4[(s0) & 0xff] ^ (u32)Td4[(s3 >> 8) & 0xff] << 8 ^ (u32)Td4[(s2 >> 16) & 0xff] << 16 ^ (u32)Td4[(s1 >> 24)] << 24; - t[1] = (u32)Td4[(s1) & 0xff] ^ (u32)Td4[(s0 >> 8) & 0xff] << 8 ^ (u32)Td4[(s3 >> 16) & 0xff] << 16 ^ (u32)Td4[(s2 >> 24)] << 24; - t[2] = (u32)Td4[(s2) & 0xff] ^ (u32)Td4[(s1 >> 8) & 0xff] << 8 ^ (u32)Td4[(s0 >> 16) & 0xff] << 16 ^ (u32)Td4[(s3 >> 24)] << 24; - t[3] = (u32)Td4[(s3) & 0xff] ^ (u32)Td4[(s2 >> 8) & 0xff] << 8 ^ (u32)Td4[(s1 >> 16) & 0xff] << 16 ^ (u32)Td4[(s0 >> 24)] << 24; - - /* now do the linear transform using words */ - { - int i; - u32 tp1, tp2, tp4, tp8, tp9, tpb, tpd, tpe, m; - - for (i = 0; i < 4; i++) { - tp1 = t[i]; - m = tp1 & 0x80808080; - tp2 = ((tp1 & 0x7f7f7f7f) << 1) ^ ((m - (m >> 7)) & 0x1b1b1b1b); - m = tp2 & 0x80808080; - tp4 = ((tp2 & 0x7f7f7f7f) << 1) ^ ((m - (m >> 7)) & 0x1b1b1b1b); - m = tp4 & 0x80808080; - tp8 = ((tp4 & 0x7f7f7f7f) << 1) ^ ((m - (m >> 7)) & 0x1b1b1b1b); - tp9 = tp8 ^ tp1; - tpb = tp9 ^ tp2; - tpd = tp9 ^ tp4; - tpe = tp8 ^ tp4 ^ tp2; -#if defined(ROTATE) - t[i] = tpe ^ ROTATE(tpd, 16) ^ ROTATE(tp9, 8) ^ ROTATE(tpb, 24); -#else - t[i] = tpe ^ (tpd >> 16) ^ (tpd << 16) ^ (tp9 >> 24) ^ (tp9 << 8) ^ (tpb >> 8) ^ (tpb << 24); -#endif - t[i] ^= rk[i]; - } - } -#else - t[0] = Td0[(s0) & 0xff] ^ Td1[(s3 >> 8) & 0xff] ^ Td2[(s2 >> 16) & 0xff] ^ Td3[(s1 >> 24)] ^ rk[0]; - t[1] = Td0[(s1) & 0xff] ^ Td1[(s0 >> 8) & 0xff] ^ Td2[(s3 >> 16) & 0xff] ^ Td3[(s2 >> 24)] ^ rk[1]; - t[2] = Td0[(s2) & 0xff] ^ Td1[(s1 >> 8) & 0xff] ^ Td2[(s0 >> 16) & 0xff] ^ Td3[(s3 >> 24)] ^ rk[2]; - t[3] = Td0[(s3) & 0xff] ^ Td1[(s2 >> 8) & 0xff] ^ Td2[(s1 >> 16) & 0xff] ^ Td3[(s0 >> 24)] ^ rk[3]; -#endif - s0 = t[0]; - s1 = t[1]; - s2 = t[2]; - s3 = t[3]; - } - /* - * apply last round and - * map cipher state to byte array block: - */ - prefetch256(Td4); - - *(u32 *)(out + 0) = ((u32)Td4[(s0) & 0xff]) ^ ((u32)Td4[(s3 >> 8) & 0xff] << 8) ^ ((u32)Td4[(s2 >> 16) & 0xff] << 16) ^ ((u32)Td4[(s1 >> 24)] << 24) ^ rk[0]; - *(u32 *)(out + 4) = ((u32)Td4[(s1) & 0xff]) ^ ((u32)Td4[(s0 >> 8) & 0xff] << 8) ^ ((u32)Td4[(s3 >> 16) & 0xff] << 16) ^ ((u32)Td4[(s2 >> 24)] << 24) ^ rk[1]; - *(u32 *)(out + 8) = ((u32)Td4[(s2) & 0xff]) ^ ((u32)Td4[(s1 >> 8) & 0xff] << 8) ^ ((u32)Td4[(s0 >> 16) & 0xff] << 16) ^ ((u32)Td4[(s3 >> 24)] << 24) ^ rk[2]; - *(u32 *)(out + 12) = ((u32)Td4[(s3) & 0xff]) ^ ((u32)Td4[(s2 >> 8) & 0xff] << 8) ^ ((u32)Td4[(s1 >> 16) & 0xff] << 16) ^ ((u32)Td4[(s0 >> 24)] << 24) ^ rk[3]; -} diff --git a/deps/openssl/openssl/crypto/aes/asm/aesni-mb-x86_64.pl b/deps/openssl/openssl/crypto/aes/asm/aesni-mb-x86_64.pl index dde15b1ef7ee..87ed95cdf33c 100644 --- a/deps/openssl/openssl/crypto/aes/asm/aesni-mb-x86_64.pl +++ b/deps/openssl/openssl/crypto/aes/asm/aesni-mb-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2013-2020 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2013-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -80,6 +80,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/deps/openssl/openssl/crypto/aes/asm/aesni-sha1-x86_64.pl b/deps/openssl/openssl/crypto/aes/asm/aesni-sha1-x86_64.pl index 4e8fa1d753d7..bc08da946064 100644 --- a/deps/openssl/openssl/crypto/aes/asm/aesni-sha1-x86_64.pl +++ b/deps/openssl/openssl/crypto/aes/asm/aesni-sha1-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2011-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2011-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -111,6 +111,9 @@ $1>=10); $avx=1 if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:clang|LLVM) version|.*based on LLVM) ([0-9]+\.[0-9]+)/ && $2>=3.0); +$avx=1 if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` =~ /#define __clang_major__.([0-9]+)/ && + $1>=11); #icx started with clang 11 + $shaext=1; ### set to zero if compiling for 1.0.1 $stitched_decrypt=0; diff --git a/deps/openssl/openssl/crypto/aes/asm/aesni-sha256-x86_64.pl b/deps/openssl/openssl/crypto/aes/asm/aesni-sha256-x86_64.pl index 39d29ddbb022..6715ba2e11a7 100644 --- a/deps/openssl/openssl/crypto/aes/asm/aesni-sha256-x86_64.pl +++ b/deps/openssl/openssl/crypto/aes/asm/aesni-sha256-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2013-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2013-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -75,6 +75,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + $shaext=$avx; ### set to zero if compiling for 1.0.1 $avx=1 if (!$shaext && $avx); diff --git a/deps/openssl/openssl/crypto/aes/asm/aesni-xts-avx512.pl b/deps/openssl/openssl/crypto/aes/asm/aesni-xts-avx512.pl index d89564112e31..16f2bbe78964 100644 --- a/deps/openssl/openssl/crypto/aes/asm/aesni-xts-avx512.pl +++ b/deps/openssl/openssl/crypto/aes/asm/aesni-xts-avx512.pl @@ -59,6 +59,13 @@ } } +if (!$avx512vaes && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx512vaes = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/deps/openssl/openssl/crypto/armcap.c b/deps/openssl/openssl/crypto/armcap.c index 03e47dc5bbfb..3005d295cfd0 100644 --- a/deps/openssl/openssl/crypto/armcap.c +++ b/deps/openssl/openssl/crypto/armcap.c @@ -1,5 +1,5 @@ /* - * Copyright 2011-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2011-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -408,14 +408,38 @@ void OPENSSL_cpuid_setup(void) if (OPENSSL_armcap_P & ARMV8_CPUID) OPENSSL_arm_midr = _armv8_cpuid_probe(); - if ((MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_N1)) && (OPENSSL_armcap_P & ARMV7_NEON)) { + if ((OPENSSL_armcap_P & ARMV7_NEON) + && (MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_N1))) OPENSSL_armv8_rsa_neonized = 1; - } - if ((MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V1) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_N2) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_MICROSOFT, MICROSOFT_CPU_PART_COBALT_100) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V2) || MIDR_IMPLEMENTER(OPENSSL_arm_midr) == ARM_CPU_IMP_AMPERE) && (OPENSSL_armcap_P & ARMV8_SHA3)) + + if ((OPENSSL_armcap_P & ARMV8_SHA3) + && (MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V1) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_N2) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_MICROSOFT, MICROSOFT_CPU_PART_COBALT_100) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V2) + || MIDR_IMPLEMENTER(OPENSSL_arm_midr) == ARM_CPU_IMP_AMPERE)) OPENSSL_armcap_P |= ARMV8_UNROLL8_EOR3; - if ((MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V1) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V2) || MIDR_IMPLEMENTER(OPENSSL_arm_midr) == ARM_CPU_IMP_AMPERE) && (OPENSSL_armcap_P & ARMV8_SHA3)) + + if ((OPENSSL_armcap_P & ARMV8_SHA3) + && (MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V1) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V2) + || MIDR_IMPLEMENTER(OPENSSL_arm_midr) == ARM_CPU_IMP_AMPERE)) OPENSSL_armcap_P |= ARMV8_UNROLL12_EOR3; - if ((MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM_PRO) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM_PRO) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM_MAX) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM_MAX) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE_PRO) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD_PRO) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE_MAX) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD_MAX)) && (OPENSSL_armcap_P & ARMV8_SHA3)) + + if ((OPENSSL_armcap_P & ARMV8_SHA3) + && (MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM_PRO) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM_PRO) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM_MAX) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM_MAX) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE_PRO) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD_PRO) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE_MAX) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD_MAX))) OPENSSL_armcap_P |= ARMV8_HAVE_SHA3_AND_WORTH_USING; #endif } diff --git a/deps/openssl/openssl/crypto/asn1/a_d2i_fp.c b/deps/openssl/openssl/crypto/asn1/a_d2i_fp.c index a23dea8ebda2..19595683ef98 100644 --- a/deps/openssl/openssl/crypto/asn1/a_d2i_fp.c +++ b/deps/openssl/openssl/crypto/asn1/a_d2i_fp.c @@ -139,7 +139,20 @@ int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb) } i = BIO_read(in, &(b->data[len]), want); if (i <= 0) { - ERR_raise(ERR_LIB_ASN1, ASN1_R_NOT_ENOUGH_DATA); + /* + * A read error (i < 0), an EOF in the middle of an object + * (diff != 0, some bytes already buffered), or an EOF while + * still inside an indefinite-length constructed value awaiting + * its end-of-contents octets (eos != 0) all mean the input is + * truncated. Only a clean EOF at a top-level object boundary + * (i == 0, diff == 0, eos == 0) is the normal end of input: + * fail without queuing an error so that callers looping over + * concatenated DER values (e.g. the libcrypto d2i_*_bio() + * consumers in CPython's ssl module) terminate cleanly instead + * of seeing a spurious ASN1_R_NOT_ENOUGH_DATA. + */ + if (i < 0 || diff != 0 || eos != 0) + ERR_raise(ERR_LIB_ASN1, ASN1_R_NOT_ENOUGH_DATA); goto err; } if (i > 0) { diff --git a/deps/openssl/openssl/crypto/asn1/a_mbstr.c b/deps/openssl/openssl/crypto/asn1/a_mbstr.c index ce5618dfd48b..9a61f7f1e051 100644 --- a/deps/openssl/openssl/crypto/asn1/a_mbstr.c +++ b/deps/openssl/openssl/crypto/asn1/a_mbstr.c @@ -51,12 +51,24 @@ int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len, unsigned char *p; int nchar; int (*cpyfunc)(unsigned long, void *) = NULL; - if (len == -1) - len = strlen((const char *)in); + if (len == -1) { + size_t len_s = strlen((const char *)in); + + if (len_s >= INT_MAX) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_STRING_TOO_LONG); + return -1; + } + len = (int)len_s; + } if (!mask) mask = DIRSTRING_TYPE; - if (len < 0) + if (len < 0) { + ERR_raise(ERR_LIB_ASN1, ERR_R_PASSED_INVALID_ARGUMENT); + return -1; + } else if (len >= INT_MAX) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_STRING_TOO_LONG); return -1; + } /* First do a string check and work out the number of characters */ switch (inform) { @@ -294,7 +306,7 @@ static int out_utf8(unsigned long value, void *arg) return len; } outlen = arg; - if (*outlen > INT_MAX - len) { + if (*outlen >= INT_MAX - len) { ERR_raise(ERR_LIB_ASN1, ASN1_R_STRING_TOO_LONG); return -1; } diff --git a/deps/openssl/openssl/crypto/asn1/asn1_gen.c b/deps/openssl/openssl/crypto/asn1/asn1_gen.c index 1c8d3d585940..69fbd6f89e58 100644 --- a/deps/openssl/openssl/crypto/asn1/asn1_gen.c +++ b/deps/openssl/openssl/crypto/asn1/asn1_gen.c @@ -426,8 +426,11 @@ static ASN1_TYPE *asn1_multi(int utype, const char *section, X509V3_CTX *cnf, depth + 1, perr); if (!typ) goto bad; - if (!sk_ASN1_TYPE_push(sk, typ)) + + if (!sk_ASN1_TYPE_push(sk, typ)) { + ASN1_TYPE_free(typ); goto bad; + } } } diff --git a/deps/openssl/openssl/crypto/bio/bss_file.c b/deps/openssl/openssl/crypto/bio/bss_file.c index 6b8daeb95f90..023bb458ce5f 100644 --- a/deps/openssl/openssl/crypto/bio/bss_file.c +++ b/deps/openssl/openssl/crypto/bio/bss_file.c @@ -312,7 +312,13 @@ static long file_ctrl(BIO *b, int cmd, long num, void *ptr) /* the ptr parameter is actually a FILE ** in this case. */ if (ptr != NULL) { fpp = (FILE **)ptr; - *fpp = (FILE *)b->ptr; + if (BIO_FLAGS_UPLINK_INTERNAL == 0 + || b->flags & BIO_FLAGS_UPLINK_INTERNAL) { + *fpp = (FILE *)b->ptr; + } else { /* avoid returning internal FILE * to the app */ + *fpp = NULL; + ret = 0; + } } break; case BIO_CTRL_GET_CLOSE: diff --git a/deps/openssl/openssl/crypto/bn/asm/rsaz-2k-avx512.pl b/deps/openssl/openssl/crypto/bn/asm/rsaz-2k-avx512.pl index 27f2e9b4b938..6c0cb566f9d7 100644 --- a/deps/openssl/openssl/crypto/bn/asm/rsaz-2k-avx512.pl +++ b/deps/openssl/openssl/crypto/bn/asm/rsaz-2k-avx512.pl @@ -1,4 +1,4 @@ -# Copyright 2020-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2020-2026 The OpenSSL Project Authors. All Rights Reserved. # Copyright (c) 2020, Intel Corporation. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use @@ -64,6 +64,13 @@ } } +if (!$avx512ifma && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx512ifma = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/deps/openssl/openssl/crypto/bn/asm/rsaz-2k-avxifma.pl b/deps/openssl/openssl/crypto/bn/asm/rsaz-2k-avxifma.pl index b84a3e4f1954..52d9781834d6 100644 --- a/deps/openssl/openssl/crypto/bn/asm/rsaz-2k-avxifma.pl +++ b/deps/openssl/openssl/crypto/bn/asm/rsaz-2k-avxifma.pl @@ -39,6 +39,13 @@ $avxifma = ($ver>=16.0); } +if (!$avxifma && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avxifma = ($1>=16); + } +} + if ($win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && `nasm -v 2>&1` =~ /NASM version ([0-9]+)\.([0-9]+)(?:\.([0-9]+))?(rc[0-9]+)?/) { my $ver = $1 + $2/100.0 + $3/10000.0; # 3.1.0->3.01, 3.10.1->3.1001 diff --git a/deps/openssl/openssl/crypto/bn/asm/rsaz-3k-avx512.pl b/deps/openssl/openssl/crypto/bn/asm/rsaz-3k-avx512.pl index b2ed3e8ca7cf..fe5b1ebefab6 100644 --- a/deps/openssl/openssl/crypto/bn/asm/rsaz-3k-avx512.pl +++ b/deps/openssl/openssl/crypto/bn/asm/rsaz-3k-avx512.pl @@ -1,4 +1,4 @@ -# Copyright 2021-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2021-2026 The OpenSSL Project Authors. All Rights Reserved. # Copyright (c) 2021, Intel Corporation. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use @@ -63,6 +63,13 @@ } } +if (!$avx512ifma && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx512ifma = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/deps/openssl/openssl/crypto/bn/asm/rsaz-3k-avxifma.pl b/deps/openssl/openssl/crypto/bn/asm/rsaz-3k-avxifma.pl index 1948d726b38b..aa11c546af6d 100644 --- a/deps/openssl/openssl/crypto/bn/asm/rsaz-3k-avxifma.pl +++ b/deps/openssl/openssl/crypto/bn/asm/rsaz-3k-avxifma.pl @@ -38,6 +38,13 @@ $avxifma = ($ver>=16.0); } +if (!$avxifma && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avxifma = ($1>=16); + } +} + if ($win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)(?:\.([0-9]+))?(rc[0-9]+)?/) { $avxifma = ($1>2.16) + ($1==2.16 && ((!defined($2) && !defined($3)) || (defined($2)))); diff --git a/deps/openssl/openssl/crypto/bn/asm/rsaz-4k-avx512.pl b/deps/openssl/openssl/crypto/bn/asm/rsaz-4k-avx512.pl index b76ab5904c88..b07180f6feca 100644 --- a/deps/openssl/openssl/crypto/bn/asm/rsaz-4k-avx512.pl +++ b/deps/openssl/openssl/crypto/bn/asm/rsaz-4k-avx512.pl @@ -1,4 +1,4 @@ -# Copyright 2021-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2021-2026 The OpenSSL Project Authors. All Rights Reserved. # Copyright (c) 2021, Intel Corporation. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use @@ -63,6 +63,13 @@ } } +if (!$avx512ifma && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx512ifma = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/deps/openssl/openssl/crypto/bn/asm/rsaz-4k-avxifma.pl b/deps/openssl/openssl/crypto/bn/asm/rsaz-4k-avxifma.pl index 9f299430cefc..28a447800d0d 100644 --- a/deps/openssl/openssl/crypto/bn/asm/rsaz-4k-avxifma.pl +++ b/deps/openssl/openssl/crypto/bn/asm/rsaz-4k-avxifma.pl @@ -38,6 +38,13 @@ $avxifma = ($ver>=16.0); } +if (!$avxifma && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avxifma = ($1>=16); + } +} + if ($win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)(?:\.([0-9]+))?(rc[0-9]+)?/) { $avxifma = ($1>2.16) + ($1==2.16 && ((!defined($2) && !defined($3)) || (defined($2)))); diff --git a/deps/openssl/openssl/crypto/bn/asm/rsaz-avx2.pl b/deps/openssl/openssl/crypto/bn/asm/rsaz-avx2.pl index 59b9c89b5be2..29243a7c0b76 100755 --- a/deps/openssl/openssl/crypto/bn/asm/rsaz-avx2.pl +++ b/deps/openssl/openssl/crypto/bn/asm/rsaz-avx2.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2013-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2013-2026 The OpenSSL Project Authors. All Rights Reserved. # Copyright (c) 2012, Intel Corporation. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use @@ -73,6 +73,14 @@ $addx = ($ver>=3.03); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $addx = ($1>=11); #icx started with clang 11 + $avx = ($1>=11); + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT = *OUT; diff --git a/deps/openssl/openssl/crypto/bn/asm/rsaz-x86_64.pl b/deps/openssl/openssl/crypto/bn/asm/rsaz-x86_64.pl index 64acf8f0d84d..3ceacea1d338 100755 --- a/deps/openssl/openssl/crypto/bn/asm/rsaz-x86_64.pl +++ b/deps/openssl/openssl/crypto/bn/asm/rsaz-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2013-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2013-2026 The OpenSSL Project Authors. All Rights Reserved. # Copyright (c) 2012, Intel Corporation. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use @@ -90,6 +90,13 @@ $addx = ($ver>=3.03); } +if (!$addx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $addx = ($1>=11); #icx started with clang 11 + } +} + ($out, $inp, $mod) = ("%rdi", "%rsi", "%rbp"); # common internal API { my ($out,$inp,$mod,$n0,$times) = ("%rdi","%rsi","%rdx","%rcx","%r8d"); diff --git a/deps/openssl/openssl/crypto/bn/asm/x86_64-mont.pl b/deps/openssl/openssl/crypto/bn/asm/x86_64-mont.pl index 140072b899dc..9c7b3091f434 100755 --- a/deps/openssl/openssl/crypto/bn/asm/x86_64-mont.pl +++ b/deps/openssl/openssl/crypto/bn/asm/x86_64-mont.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2005-2020 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2005-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -82,6 +82,13 @@ $addx = ($ver>=3.03); } +if (!$addx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $addx = ($1>=11); #icx started with clang 11 + } +} + # int bn_mul_mont( $rp="%rdi"; # BN_ULONG *rp, $ap="%rsi"; # const BN_ULONG *ap, diff --git a/deps/openssl/openssl/crypto/bn/asm/x86_64-mont5.pl b/deps/openssl/openssl/crypto/bn/asm/x86_64-mont5.pl index e06d13d74aea..52f95a485317 100755 --- a/deps/openssl/openssl/crypto/bn/asm/x86_64-mont5.pl +++ b/deps/openssl/openssl/crypto/bn/asm/x86_64-mont5.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2011-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2011-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -69,6 +69,13 @@ $addx = ($ver>=3.03); } +if (!$addx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $addx = ($1>=11); #icx started with clang 11 + } +} + # int bn_mul_mont_gather5( $rp="%rdi"; # BN_ULONG *rp, $ap="%rsi"; # const BN_ULONG *ap, diff --git a/deps/openssl/openssl/crypto/bn/bn_add.c b/deps/openssl/openssl/crypto/bn/bn_add.c index 38de39d1b8ac..9c028269840c 100644 --- a/deps/openssl/openssl/crypto/bn/bn_add.c +++ b/deps/openssl/openssl/crypto/bn/bn_add.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -97,6 +97,8 @@ int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) return 0; r->top = max; + if (max == 0) + goto end; ap = a->d; bp = b->d; @@ -116,6 +118,7 @@ int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) *rp = carry; r->top += carry; +end: r->neg = 0; bn_check_top(r); return 1; @@ -143,6 +146,9 @@ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) if (bn_wexpand(r, max) == NULL) return 0; + if (max == 0) + goto end; + ap = a->d; bp = b->d; rp = r->d; @@ -162,6 +168,7 @@ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) while (max && *--rp == 0) max--; +end: r->top = max; r->neg = 0; bn_pollute(r); diff --git a/deps/openssl/openssl/crypto/bn/bn_exp.c b/deps/openssl/openssl/crypto/bn/bn_exp.c index 44931f803802..ddcd89e2d4bc 100644 --- a/deps/openssl/openssl/crypto/bn/bn_exp.c +++ b/deps/openssl/openssl/crypto/bn/bn_exp.c @@ -552,7 +552,7 @@ static int MOD_EXP_CTIME_COPY_FROM_PREBUF(BIGNUM *b, int top, BN_ULONG acc = 0; for (j = 0; j < width; j++) { - acc |= table[j] & ((BN_ULONG)0 - (constant_time_eq_int(j, idx) & 1)); + acc |= table[j] & value_barrier_bn((BN_ULONG)0 - (constant_time_eq_int(j, idx) & 1)); } b->d[i] = acc; @@ -573,8 +573,9 @@ static int MOD_EXP_CTIME_COPY_FROM_PREBUF(BIGNUM *b, int top, BN_ULONG acc = 0; for (j = 0; j < xstride; j++) { - acc |= ((table[j + 0 * xstride] & y0) | (table[j + 1 * xstride] & y1) | (table[j + 2 * xstride] & y2) | (table[j + 3 * xstride] & y3)) - & ((BN_ULONG)0 - (constant_time_eq_int(j, idx) & 1)); + acc |= ((table[j + 0 * xstride] & value_barrier_bn(y0)) | (table[j + 1 * xstride] & value_barrier_bn(y1)) + | (table[j + 2 * xstride] & value_barrier_bn(y2)) | (table[j + 3 * xstride] & value_barrier_bn(y3))) + & value_barrier_bn((BN_ULONG)0 - (constant_time_eq_int(j, idx) & 1)); } b->d[i] = acc; diff --git a/deps/openssl/openssl/crypto/bn/bn_lib.c b/deps/openssl/openssl/crypto/bn/bn_lib.c index 93d54fd0a6ed..7961906f9ae7 100644 --- a/deps/openssl/openssl/crypto/bn/bn_lib.c +++ b/deps/openssl/openssl/crypto/bn/bn_lib.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -707,19 +707,37 @@ int BN_ucmp(const BIGNUM *a, const BIGNUM *b) int i; BN_ULONG t1, t2, *ap, *bp; + /* + * As it is a public API function, we should handle NULL parameters in + * some way. The function can’t return an error, so let’s define that NULL + * is less than any BIGNUM. + */ + if (!ossl_assert(a != NULL && b != NULL)) + return (b == NULL) - (a == NULL); + ap = a->d; bp = b->d; if (BN_get_flags(a, BN_FLG_CONSTTIME) - && a->top == b->top) { + || BN_get_flags(b, BN_FLG_CONSTTIME)) { int res = 0; + int min_top = a->top < b->top ? a->top : b->top; - for (i = 0; i < b->top; i++) { + for (i = 0; i < min_top; i++) { res = constant_time_select_int(constant_time_lt_bn(ap[i], bp[i]), -1, res); res = constant_time_select_int(constant_time_lt_bn(bp[i], ap[i]), 1, res); } + + for (i = min_top; i < a->top; ++i) + res = constant_time_select_int((int)constant_time_is_zero_bn(ap[i]), + res, 1); + + for (i = min_top; i < b->top; ++i) + res = constant_time_select_int((int)constant_time_is_zero_bn(bp[i]), + res, -1); + return res; } @@ -948,11 +966,11 @@ void BN_consttime_swap(BN_ULONG condition, BIGNUM *a, BIGNUM *b, int nwords) condition = ((~condition & ((condition - 1))) >> (BN_BITS2 - 1)) - 1; - t = (a->top ^ b->top) & condition; + t = (a->top ^ b->top) & value_barrier_bn(condition); a->top ^= t; b->top ^= t; - t = (a->neg ^ b->neg) & condition; + t = (a->neg ^ b->neg) & value_barrier_bn(condition); a->neg ^= t; b->neg ^= t; @@ -980,13 +998,13 @@ void BN_consttime_swap(BN_ULONG condition, BIGNUM *a, BIGNUM *b, int nwords) #define BN_CONSTTIME_SWAP_FLAGS (BN_FLG_CONSTTIME | BN_FLG_FIXED_TOP) - t = ((a->flags ^ b->flags) & BN_CONSTTIME_SWAP_FLAGS) & condition; + t = ((a->flags ^ b->flags) & BN_CONSTTIME_SWAP_FLAGS) & value_barrier_bn(condition); a->flags ^= t; b->flags ^= t; /* conditionally swap the data */ for (i = 0; i < nwords; i++) { - t = (a->d[i] ^ b->d[i]) & condition; + t = (a->d[i] ^ b->d[i]) & value_barrier_bn(condition); a->d[i] ^= t; b->d[i] ^= t; } diff --git a/deps/openssl/openssl/crypto/chacha/asm/chacha-x86.pl b/deps/openssl/openssl/crypto/chacha/asm/chacha-x86.pl index a1ea4ea461b0..b95d4df37979 100755 --- a/deps/openssl/openssl/crypto/chacha/asm/chacha-x86.pl +++ b/deps/openssl/openssl/crypto/chacha/asm/chacha-x86.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2016-2020 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2016-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -64,6 +64,10 @@ `$ENV{CC} -v 2>&1` =~ /((?:clang|LLVM) version|based on LLVM) ([0-9]+\.[0-9]+)/ && $2>=3.0); # first version supporting AVX +$ymm=1 if ($xmm && !$ymm && + `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` =~ /#define __clang_major__.([0-9]+)/ && + $1>=11); #icx started with clang 11 + $a="eax"; ($b,$b_)=("ebx","ebp"); ($c,$c_)=("ecx","esi"); diff --git a/deps/openssl/openssl/crypto/chacha/asm/chacha-x86_64.pl b/deps/openssl/openssl/crypto/chacha/asm/chacha-x86_64.pl index d46bc03b3eec..69e5319ad43e 100755 --- a/deps/openssl/openssl/crypto/chacha/asm/chacha-x86_64.pl +++ b/deps/openssl/openssl/crypto/chacha/asm/chacha-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2016-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2016-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -91,6 +91,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/deps/openssl/openssl/crypto/cmp/cmp_protect.c b/deps/openssl/openssl/crypto/cmp/cmp_protect.c index 1c8d2135fdab..110693b84038 100644 --- a/deps/openssl/openssl/crypto/cmp/cmp_protect.c +++ b/deps/openssl/openssl/crypto/cmp/cmp_protect.c @@ -1,5 +1,5 @@ /* - * Copyright 2007-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2007-2026 The OpenSSL Project Authors. All Rights Reserved. * Copyright Nokia 2007-2019 * Copyright Siemens AG 2015-2019 * @@ -66,7 +66,7 @@ ASN1_BIT_STRING *ossl_cmp_calc_protection(const OSSL_CMP_CTX *ctx, ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_PBM_SECRET); return NULL; } - if (ppval == NULL) { + if (pptype != V_ASN1_SEQUENCE || ppval == NULL) { ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_CALCULATING_PROTECTION); return NULL; } diff --git a/deps/openssl/openssl/crypto/cmp/cmp_vfy.c b/deps/openssl/openssl/crypto/cmp/cmp_vfy.c index eaa700d139d1..e79adb09d387 100644 --- a/deps/openssl/openssl/crypto/cmp/cmp_vfy.c +++ b/deps/openssl/openssl/crypto/cmp/cmp_vfy.c @@ -64,8 +64,10 @@ static int verify_signature(const OSSL_CMP_CTX *cmp_ctx, sig_err: res = ossl_x509_print_ex_brief(bio, cert, X509_FLAG_NO_EXTENSIONS); ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_VALIDATING_SIGNATURE); - if (res) - ERR_add_error_mem_bio("\n", bio); + if (res) { + ERR_add_error_txt(NULL, "\n"); + ERR_add_error_mem_bio(NULL, bio); + } res = 0; end: @@ -387,7 +389,7 @@ static int check_msg_with_certs(OSSL_CMP_CTX *ctx, const STACK_OF(X509) *certs, int i; if (sk_X509_num(certs) <= 0) { - ossl_cmp_log1(WARN, ctx, "no %s", desc); + ossl_cmp_log1(INFO, ctx, "no %s", desc); return 0; } @@ -407,7 +409,7 @@ static int check_msg_with_certs(OSSL_CMP_CTX *ctx, const STACK_OF(X509) *certs, } } if (in_extraCerts && n_acceptable_certs == 0) - ossl_cmp_warn(ctx, "no acceptable cert in extraCerts"); + ossl_cmp_log1(WARN, ctx, "no acceptable %s", desc); return 0; } @@ -502,14 +504,14 @@ static int check_msg_find_cert(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg) res = check_msg_all_certs(ctx, msg, 0 /* using ctx->trusted */) || check_msg_all_certs(ctx, msg, 1 /* 3gpp */); - ctx->log_cb = backup_log_cb; - if (res) { - /* discard any diagnostic information on trying to use certs */ - (void)ERR_pop_to_mark(); + + ctx->log_cb = backup_log_cb; /* re-enable logging */ + /* discard any previous diagnostic information on trying to use certs */ + (void)ERR_pop_to_mark(); + + if (res) goto end; - } /* failed finding a sender cert that verifies the message signature */ - (void)ERR_clear_last_mark(); sname = X509_NAME_oneline(sender->d.directoryName, NULL, 0); skid_str = skid == NULL ? NULL : i2s_ASN1_OCTET_STRING(NULL, skid); @@ -732,7 +734,7 @@ int ossl_cmp_msg_check_update(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg, "expected sender", expected_sender)) { str = X509_NAME_oneline(actual_sender, NULL, 0); ERR_raise_data(ERR_LIB_CMP, CMP_R_UNEXPECTED_SENDER, - str != NULL ? str : ""); + "%s", str != NULL ? str : ""); OPENSSL_free(str); return 0; } @@ -776,8 +778,13 @@ int ossl_cmp_msg_check_update(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg, res = 1; /* support more aggressive fuzzing by letting invalid msg pass */ #endif - /* remove extraCerts again if not caching */ - if (ctx->noCacheExtraCerts) + /* + * remove extraCerts again if not caching + * or if we failed validation above, lest a remote user + * starts sending us lots of certificates in invalid messages + * leading to a DOS from unbounded certificate stack growth + */ + if (ctx->noCacheExtraCerts || res != 1) while (num_added-- > 0) X509_free(sk_X509_shift(ctx->untrusted)); diff --git a/deps/openssl/openssl/crypto/cms/cms_asn1.c b/deps/openssl/openssl/crypto/cms/cms_asn1.c index fb87f6c6ad27..b3c103699031 100644 --- a/deps/openssl/openssl/crypto/cms/cms_asn1.c +++ b/deps/openssl/openssl/crypto/cms/cms_asn1.c @@ -245,9 +245,9 @@ ASN1_NDEF_SEQUENCE(CMS_AuthEnvelopedData) = { ASN1_IMP_OPT(CMS_AuthEnvelopedData, originatorInfo, CMS_OriginatorInfo, 0), ASN1_SET_OF(CMS_AuthEnvelopedData, recipientInfos, CMS_RecipientInfo), ASN1_SIMPLE(CMS_AuthEnvelopedData, authEncryptedContentInfo, CMS_EncryptedContentInfo), - ASN1_IMP_SET_OF_OPT(CMS_AuthEnvelopedData, authAttrs, X509_ALGOR, 2), + ASN1_IMP_SET_OF_OPT(CMS_AuthEnvelopedData, authAttrs, X509_ATTRIBUTE, 1), ASN1_SIMPLE(CMS_AuthEnvelopedData, mac, ASN1_OCTET_STRING), - ASN1_IMP_SET_OF_OPT(CMS_AuthEnvelopedData, unauthAttrs, X509_ALGOR, 3) + ASN1_IMP_SET_OF_OPT(CMS_AuthEnvelopedData, unauthAttrs, X509_ATTRIBUTE, 2) } ASN1_NDEF_SEQUENCE_END(CMS_AuthEnvelopedData) ASN1_NDEF_SEQUENCE(CMS_AuthenticatedData) = { @@ -257,9 +257,9 @@ ASN1_NDEF_SEQUENCE(CMS_AuthenticatedData) = { ASN1_SIMPLE(CMS_AuthenticatedData, macAlgorithm, X509_ALGOR), ASN1_IMP(CMS_AuthenticatedData, digestAlgorithm, X509_ALGOR, 1), ASN1_SIMPLE(CMS_AuthenticatedData, encapContentInfo, CMS_EncapsulatedContentInfo), - ASN1_IMP_SET_OF_OPT(CMS_AuthenticatedData, authAttrs, X509_ALGOR, 2), + ASN1_IMP_SET_OF_OPT(CMS_AuthenticatedData, authAttrs, X509_ATTRIBUTE, 2), ASN1_SIMPLE(CMS_AuthenticatedData, mac, ASN1_OCTET_STRING), - ASN1_IMP_SET_OF_OPT(CMS_AuthenticatedData, unauthAttrs, X509_ALGOR, 3) + ASN1_IMP_SET_OF_OPT(CMS_AuthenticatedData, unauthAttrs, X509_ATTRIBUTE, 3) } static_ASN1_NDEF_SEQUENCE_END(CMS_AuthenticatedData) ASN1_NDEF_SEQUENCE(CMS_CompressedData) diff --git a/deps/openssl/openssl/crypto/cms/cms_env.c b/deps/openssl/openssl/crypto/cms/cms_env.c index a8ecabb64ed7..ee86ae71d3ed 100644 --- a/deps/openssl/openssl/crypto/cms/cms_env.c +++ b/deps/openssl/openssl/crypto/cms/cms_env.c @@ -928,6 +928,7 @@ static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms, CMS_EncryptedContentInfo *ec; CMS_KEKRecipientInfo *kekri; unsigned char *ukey = NULL; + size_t ukey_alloc_len = 0; int ukeylen; int r = 0, wrap_nid; EVP_CIPHER *cipher = NULL; @@ -965,7 +966,8 @@ static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms, goto err; } - ukey = OPENSSL_malloc(kekri->encryptedKey->length - 8); + ukey_alloc_len = (size_t)kekri->encryptedKey->length - 8; + ukey = OPENSSL_malloc(ukey_alloc_len); if (ukey == NULL) goto err; @@ -994,7 +996,7 @@ static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms, err: EVP_CIPHER_free(cipher); if (!r) - OPENSSL_free(ukey); + OPENSSL_clear_free(ukey, ukey_alloc_len); EVP_CIPHER_CTX_free(ctx); return r; @@ -1204,6 +1206,35 @@ BIO *ossl_cms_EnvelopedData_init_bio(CMS_ContentInfo *cms) return cms_EnvelopedData_Decryption_init_bio(cms); } +/* The DER encoding of authAttrs, with the universal SET OF tag, is the AAD */ +static int cms_AuthEnvelopedData_set_aad(BIO *b, + STACK_OF(X509_ATTRIBUTE) *authAttrs) +{ + EVP_CIPHER_CTX *ctx; + unsigned char *aad = NULL; + int aadlen, outl, ok = 0; + const ASN1_ITEM *item; + + if (!BIO_get_cipher_ctx(b, &ctx)) + return 0; + item = EVP_CIPHER_CTX_is_encrypting(ctx) + ? ASN1_ITEM_rptr(CMS_Attributes_AadEncrypt) + : ASN1_ITEM_rptr(CMS_Attributes_AadDecrypt); + aadlen = ASN1_item_i2d((ASN1_VALUE *)authAttrs, &aad, item); + if (aadlen <= 0 || aad == NULL) { + ERR_raise(ERR_LIB_CMS, ERR_R_ASN1_LIB); + goto err; + } + if (EVP_CipherUpdate(ctx, NULL, &outl, aad, aadlen) <= 0) { + ERR_raise(ERR_LIB_CMS, CMS_R_CTRL_FAILURE); + goto err; + } + ok = 1; +err: + OPENSSL_free(aad); + return ok; +} + BIO *ossl_cms_AuthEnvelopedData_init_bio(CMS_ContentInfo *cms) { CMS_EncryptedContentInfo *ec; @@ -1220,9 +1251,16 @@ BIO *ossl_cms_AuthEnvelopedData_init_bio(CMS_ContentInfo *cms) ec->taglen = aenv->mac->length; } ret = ossl_cms_EncryptedContent_init_bio(ec, ossl_cms_get0_cmsctx(cms), 1); + if (ret == NULL) + return NULL; + + /* authAttrs, if present, are the AEAD associated data */ + if (aenv->authAttrs != NULL + && !cms_AuthEnvelopedData_set_aad(ret, aenv->authAttrs)) + goto err; - /* If error or no cipher end of processing */ - if (ret == NULL || ec->cipher == NULL) + /* If no cipher end of processing */ + if (ec->cipher == NULL) return ret; /* Now encrypt content key according to each RecipientInfo type */ diff --git a/deps/openssl/openssl/crypto/cms/cms_kari.c b/deps/openssl/openssl/crypto/cms/cms_kari.c index eb5b5d786285..459991525f09 100644 --- a/deps/openssl/openssl/crypto/cms/cms_kari.c +++ b/deps/openssl/openssl/crypto/cms/cms_kari.c @@ -1,5 +1,5 @@ /* - * Copyright 2013-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2013-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -216,7 +216,9 @@ static int cms_kek_cipher(unsigned char **pout, size_t *poutlen, size_t keklen; int rv = 0; unsigned char *out = NULL; + size_t out_alloc_len = 0; int outlen; + size_t outsize; keklen = EVP_CIPHER_CTX_get_key_length(kari->ctx); if (keklen > EVP_MAX_KEY_LENGTH) @@ -230,10 +232,17 @@ static int cms_kek_cipher(unsigned char **pout, size_t *poutlen, /* obtain output length of ciphered key */ if (!EVP_CipherUpdate(kari->ctx, NULL, &outlen, in, inlen)) goto err; - out = OPENSSL_malloc(outlen); + /* + * On its integrity-failure paths that primitive writes and cleanses up to + * inlen bytes of the output buffer. Size the buffer for that worst case so + * a failed unwrap cannot write past the allocation. + */ + outsize = (size_t)outlen < inlen ? inlen : (size_t)outlen; + out = OPENSSL_malloc(outsize); if (out == NULL) goto err; - if (!EVP_CipherUpdate(kari->ctx, out, &outlen, in, inlen)) + out_alloc_len = (size_t)outlen; + if (!EVP_CipherUpdate(kari->ctx, out, &outlen, in, (int)inlen)) goto err; *pout = out; *poutlen = (size_t)outlen; @@ -242,7 +251,7 @@ static int cms_kek_cipher(unsigned char **pout, size_t *poutlen, err: OPENSSL_cleanse(kek, keklen); if (!rv) - OPENSSL_free(out); + OPENSSL_clear_free(out, out_alloc_len); EVP_CIPHER_CTX_reset(kari->ctx); /* FIXME: WHY IS kari->pctx freed here? /RL */ EVP_PKEY_CTX_free(kari->pctx); diff --git a/deps/openssl/openssl/crypto/cms/cms_local.h b/deps/openssl/openssl/crypto/cms/cms_local.h index 94496b3823ef..55f41af054be 100644 --- a/deps/openssl/openssl/crypto/cms/cms_local.h +++ b/deps/openssl/openssl/crypto/cms/cms_local.h @@ -371,6 +371,9 @@ DECLARE_ASN1_ITEM(CMS_EncryptedContentInfo) DECLARE_ASN1_ITEM(CMS_IssuerAndSerialNumber) DECLARE_ASN1_ITEM(CMS_Attributes_Sign) DECLARE_ASN1_ITEM(CMS_Attributes_Verify) +/* The authAttrs AAD encoding matches the signed-attributes one */ +#define CMS_Attributes_AadEncrypt_it CMS_Attributes_Sign_it +#define CMS_Attributes_AadDecrypt_it CMS_Attributes_Verify_it DECLARE_ASN1_ITEM(CMS_RecipientInfo) DECLARE_ASN1_ITEM(CMS_PasswordRecipientInfo) DECLARE_ASN1_ALLOC_FUNCTIONS(CMS_IssuerAndSerialNumber) diff --git a/deps/openssl/openssl/crypto/cms/cms_pwri.c b/deps/openssl/openssl/crypto/cms/cms_pwri.c index 54f0eda2a2d8..de59c74fdd6e 100644 --- a/deps/openssl/openssl/crypto/cms/cms_pwri.c +++ b/deps/openssl/openssl/crypto/cms/cms_pwri.c @@ -315,6 +315,7 @@ int ossl_cms_RecipientInfo_pwri_crypt(const CMS_ContentInfo *cms, EVP_CIPHER *kekcipher; unsigned char *key = NULL; size_t keylen; + size_t key_alloc_len = 0; const CMS_CTX *cms_ctx = ossl_cms_get0_cmsctx(cms); ec = ossl_cms_get0_env_enc_content(cms); @@ -391,6 +392,7 @@ int ossl_cms_RecipientInfo_pwri_crypt(const CMS_ContentInfo *cms, if (key == NULL) goto err; + key_alloc_len = keylen; if (!kek_wrap_key(key, &keylen, ec->key, ec->keylen, kekctx, cms_ctx)) goto err; @@ -400,6 +402,7 @@ int ossl_cms_RecipientInfo_pwri_crypt(const CMS_ContentInfo *cms, key = OPENSSL_malloc(pwri->encryptedKey->length); if (key == NULL) goto err; + key_alloc_len = (size_t)pwri->encryptedKey->length; if (!kek_unwrap_key(key, &keylen, pwri->encryptedKey->data, pwri->encryptedKey->length, kekctx)) { @@ -419,7 +422,7 @@ int ossl_cms_RecipientInfo_pwri_crypt(const CMS_ContentInfo *cms, EVP_CIPHER_CTX_free(kekctx); if (!r) - OPENSSL_free(key); + OPENSSL_clear_free(key, key_alloc_len); X509_ALGOR_free(kekalg); return r; diff --git a/deps/openssl/openssl/crypto/cms/cms_smime.c b/deps/openssl/openssl/crypto/cms/cms_smime.c index 4b5009b9d5bf..dea1df084764 100644 --- a/deps/openssl/openssl/crypto/cms/cms_smime.c +++ b/deps/openssl/openssl/crypto/cms/cms_smime.c @@ -36,6 +36,7 @@ static int cms_copy_content(BIO *out, BIO *in, unsigned int flags) unsigned char buf[4096]; int r = 0, i; BIO *tmpout; + BIO *aeadbuf = NULL; tmpout = cms_get_text_bio(out, flags); @@ -44,6 +45,33 @@ static int cms_copy_content(BIO *out, BIO *in, unsigned int flags) goto err; } + /* + * For AEAD content (AuthEnvelopedData) the integrity tag is only verified + * once all the ciphertext has been processed, by the + * BIO_get_cipher_status() call below. RFC 5083 requires that the plaintext + * is not released to the caller until that verification succeeds, so + * buffer it in memory and only forward it to the output BIO once the tag + * has been checked. When CMS_TEXT is set tmpout is already a memory BIO + * that is flushed only on success, so the extra buffering is not needed. + */ + if (tmpout == out && BIO_method_type(in) == BIO_TYPE_CIPHER) { + EVP_CIPHER_CTX *ctx = NULL; + + if (BIO_get_cipher_ctx(in, &ctx) > 0 && ctx != NULL + && (EVP_CIPHER_get_flags(EVP_CIPHER_CTX_get0_cipher(ctx)) + & EVP_CIPH_FLAG_AEAD_CIPHER) + != 0) { + aeadbuf = BIO_new(BIO_s_mem()); + if (aeadbuf == NULL) { + ERR_raise(ERR_LIB_CMS, ERR_R_BIO_LIB); + goto err; + } + /* Return 0 (EOF) rather than a retryable -1 once drained. */ + BIO_set_mem_eof_return(aeadbuf, 0); + tmpout = aeadbuf; + } + } + /* Read all content through chain to process digest, decrypt etc */ for (;;) { i = BIO_read(in, buf, sizeof(buf)); @@ -66,6 +94,17 @@ static int cms_copy_content(BIO *out, BIO *in, unsigned int flags) ERR_raise(ERR_LIB_CMS, CMS_R_SMIME_TEXT_ERROR); goto err; } + } else if (aeadbuf != NULL) { + /* Forward the AEAD BIO to out BIO as the tag has been verified. */ + for (;;) { + i = BIO_read(aeadbuf, buf, sizeof(buf)); + if (i < 0) + goto err; + if (i == 0) + break; + if (BIO_write(out, buf, i) != i) + goto err; + } } r = 1; diff --git a/deps/openssl/openssl/crypto/ct/ct_b64.c b/deps/openssl/openssl/crypto/ct/ct_b64.c index e7eb9740ee08..01bd8fc508d6 100644 --- a/deps/openssl/openssl/crypto/ct/ct_b64.c +++ b/deps/openssl/openssl/crypto/ct/ct_b64.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -84,7 +84,7 @@ SCT *SCT_new_from_base64(unsigned char version, const char *logid_base64, declen = ct_base64_decode(logid_base64, &dec); if (declen < 0) { - ERR_raise(ERR_LIB_CT, X509_R_BASE64_DECODE_ERROR); + ERR_raise(ERR_LIB_CT, CT_R_BASE64_DECODE_ERROR); goto err; } if (!SCT_set0_log_id(sct, dec, declen)) @@ -93,7 +93,7 @@ SCT *SCT_new_from_base64(unsigned char version, const char *logid_base64, declen = ct_base64_decode(extensions_base64, &dec); if (declen < 0) { - ERR_raise(ERR_LIB_CT, X509_R_BASE64_DECODE_ERROR); + ERR_raise(ERR_LIB_CT, CT_R_BASE64_DECODE_ERROR); goto err; } SCT_set0_extensions(sct, dec, declen); @@ -101,7 +101,7 @@ SCT *SCT_new_from_base64(unsigned char version, const char *logid_base64, declen = ct_base64_decode(signature_base64, &dec); if (declen < 0) { - ERR_raise(ERR_LIB_CT, X509_R_BASE64_DECODE_ERROR); + ERR_raise(ERR_LIB_CT, CT_R_BASE64_DECODE_ERROR); goto err; } diff --git a/deps/openssl/openssl/crypto/ctype.c b/deps/openssl/openssl/crypto/ctype.c index 686fe64165fc..4f19d6002c5e 100644 --- a/deps/openssl/openssl/crypto/ctype.c +++ b/deps/openssl/openssl/crypto/ctype.c @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2017-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -226,7 +226,7 @@ static const unsigned short ctype_char_map[128] = { #ifdef CHARSET_EBCDIC int ossl_toascii(int c) { - if (c < -128 || c > 256 || c == EOF) + if (c < -128 || c >= 256 || c == EOF) return c; /* * Adjust negatively signed characters. @@ -241,7 +241,7 @@ int ossl_toascii(int c) int ossl_fromascii(int c) { - if (c < -128 || c > 256 || c == EOF) + if (c < -128 || c >= 256 || c == EOF) return c; if (c < 0) c += 256; diff --git a/deps/openssl/openssl/crypto/dh/dh_backend.c b/deps/openssl/openssl/crypto/dh/dh_backend.c index f68429862cd5..77b0b3257fb7 100644 --- a/deps/openssl/openssl/crypto/dh/dh_backend.c +++ b/deps/openssl/openssl/crypto/dh/dh_backend.c @@ -1,5 +1,5 @@ /* - * Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2020-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -232,7 +232,7 @@ DH *ossl_dh_key_from_pkcs8(const PKCS8_PRIV_KEY_INFO *p8inf, goto done; decerr: - ERR_raise(ERR_LIB_DH, EVP_R_DECODE_ERROR); + ERR_raise(ERR_LIB_DH, DH_R_DECODE_ERROR); dherr: DH_free(dh); dh = NULL; diff --git a/deps/openssl/openssl/crypto/dh/dh_check.c b/deps/openssl/openssl/crypto/dh/dh_check.c index 3002609b68f5..8787945f8a1c 100644 --- a/deps/openssl/openssl/crypto/dh/dh_check.c +++ b/deps/openssl/openssl/crypto/dh/dh_check.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -74,6 +74,14 @@ int DH_check_params(const DH *dh, int *ret) BN_CTX *ctx = NULL; *ret = 0; + /* + * A DH with no modulus or generator cannot be checked. Report + * the failure via |*ret| rather than dereferencing NULL below. + */ + if (dh->params.p == NULL || dh->params.g == NULL) { + *ret = DH_NOT_SUITABLE_GENERATOR | DH_CHECK_P_NOT_PRIME; + return 1; + } ctx = BN_CTX_new_ex(dh->libctx); if (ctx == NULL) goto err; @@ -150,6 +158,11 @@ int DH_check(const DH *dh, int *ret) int nid = DH_get_nid((DH *)dh); *ret = 0; + /* A DH with no modulus or generator cannot be checked. */ + if (dh->params.p == NULL || dh->params.g == NULL) { + *ret = DH_NOT_SUITABLE_GENERATOR | DH_CHECK_P_NOT_PRIME; + return 1; + } if (nid != NID_undef) return 1; @@ -250,6 +263,15 @@ int DH_check_pub_key_ex(const DH *dh, const BIGNUM *pub_key) */ int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret) { + *ret = 0; + /* + * Without a modulus we cannot check anything; signal failure via + * |*ret| rather than crashing in BN_num_bits below. + */ + if (dh->params.p == NULL) { + *ret = DH_CHECK_PUBKEY_INVALID; + return 1; + } /* Don't do any checks at all with an excessively large modulus */ if (BN_num_bits(dh->params.p) > OPENSSL_DH_CHECK_MAX_MODULUS_BITS) { ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE); diff --git a/deps/openssl/openssl/crypto/dsa/dsa_key.c b/deps/openssl/openssl/crypto/dsa/dsa_key.c index aa69c3eea8fb..738915cc4f3d 100644 --- a/deps/openssl/openssl/crypto/dsa/dsa_key.c +++ b/deps/openssl/openssl/crypto/dsa/dsa_key.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -198,7 +198,6 @@ static int dsa_keygen(DSA *dsa) ok = dsa_keygen_pairwise_test(dsa, cb, cbarg) && dsa_keygen_knownanswer_test(dsa, ctx, cb, cbarg); if (!ok) { - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); BN_free(dsa->pub_key); BN_clear_free(dsa->priv_key); dsa->pub_key = NULL; diff --git a/deps/openssl/openssl/crypto/ec/asm/ecp_nistz256-x86_64.pl b/deps/openssl/openssl/crypto/ec/asm/ecp_nistz256-x86_64.pl index 4da9a149a99a..12a104b5ec0f 100755 --- a/deps/openssl/openssl/crypto/ec/asm/ecp_nistz256-x86_64.pl +++ b/deps/openssl/openssl/crypto/ec/asm/ecp_nistz256-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2014-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2014-2026 The OpenSSL Project Authors. All Rights Reserved. # Copyright (c) 2014, Intel Corporation. All Rights Reserved. # Copyright (c) 2015 CloudFlare, Inc. # @@ -80,6 +80,14 @@ $addx = ($ver>=3.03); } +if (!$addx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + $addx = ($1>=11); + } +} + $code.=<<___; .text .extern OPENSSL_ia32cap_P diff --git a/deps/openssl/openssl/crypto/ec/asm/x25519-x86_64.pl b/deps/openssl/openssl/crypto/ec/asm/x25519-x86_64.pl index d2285269a308..204c51854813 100755 --- a/deps/openssl/openssl/crypto/ec/asm/x25519-x86_64.pl +++ b/deps/openssl/openssl/crypto/ec/asm/x25519-x86_64.pl @@ -1,5 +1,5 @@ #!/usr/bin/env perl -# Copyright 2018-2020 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2018-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -97,6 +97,13 @@ $addx = ($ver>=3.03); } +if (!$addx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $addx = ($1>=11); #icx started with clang 11 + } +} + $code.=<<___; .text diff --git a/deps/openssl/openssl/crypto/ec/ec_key.c b/deps/openssl/openssl/crypto/ec/ec_key.c index 8723ead41e0e..71f1c63e2ab6 100644 --- a/deps/openssl/openssl/crypto/ec/ec_key.c +++ b/deps/openssl/openssl/crypto/ec/ec_key.c @@ -1,5 +1,5 @@ /* - * Copyright 2002-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2002-2026 The OpenSSL Project Authors. All Rights Reserved. * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved * * Licensed under the Apache License 2.0 (the "License"). You may not use @@ -236,56 +236,6 @@ int ossl_ec_key_gen(EC_KEY *eckey) return ret; } -/* - * Refer: FIPS 140-3 IG 10.3.A Additional Comment 1 - * Perform a KAT by duplicating the public key generation. - * - * NOTE: This issue requires a background understanding, provided in a separate - * document; the current IG 10.3.A AC1 is insufficient regarding the PCT for - * the key agreement scenario. - * - * Currently IG 10.3.A requires PCT in the mode of use prior to use of the - * key pair, citing the PCT defined in the associated standard. For key - * agreement, the only PCT defined in SP 800-56A is that of Section 5.6.2.4: - * the comparison of the original public key to a newly calculated public key. - */ -static int ecdsa_keygen_knownanswer_test(EC_KEY *eckey, BN_CTX *ctx, - OSSL_CALLBACK *cb, void *cbarg) -{ - int len, ret = 0; - OSSL_SELF_TEST *st = NULL; - unsigned char bytes[512] = { 0 }; - EC_POINT *pub_key2 = NULL; - - st = OSSL_SELF_TEST_new(cb, cbarg); - if (st == NULL) - return 0; - - OSSL_SELF_TEST_onbegin(st, OSSL_SELF_TEST_TYPE_PCT_KAT, - OSSL_SELF_TEST_DESC_PCT_ECDSA); - - if ((pub_key2 = EC_POINT_new(eckey->group)) == NULL) - goto err; - - /* pub_key = priv_key * G (where G is a point on the curve) */ - if (!EC_POINT_mul(eckey->group, pub_key2, eckey->priv_key, NULL, NULL, ctx)) - goto err; - - if (BN_num_bytes(pub_key2->X) > (int)sizeof(bytes)) - goto err; - len = BN_bn2bin(pub_key2->X, bytes); - if (OSSL_SELF_TEST_oncorrupt_byte(st, bytes) - && BN_bin2bn(bytes, len, pub_key2->X) == NULL) - goto err; - ret = !EC_POINT_cmp(eckey->group, eckey->pub_key, pub_key2, ctx); - -err: - OSSL_SELF_TEST_onend(st, ret); - OSSL_SELF_TEST_free(st); - EC_POINT_free(pub_key2); - return ret; -} - /* * ECC Key generation. * See SP800-56AR3 5.6.1.2.2 "Key Pair Generation by Testing Candidates" @@ -382,13 +332,11 @@ static int ec_generate_key(EC_KEY *eckey, int pairwise_test) void *cbarg = NULL; OSSL_SELF_TEST_get_callback(eckey->libctx, &cb, &cbarg); - ok = ecdsa_keygen_pairwise_test(eckey, cb, cbarg) - && ecdsa_keygen_knownanswer_test(eckey, ctx, cb, cbarg); + ok = ecdsa_keygen_pairwise_test(eckey, cb, cbarg); } err: /* Step (9): If there is an error return an invalid keypair. */ if (!ok) { - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); BN_clear(eckey->priv_key); if (eckey->pub_key != NULL) EC_POINT_set_to_infinity(group, eckey->pub_key); diff --git a/deps/openssl/openssl/crypto/err/openssl.txt b/deps/openssl/openssl/crypto/err/openssl.txt index 5b2ea1c4a4e6..be65c1767ec6 100644 --- a/deps/openssl/openssl/crypto/err/openssl.txt +++ b/deps/openssl/openssl/crypto/err/openssl.txt @@ -1861,6 +1861,7 @@ X509_R_CANT_CHECK_DH_KEY:114:can't check dh key X509_R_CERTIFICATE_VERIFICATION_FAILED:139:certificate verification failed X509_R_CERT_ALREADY_IN_HASH_TABLE:101:cert already in hash table X509_R_CRL_ALREADY_DELTA:127:crl already delta +X509_R_CRL_SIGNATURE_ALGORITHM_MISMATCH:147:crl signature algorithm mismatch X509_R_CRL_VERIFY_FAILURE:131:crl verify failure X509_R_DUPLICATE_ATTRIBUTE:140:duplicate attribute X509_R_ERROR_GETTING_MD_BY_NID:141:error getting md by nid diff --git a/deps/openssl/openssl/crypto/evp/exchange.c b/deps/openssl/openssl/crypto/evp/exchange.c index 088d2fdc6e73..30299d67defd 100644 --- a/deps/openssl/openssl/crypto/evp/exchange.c +++ b/deps/openssl/openssl/crypto/evp/exchange.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -287,7 +287,9 @@ int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[]) * iteration we're on. */ EVP_KEYEXCH_free(exchange); + exchange = NULL; EVP_KEYMGMT_free(tmp_keymgmt); + tmp_keymgmt = NULL; switch (iter) { case 1: diff --git a/deps/openssl/openssl/crypto/ffc/ffc_params_generate.c b/deps/openssl/openssl/crypto/ffc/ffc_params_generate.c index 969cca76f999..94b1602dd28e 100644 --- a/deps/openssl/openssl/crypto/ffc/ffc_params_generate.c +++ b/deps/openssl/openssl/crypto/ffc/ffc_params_generate.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -77,6 +77,13 @@ static int ffc_validate_LN(size_t L, size_t N, int type, int verify) ERR_raise(ERR_LIB_DH, DH_R_BAD_FFC_PARAMETERS); #endif } else if (type == FFC_PARAM_TYPE_DSA) { + if (N > 512) { +#ifndef OPENSSL_NO_DSA + ERR_raise_data(ERR_LIB_DSA, DSA_R_BAD_FFC_PARAMETERS, + "N is %zu, but the maximum supported N is 512", N); +#endif + return 0; + } if (L >= 3072 && N >= 256) return 128; if (L >= 2048 && N >= 224) diff --git a/deps/openssl/openssl/crypto/hmac/hmac.c b/deps/openssl/openssl/crypto/hmac/hmac.c index c5d42db82020..77b97b6bef6a 100644 --- a/deps/openssl/openssl/crypto/hmac/hmac.c +++ b/deps/openssl/openssl/crypto/hmac/hmac.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -50,9 +50,11 @@ int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len, return 0; #ifdef OPENSSL_HMAC_S390X - rv = s390x_HMAC_init(ctx, key, len, impl); - if (rv >= 1) - return rv; + { + int ret = s390x_HMAC_init(ctx, key, len, impl); + if (ret != -1) /* -1 means SW fallback */ + return ret; + } #endif if (key != NULL) { diff --git a/deps/openssl/openssl/crypto/http/http_lib.c b/deps/openssl/openssl/crypto/http/http_lib.c index 05bf4be78856..d7227f5df248 100644 --- a/deps/openssl/openssl/crypto/http/http_lib.c +++ b/deps/openssl/openssl/crypto/http/http_lib.c @@ -21,6 +21,7 @@ #define NI_MAXHOST 255 #endif #include "crypto/ctype.h" /* for ossl_isspace() */ +#define OSSL_URL_SCHEME_SUFFIX "://" static void init_pstring(char **pstr) { @@ -79,16 +80,20 @@ int OSSL_parse_url(const char *url, char **pscheme, char **puser, char **phost, return 0; } - /* check for optional prefix "://" */ - scheme = scheme_end = url; - p = strstr(url, "://"); - if (p == NULL) { - p = url; - } else { - scheme_end = p; - if (scheme_end == scheme) - goto parse_err; - p += strlen("://"); + /* check for optional prefix "://" as per RFC 3986: */ + scheme = scheme_end = p = url; + if (ossl_isalpha(*p)) { + while (*p != '\0' + && (ossl_isalpha(*p) + || ossl_isdigit(*p) + || strchr("+-.", *p) != NULL)) + p++; + if (HAS_PREFIX(p, OSSL_URL_SCHEME_SUFFIX)) { + scheme_end = p; + p += sizeof(OSSL_URL_SCHEME_SUFFIX) - 1; + } else { + p = url; + } } /* parse optional "userinfo@" */ @@ -105,7 +110,7 @@ int OSSL_parse_url(const char *url, char **pscheme, char **puser, char **phost, /* parse hostname/address as far as needed here */ if (host[0] == '[') { /* IPv6 literal, which may include ':' */ - host_end = strchr(host + 1, ']'); + host_end = memchr(host + 1, ']', authority_end - host - 1); if (host_end == NULL) goto parse_err; p = ++host_end; diff --git a/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_encoders.c b/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_encoders.c index 00e2b1772cf9..9ebe5ae02d9b 100644 --- a/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_encoders.c +++ b/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_encoders.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -932,6 +932,9 @@ int ossl_ml_dsa_sig_encode(const ML_DSA_SIG *sig, const ML_DSA_PARAMS *params, ret = 1; err: WPACKET_finish(&pkt); + /* Erase any partial signature output on failure */ + if (ret == 0) + OPENSSL_cleanse(out, params->sig_len); return ret; } diff --git a/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_key.c b/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_key.c index e999b6c08d09..66e2ff2b61a0 100644 --- a/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_key.c +++ b/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_key.c @@ -346,10 +346,15 @@ static int public_from_private(const ML_DSA_KEY *key, EVP_MD_CTX *md_ctx, /* Compress t */ vector_power2_round(&t, t1, t0); - /* Zeroize secret */ - vector_zero(&s1_ntt); ret = 1; err: + /* + * The low bits of |t| are private and |s1_ntt| is secret, wipe both. + * The trailing |a_ntt| matrix is not wiped: per FIPS 204 section 3.6.3 + * the matrix A is easily computed from the public key and does not + * require any special protections. + */ + OPENSSL_cleanse(polys, (k + l) * sizeof(*polys)); OPENSSL_free(polys); return ret; } @@ -370,6 +375,7 @@ int ossl_ml_dsa_key_public_from_private(ML_DSA_KEY *key) && shake_xof(md_ctx, key->shake256_md, key->pub_encoding, key->params->pk_len, key->tr, sizeof(key->tr)); + vector_zero(&t0); vector_free(&t0); EVP_MD_CTX_free(md_ctx); return ret; @@ -401,7 +407,7 @@ int ossl_ml_dsa_key_pairwise_check(const ML_DSA_KEY *key) ret = vector_equal(&t1, &key->t1) && vector_equal(&t0, &key->t0); err: EVP_MD_CTX_free(md_ctx); - OPENSSL_free(polys); + OPENSSL_clear_free(polys, 2 * k * sizeof(*polys)); return ret; } @@ -489,7 +495,7 @@ int ossl_ml_dsa_generate_key(ML_DSA_KEY *out) "explicit %s private key does not match seed", out->params->alg); } - OPENSSL_free(sk); + OPENSSL_clear_free(sk, out->params->sk_len); } return ret; } diff --git a/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_matrix.c b/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_matrix.c index c7ff59845217..94fd16936c8b 100644 --- a/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_matrix.c +++ b/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_matrix.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -7,6 +7,7 @@ * https://www.openssl.org/source/license.html */ +#include #include "ml_dsa_local.h" #include "ml_dsa_vector.h" #include "ml_dsa_matrix.h" @@ -25,15 +26,16 @@ void ossl_ml_dsa_matrix_mult_vector(const MATRIX *a, const VECTOR *s, { size_t i, j; POLY *poly = a->m_poly; + POLY product; vector_zero(t); for (i = 0; i < a->k; i++) { for (j = 0; j < a->l; j++) { - POLY product; - ossl_ml_dsa_poly_ntt_mult(poly++, &s->poly[j], &product); poly_add(&product, &t->poly[i], &t->poly[i]); } } + + OPENSSL_cleanse(&product, sizeof(product)); } diff --git a/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_sample.c b/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_sample.c index 6fae4c4a0de5..f8ce638dc229 100644 --- a/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_sample.c +++ b/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_sample.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -8,6 +8,7 @@ */ #include +#include #include "ml_dsa_local.h" #include "ml_dsa_vector.h" #include "ml_dsa_matrix.h" @@ -159,13 +160,14 @@ static int rej_bounded_poly(EVP_MD_CTX *h_ctx, const EVP_MD *md, COEFF_FROM_NIBBLE_FUNC *coef_from_nibble, const uint8_t *seed, size_t seed_len, POLY *out) { + int ret = 0; int j = 0; uint32_t z0, z1; uint8_t blocks[SHAKE256_BLOCKSIZE], *b, *end = blocks + sizeof(blocks); /* Instead of just squeezing 1 byte at a time, we grab a whole block */ if (!shake_xof(h_ctx, md, seed, seed_len, blocks, sizeof(blocks))) - return 0; + goto err; while (1) { for (b = blocks; b < end; b++) { @@ -173,15 +175,22 @@ static int rej_bounded_poly(EVP_MD_CTX *h_ctx, const EVP_MD *md, z1 = *b >> 4; /* high nibble of byte */ if (coef_from_nibble(z0, &out->coeff[j]) - && ++j >= ML_DSA_NUM_POLY_COEFFICIENTS) - return 1; + && ++j >= ML_DSA_NUM_POLY_COEFFICIENTS) { + ret = 1; + goto err; + } if (coef_from_nibble(z1, &out->coeff[j]) - && ++j >= ML_DSA_NUM_POLY_COEFFICIENTS) - return 1; + && ++j >= ML_DSA_NUM_POLY_COEFFICIENTS) { + ret = 1; + goto err; + } } if (!EVP_DigestSqueeze(h_ctx, blocks, sizeof(blocks))) - return 0; + goto err; } +err: + OPENSSL_cleanse(blocks, sizeof(blocks)); + return ret; } /** @@ -205,6 +214,13 @@ int ossl_ml_dsa_matrix_expand_A(EVP_MD_CTX *g_ctx, const EVP_MD *md, uint8_t derived_seed[ML_DSA_RHO_BYTES + 2]; POLY *poly = out->m_poly; + /* + * The seeds derived below and the sampling buffers in rej_ntt_poly() are + * not cleansed: per FIPS 204 section 3.6.3 the matrix A is easily + * computed from the public key and does not require any special + * protections. + */ + /* The seed used for each matrix element is rho + column_index + row_index */ memcpy(derived_seed, rho, ML_DSA_RHO_BYTES); @@ -274,6 +290,7 @@ int ossl_ml_dsa_vector_expand_S(EVP_MD_CTX *h_ctx, const EVP_MD *md, int eta, } ret = 1; err: + OPENSSL_cleanse(derived_seed, sizeof(derived_seed)); return ret; } @@ -284,9 +301,11 @@ int ossl_ml_dsa_poly_expand_mask(POLY *out, const uint8_t *seed, size_t seed_len { uint8_t buf[32 * 20]; size_t buf_len = 32 * (gamma1 == ML_DSA_GAMMA1_TWO_POWER_19 ? 20 : 18); - - return shake_xof(h_ctx, md, seed, seed_len, buf, buf_len) + int ret = shake_xof(h_ctx, md, seed, seed_len, buf, buf_len) && ossl_ml_dsa_poly_decode_expand_mask(out, buf, buf_len, gamma1); + + OPENSSL_cleanse(buf, sizeof(buf)); + return ret; } /* @@ -311,13 +330,14 @@ int ossl_ml_dsa_poly_sample_in_ball(POLY *out_c, const uint8_t *seed, int seed_l uint64_t signs; int offset = 8; size_t end; + int ret = 0; /* * Rather than squeeze 8 bytes followed by lots of 1 byte squeezes * the SHAKE blocksize is squeezed each time and buffered into 'block'. */ if (!shake_xof(h_ctx, md, seed, seed_len, block, sizeof(block))) - return 0; + goto err; /* * grab the first 64 bits - since tau < 64 @@ -336,7 +356,7 @@ int ossl_ml_dsa_poly_sample_in_ball(POLY *out_c, const uint8_t *seed, int seed_l if (offset == sizeof(block)) { /* squeeze another block if the bytes from block have been used */ if (!EVP_DigestSqueeze(h_ctx, block, sizeof(block))) - return 0; + goto err; offset = 0; } @@ -354,5 +374,8 @@ int ossl_ml_dsa_poly_sample_in_ball(POLY *out_c, const uint8_t *seed, int seed_l out_c->coeff[index] = mod_sub(1, 2 * (signs & 1)); signs >>= 1; /* grab the next random bit */ } - return 1; + ret = 1; +err: + OPENSSL_cleanse(block, sizeof(block)); + return ret; } diff --git a/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_sign.c b/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_sign.c index 71eccf875963..166a604bcd57 100644 --- a/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_sign.c +++ b/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_sign.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -197,6 +197,7 @@ static int ml_dsa_sign_internal(const ML_DSA_KEY *priv, int msg_is_mu, EVP_MD_CTX_free(md_ctx); OPENSSL_clear_free(alloc, alloc_len); OPENSSL_cleanse(rho_prime, sizeof(rho_prime)); + OPENSSL_cleanse(c_tilde, sizeof(c_tilde)); return ret; } @@ -387,7 +388,13 @@ int ossl_ml_dsa_sign(const ML_DSA_KEY *priv, int msg_is_mu, alloced_m = m; } ret = ml_dsa_sign_internal(priv, msg_is_mu, m, m_len, rand, rand_len, sig); - OPENSSL_free(alloced_m); + /* The encoded message may contain confidential message content */ + if (m != msg) { + if (m != m_tmp) + OPENSSL_clear_free(alloced_m, m_len); + else + OPENSSL_cleanse(m_tmp, sizeof(m_tmp)); + } } if (sig_len != NULL) *sig_len = priv->params->sig_len; @@ -424,6 +431,12 @@ int ossl_ml_dsa_verify(const ML_DSA_KEY *pub, int msg_is_mu, } ret = ml_dsa_verify_internal(pub, msg_is_mu, m, m_len, sig, sig_len); - OPENSSL_free(alloced_m); + /* The encoded message may contain confidential message content */ + if (m != msg) { + if (m != m_tmp) + OPENSSL_clear_free(alloced_m, m_len); + else + OPENSSL_cleanse(m_tmp, sizeof(m_tmp)); + } return ret; } diff --git a/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_vector.h b/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_vector.h index d24bf031a292..1f3e6a03299c 100644 --- a/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_vector.h +++ b/deps/openssl/openssl/crypto/ml_dsa/ml_dsa_vector.h @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -8,6 +8,7 @@ */ #include +#include #include "ml_dsa_poly.h" struct vector_st { @@ -153,6 +154,7 @@ vector_expand_mask(VECTOR *out, const uint8_t *rho_prime, size_t rho_prime_len, poly_expand_mask(out->poly + i, derived_seed, sizeof(derived_seed), gamma1, h_ctx, md); } + OPENSSL_cleanse(derived_seed, sizeof(derived_seed)); } /* Scale back previously rounded value */ diff --git a/deps/openssl/openssl/crypto/ml_kem/ml_kem.c b/deps/openssl/openssl/crypto/ml_kem/ml_kem.c index dd8a39197ac8..6c3141ca2d32 100644 --- a/deps/openssl/openssl/crypto/ml_kem/ml_kem.c +++ b/deps/openssl/openssl/crypto/ml_kem/ml_kem.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -1310,6 +1310,12 @@ static __owur int matrix_expand(EVP_MD_CTX *mdctx, ML_KEM_KEY *key) int rank = key->vinfo->rank; int i, j; + /* + * The seeds derived below and the sampling buffers in sample_scalar() + * are not cleansed: per FIPS 203 section 3.3 the matrix A is easily + * computed from the public encapsulation key and does not require any + * special protections. + */ memcpy(input, key->rho, ML_KEM_RANDOM_BYTES); for (i = 0; i < rank; i++) { for (j = 0; j < rank; j++) { @@ -1340,8 +1346,10 @@ static __owur int cbd_2(scalar *out, uint8_t in[ML_KEM_RANDOM_BYTES + 1], uint16_t value, mask; uint8_t b; - if (!prf(randbuf, sizeof(randbuf), in, mdctx, key)) + if (!prf(randbuf, sizeof(randbuf), in, mdctx, key)) { + OPENSSL_cleanse((void *)randbuf, sizeof(randbuf)); return 0; + } do { b = *r++; @@ -1363,6 +1371,8 @@ static __owur int cbd_2(scalar *out, uint8_t in[ML_KEM_RANDOM_BYTES + 1], mask = constish_time_non_zero(value >> 15); *curr++ = value + (kPrime & mask); } while (curr < end); + + OPENSSL_cleanse((void *)randbuf, sizeof(randbuf)); return 1; } @@ -1380,8 +1390,10 @@ static __owur int cbd_3(scalar *out, uint8_t in[ML_KEM_RANDOM_BYTES + 1], uint8_t b1, b2, b3; uint16_t value, mask; - if (!prf(randbuf, sizeof(randbuf), in, mdctx, key)) + if (!prf(randbuf, sizeof(randbuf), in, mdctx, key)) { + OPENSSL_cleanse((void *)randbuf, sizeof(randbuf)); return 0; + } do { b1 = *r++; @@ -1415,6 +1427,8 @@ static __owur int cbd_3(scalar *out, uint8_t in[ML_KEM_RANDOM_BYTES + 1], mask = constish_time_non_zero(value >> 15); *curr++ = value + (kPrime & mask); } while (curr < end); + + OPENSSL_cleanse((void *)randbuf, sizeof(randbuf)); return 1; } @@ -1427,14 +1441,19 @@ static __owur int gencbd_vector(scalar *out, CBD_FUNC cbd, uint8_t *counter, EVP_MD_CTX *mdctx, const ML_KEM_KEY *key) { uint8_t input[ML_KEM_RANDOM_BYTES + 1]; + int ret = 0; memcpy(input, seed, ML_KEM_RANDOM_BYTES); do { input[ML_KEM_RANDOM_BYTES] = (*counter)++; if (!cbd(out++, input, mdctx, key)) - return 0; + goto end; } while (--rank > 0); - return 1; + ret = 1; + +end: + OPENSSL_cleanse((void *)input, sizeof(input)); + return ret; } /* @@ -1445,15 +1464,20 @@ static __owur int gencbd_vector_ntt(scalar *out, CBD_FUNC cbd, uint8_t *counter, EVP_MD_CTX *mdctx, const ML_KEM_KEY *key) { uint8_t input[ML_KEM_RANDOM_BYTES + 1]; + int ret = 0; memcpy(input, seed, ML_KEM_RANDOM_BYTES); do { input[ML_KEM_RANDOM_BYTES] = (*counter)++; if (!cbd(out, input, mdctx, key)) - return 0; + goto end; scalar_ntt(out++); } while (--rank > 0); - return 1; + ret = 1; + +end: + OPENSSL_cleanse((void *)input, sizeof(input)); + return ret; } /* The |ETA1| value for ML-KEM-512 is 3, the rest and all ETA2 values are 2. */ @@ -1492,10 +1516,11 @@ static __owur int encrypt_cpa(uint8_t out[ML_KEM_SHARED_SECRET_BYTES], uint8_t counter = 0; int du = vinfo->du; int dv = vinfo->dv; + int ret = 0; /* FIPS 203 "y" vector */ if (!gencbd_vector_ntt(y, cbd_1, &counter, r, rank, mdctx, key)) - return 0; + goto end; /* FIPS 203 "v" scalar */ inner_product(&v, key->t, y, rank); scalar_inverse_ntt(&v); @@ -1504,7 +1529,7 @@ static __owur int encrypt_cpa(uint8_t out[ML_KEM_SHARED_SECRET_BYTES], /* All done with |y|, now free to reuse tmp[0] for FIPS 203 |e1| */ if (!gencbd_vector(e1, cbd_2, &counter, r, rank, mdctx, key)) - return 0; + goto end; vector_add(u, e1, rank); vector_compress(u, du, rank); vector_encode(out, u, du, rank); @@ -1513,14 +1538,19 @@ static __owur int encrypt_cpa(uint8_t out[ML_KEM_SHARED_SECRET_BYTES], memcpy(input, r, ML_KEM_RANDOM_BYTES); input[ML_KEM_RANDOM_BYTES] = counter; if (!cbd_2(e2, input, mdctx, key)) - return 0; + goto end; scalar_add(&v, e2); /* Combine message with |v| */ scalar_decode_decompress_add(&v, message); scalar_compress(&v, dv); scalar_encode(out + vinfo->u_vector_bytes, &v, dv); - return 1; + ret = 1; + +end: + OPENSSL_cleanse((void *)input, sizeof(input)); + OPENSSL_cleanse((void *)&v, sizeof(v)); + return ret; } /* @@ -1544,6 +1574,9 @@ decrypt_cpa(uint8_t out[ML_KEM_SHARED_SECRET_BYTES], scalar_sub(&v, &mask); scalar_compress(&v, 1); scalar_encode_1(out, &v); + + OPENSSL_cleanse((void *)&v, sizeof(v)); + OPENSSL_cleanse((void *)&mask, sizeof(mask)); } /*- @@ -1737,8 +1770,8 @@ static __owur int genkey(const uint8_t seed[ML_KEM_SEED_BYTES], ret = 1; end: - OPENSSL_cleanse((void *)augmented_seed, ML_KEM_RANDOM_BYTES); - OPENSSL_cleanse((void *)sigma, ML_KEM_RANDOM_BYTES); + OPENSSL_cleanse((void *)augmented_seed, sizeof(augmented_seed)); + OPENSSL_cleanse((void *)hashed, sizeof(hashed)); if (ret == 0) { ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR, "internal error while generating %s private key", @@ -1776,6 +1809,7 @@ static int encap(uint8_t *ctext, uint8_t secret[ML_KEM_SHARED_SECRET_BYTES], ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR, "internal error while performing %s encapsulation", key->vinfo->algorithm_name); + OPENSSL_cleanse((void *)Kr, sizeof(Kr)); return ret; } @@ -1822,6 +1856,7 @@ static int decap(uint8_t secret[ML_KEM_SHARED_SECRET_BYTES], ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR, "internal error while performing %s decapsulation", vinfo->algorithm_name); + OPENSSL_cleanse(failure_key, sizeof(failure_key)); return 0; } decrypt_cpa(decrypted, ctext, tmp, key); @@ -1830,6 +1865,8 @@ static int decap(uint8_t secret[ML_KEM_SHARED_SECRET_BYTES], || !encrypt_cpa(tmp_ctext, decrypted, r, tmp, mdctx, key)) { memcpy(secret, failure_key, ML_KEM_SHARED_SECRET_BYTES); OPENSSL_cleanse(decrypted, ML_KEM_SHARED_SECRET_BYTES); + OPENSSL_cleanse(Kr, sizeof(Kr)); + OPENSSL_cleanse(failure_key, sizeof(failure_key)); return 1; } mask = constant_time_eq_int_8(0, @@ -1838,6 +1875,7 @@ static int decap(uint8_t secret[ML_KEM_SHARED_SECRET_BYTES], secret[i] = constant_time_select_8(mask, Kr[i], failure_key[i]); OPENSSL_cleanse(decrypted, ML_KEM_SHARED_SECRET_BYTES); OPENSSL_cleanse(Kr, sizeof(Kr)); + OPENSSL_cleanse(failure_key, sizeof(failure_key)); return 1; } @@ -1845,7 +1883,7 @@ static int decap(uint8_t secret[ML_KEM_SHARED_SECRET_BYTES], * After allocating storage for public or private key data, update the key * component pointers to reference that storage. */ -static __owur int add_storage(scalar *p, int private, ML_KEM_KEY *key) +static __owur int add_storage(scalar *p, int private, int dup, ML_KEM_KEY *key) { int rank = key->vinfo->rank; @@ -1854,9 +1892,12 @@ static __owur int add_storage(scalar *p, int private, ML_KEM_KEY *key) /* * We're adding key material, the seed buffer will now hold |rho| and - * |pkhash|. + * |pkhash|. Zero the key hash when creating fresh keys; when + * duplicating, |key| was memdup'd from the source so |seedbuf| + * already carries the correct |rho|/|pkhash| bytes — preserve them. */ - memset(key->seedbuf, 0, sizeof(key->seedbuf)); + if (dup == 0) + memset(key->seedbuf, 0, sizeof(key->seedbuf)); key->rho = key->seedbuf; key->pkhash = key->seedbuf + ML_KEM_RANDOM_BYTES; key->d = key->z = NULL; @@ -1980,18 +2021,18 @@ ML_KEM_KEY *ossl_ml_kem_key_dup(const ML_KEM_KEY *key, int selection) selection = 0; else if (!ossl_ml_kem_have_prvkey(key)) selection &= ~OSSL_KEYMGMT_SELECT_PRIVATE_KEY; + else if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + selection &= ~OSSL_KEYMGMT_SELECT_PUBLIC_KEY; switch (selection & OSSL_KEYMGMT_SELECT_KEYPAIR) { case 0: ok = 1; break; case OSSL_KEYMGMT_SELECT_PUBLIC_KEY: - ok = add_storage(OPENSSL_memdup(key->t, key->vinfo->puballoc), 0, ret); - ret->rho = ret->seedbuf; - ret->pkhash = ret->rho + ML_KEM_RANDOM_BYTES; + ok = add_storage(OPENSSL_memdup(key->t, key->vinfo->puballoc), 0, 1, ret); break; case OSSL_KEYMGMT_SELECT_PRIVATE_KEY: - ok = add_storage(OPENSSL_memdup(key->t, key->vinfo->prvalloc), 1, ret); + ok = add_storage(OPENSSL_memdup(key->t, key->vinfo->prvalloc), 1, 1, ret); /* Duplicated keys retain |d|, if available */ if (key->d != NULL) ret->d = ret->z + ML_KEM_RANDOM_BYTES; @@ -2111,7 +2152,7 @@ int ossl_ml_kem_parse_public_key(const uint8_t *in, size_t len, ML_KEM_KEY *key) || (mdctx = EVP_MD_CTX_new()) == NULL) return 0; - if (add_storage(OPENSSL_malloc(vinfo->puballoc), 0, key)) + if (add_storage(OPENSSL_malloc(vinfo->puballoc), 0, 0, key)) ret = parse_pubkey(in, mdctx, key); if (!ret) @@ -2139,7 +2180,7 @@ int ossl_ml_kem_parse_private_key(const uint8_t *in, size_t len, || (mdctx = EVP_MD_CTX_new()) == NULL) return 0; - if (add_storage(OPENSSL_malloc(vinfo->prvalloc), 1, key)) + if (add_storage(OPENSSL_malloc(vinfo->prvalloc), 1, 0, key)) ret = parse_prvkey(in, mdctx, key); if (!ret) @@ -2187,7 +2228,7 @@ int ossl_ml_kem_genkey(uint8_t *pubenc, size_t publen, ML_KEM_KEY *key) */ CONSTTIME_SECRET(seed, ML_KEM_SEED_BYTES); - if (add_storage(OPENSSL_malloc(vinfo->prvalloc), 1, key)) + if (add_storage(OPENSSL_malloc(vinfo->prvalloc), 1, 0, key)) ret = genkey(seed, mdctx, pubenc, key); OPENSSL_cleanse(seed, sizeof(seed)); @@ -2196,6 +2237,9 @@ int ossl_ml_kem_genkey(uint8_t *pubenc, size_t publen, ML_KEM_KEY *key) EVP_MD_CTX_free(mdctx); if (!ret) { + /* Erase any partial public key output */ + if (pubenc != NULL) + OPENSSL_cleanse(pubenc, vinfo->pubkey_bytes); ossl_ml_kem_key_reset(key); return 0; } @@ -2254,6 +2298,10 @@ int ossl_ml_kem_encap_seed(uint8_t *ctext, size_t clen, } #undef case_encap_seed + /* Erase any partial ciphertext output on failure */ + if (!ret) + OPENSSL_cleanse(ctext, clen); + /* Declassify secret inputs and derived outputs before returning control */ CONSTTIME_DECLASSIFY(entropy, elen); CONSTTIME_DECLASSIFY(ctext, clen); @@ -2268,6 +2316,7 @@ int ossl_ml_kem_encap_rand(uint8_t *ctext, size_t clen, const ML_KEM_KEY *key) { uint8_t r[ML_KEM_RANDOM_BYTES]; + int ret; if (key == NULL) return 0; @@ -2277,8 +2326,11 @@ int ossl_ml_kem_encap_rand(uint8_t *ctext, size_t clen, < 1) return 0; - return ossl_ml_kem_encap_seed(ctext, clen, shared_secret, slen, + ret = ossl_ml_kem_encap_seed(ctext, clen, shared_secret, slen, r, sizeof(r), key); + + OPENSSL_cleanse((void *)r, sizeof(r)); + return ret; } int ossl_ml_kem_decap(uint8_t *shared_secret, size_t slen, @@ -2293,11 +2345,13 @@ int ossl_ml_kem_decap(uint8_t *shared_secret, size_t slen, #endif /* Need a private key here */ - if (!ossl_ml_kem_have_prvkey(key)) + if (!ossl_ml_kem_have_prvkey(key) + || shared_secret == NULL + || slen < ML_KEM_SHARED_SECRET_BYTES) return 0; vinfo = key->vinfo; - if (shared_secret == NULL || slen != ML_KEM_SHARED_SECRET_BYTES + if (slen != ML_KEM_SHARED_SECRET_BYTES || ctext == NULL || clen != vinfo->ctext_bytes || (mdctx = EVP_MD_CTX_new()) == NULL) { (void)RAND_bytes_ex(key->libctx, shared_secret, @@ -2326,6 +2380,7 @@ int ossl_ml_kem_decap(uint8_t *shared_secret, size_t slen, \ ret = decap(shared_secret, ctext, cbuf, tmp, mdctx, key); \ OPENSSL_cleanse((void *)tmp, sizeof(tmp)); \ + OPENSSL_cleanse((void *)cbuf, sizeof(cbuf)); \ break; \ } switch (vinfo->evp_type) { diff --git a/deps/openssl/openssl/crypto/modes/asm/aes-gcm-avx512.pl b/deps/openssl/openssl/crypto/modes/asm/aes-gcm-avx512.pl index 054672bb6b9b..3da7c69cb985 100644 --- a/deps/openssl/openssl/crypto/modes/asm/aes-gcm-avx512.pl +++ b/deps/openssl/openssl/crypto/modes/asm/aes-gcm-avx512.pl @@ -1,4 +1,4 @@ -# Copyright 2021-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2021-2026 The OpenSSL Project Authors. All Rights Reserved. # Copyright (c) 2021, Intel Corporation. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use @@ -72,6 +72,13 @@ } } +if (!$avx512vaes && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx512vaes = ($1>=11); #icx started with clang 11 + } +} + open OUT, "| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT = *OUT; diff --git a/deps/openssl/openssl/crypto/modes/asm/aesni-gcm-x86_64.pl b/deps/openssl/openssl/crypto/modes/asm/aesni-gcm-x86_64.pl index c63570bae42f..202883dac35e 100644 --- a/deps/openssl/openssl/crypto/modes/asm/aesni-gcm-x86_64.pl +++ b/deps/openssl/openssl/crypto/modes/asm/aesni-gcm-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2013-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2013-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -73,6 +73,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/deps/openssl/openssl/crypto/modes/asm/ghash-x86_64.pl b/deps/openssl/openssl/crypto/modes/asm/ghash-x86_64.pl index 6ef8e555d0a2..181793c5523c 100644 --- a/deps/openssl/openssl/crypto/modes/asm/ghash-x86_64.pl +++ b/deps/openssl/openssl/crypto/modes/asm/ghash-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2010-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2010-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -121,6 +121,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/deps/openssl/openssl/crypto/pem/pvkfmt.c b/deps/openssl/openssl/crypto/pem/pvkfmt.c index 9bfbb01e430a..8b81f66e0e3b 100644 --- a/deps/openssl/openssl/crypto/pem/pvkfmt.c +++ b/deps/openssl/openssl/crypto/pem/pvkfmt.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2005-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -893,13 +893,13 @@ static void *do_PVK_body_key(const unsigned char **in, (unsigned char *)psbuf, inlen, libctx, propq)) goto err; p += saltlen; - /* Copy BLOBHEADER across, decrypt rest */ - memcpy(enctmp, p, 8); - p += 8; if (keylen < 8) { ERR_raise(ERR_LIB_PEM, PEM_R_PVK_TOO_SHORT); goto err; } + /* Copy BLOBHEADER across, decrypt rest */ + memcpy(enctmp, p, 8); + p += 8; inlen = keylen - 8; q = enctmp + 8; if ((rc4 = EVP_CIPHER_fetch(libctx, "RC4", propq)) == NULL) diff --git a/deps/openssl/openssl/crypto/pkcs12/p12_add.c b/deps/openssl/openssl/crypto/pkcs12/p12_add.c index 4750974d6044..977aa8b65835 100644 --- a/deps/openssl/openssl/crypto/pkcs12/p12_add.c +++ b/deps/openssl/openssl/crypto/pkcs12/p12_add.c @@ -1,5 +1,5 @@ /* - * Copyright 1999-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1999-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -222,6 +222,6 @@ STACK_OF(PKCS7) *PKCS12_unpack_authsafes(const PKCS12 *p12) } return p7s; err: - sk_PKCS7_free(p7s); + sk_PKCS7_pop_free(p7s, PKCS7_free); return NULL; } diff --git a/deps/openssl/openssl/crypto/pkcs12/p12_decr.c b/deps/openssl/openssl/crypto/pkcs12/p12_decr.c index 0d415e755a18..31766989fc4a 100644 --- a/deps/openssl/openssl/crypto/pkcs12/p12_decr.c +++ b/deps/openssl/openssl/crypto/pkcs12/p12_decr.c @@ -55,7 +55,8 @@ unsigned char *PKCS12_pbe_crypt_ex(const X509_ALGOR *algor, if ((EVP_CIPHER_get_flags(EVP_CIPHER_CTX_get0_cipher(ctx)) & EVP_CIPH_FLAG_CIPHER_WITH_MAC) != 0) { - if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_TLS1_AAD, 0, &mac_len) < 0) { + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_TLS1_AAD, 0, &mac_len) + <= 0) { ERR_raise(ERR_LIB_PKCS12, ERR_R_INTERNAL_ERROR); goto err; } @@ -70,7 +71,7 @@ unsigned char *PKCS12_pbe_crypt_ex(const X509_ALGOR *algor, inlen -= mac_len; if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, (int)mac_len, (unsigned char *)in + inlen) - < 0) { + <= 0) { ERR_raise(ERR_LIB_PKCS12, ERR_R_INTERNAL_ERROR); goto err; } diff --git a/deps/openssl/openssl/crypto/pkcs12/p12_utl.c b/deps/openssl/openssl/crypto/pkcs12/p12_utl.c index a6f3248c554c..f252fd1a0061 100644 --- a/deps/openssl/openssl/crypto/pkcs12/p12_utl.c +++ b/deps/openssl/openssl/crypto/pkcs12/p12_utl.c @@ -186,6 +186,8 @@ char *OPENSSL_uni2utf8(const unsigned char *uni, int unilen) /* string must contain an even number of bytes */ if (unilen & 1) return NULL; + if (unilen < 0) + return NULL; for (asclen = 0, i = 0; i < unilen;) { j = bmp_to_utf8(NULL, uni + i, unilen - i); diff --git a/deps/openssl/openssl/crypto/pkcs7/pk7_doit.c b/deps/openssl/openssl/crypto/pkcs7/pk7_doit.c index 1ec7895fc197..aaf3c19aaeae 100644 --- a/deps/openssl/openssl/crypto/pkcs7/pk7_doit.c +++ b/deps/openssl/openssl/crypto/pkcs7/pk7_doit.c @@ -1200,7 +1200,7 @@ PKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx) rsk = p7->d.signed_and_enveloped->recipientinfo; if (rsk == NULL) return NULL; - if (sk_PKCS7_RECIP_INFO_num(rsk) <= idx) + if (idx < 0 || sk_PKCS7_RECIP_INFO_num(rsk) <= idx) return NULL; ri = sk_PKCS7_RECIP_INFO_value(rsk, idx); return ri->issuer_and_serial; diff --git a/deps/openssl/openssl/crypto/pkcs7/pk7_lib.c b/deps/openssl/openssl/crypto/pkcs7/pk7_lib.c index 6cd0c3f025c5..2fd753e873d0 100644 --- a/deps/openssl/openssl/crypto/pkcs7/pk7_lib.c +++ b/deps/openssl/openssl/crypto/pkcs7/pk7_lib.c @@ -537,7 +537,7 @@ int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md) } ERR_raise(ERR_LIB_PKCS7, PKCS7_R_WRONG_CONTENT_TYPE); - return 1; + return 0; } STACK_OF(PKCS7_SIGNER_INFO) *PKCS7_get_signer_info(PKCS7 *p7) @@ -727,6 +727,10 @@ int PKCS7_stream(unsigned char ***boundary, PKCS7 *p7) break; case NID_pkcs7_signedAndEnveloped: + if (p7->d.signed_and_enveloped == NULL || p7->d.signed_and_enveloped->enc_data == NULL) { + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_NO_CONTENT); + break; + } os = p7->d.signed_and_enveloped->enc_data->enc_data; if (os == NULL) { os = ASN1_OCTET_STRING_new(); @@ -735,6 +739,10 @@ int PKCS7_stream(unsigned char ***boundary, PKCS7 *p7) break; case NID_pkcs7_enveloped: + if (p7->d.enveloped == NULL || p7->d.enveloped->enc_data == NULL) { + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_NO_CONTENT); + break; + } os = p7->d.enveloped->enc_data->enc_data; if (os == NULL) { os = ASN1_OCTET_STRING_new(); @@ -747,7 +755,13 @@ int PKCS7_stream(unsigned char ***boundary, PKCS7 *p7) ERR_raise(ERR_LIB_PKCS7, PKCS7_R_NO_CONTENT); break; } - os = p7->d.sign->contents->d.data; + + if (!PKCS7_type_is_data(p7->d.sign->contents)) { + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_UNSUPPORTED_CONTENT_TYPE); + break; + } + + os = PKCS7_get_octet_string(p7->d.sign->contents); break; default: diff --git a/deps/openssl/openssl/crypto/poly1305/asm/poly1305-x86.pl b/deps/openssl/openssl/crypto/poly1305/asm/poly1305-x86.pl index c91d01fb3ba4..6d367d858da7 100755 --- a/deps/openssl/openssl/crypto/poly1305/asm/poly1305-x86.pl +++ b/deps/openssl/openssl/crypto/poly1305/asm/poly1305-x86.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2016-2020 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2016-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -73,6 +73,13 @@ if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:clang|LLVM) version|based on LLVM) ([0-9]+\.[0-9]+)/) { $avx = ($2>=3.0) + ($2>3.0); } + + if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } + } } ######################################################################## diff --git a/deps/openssl/openssl/crypto/poly1305/asm/poly1305-x86_64.pl b/deps/openssl/openssl/crypto/poly1305/asm/poly1305-x86_64.pl index 305099ca0308..081fe4117ad9 100755 --- a/deps/openssl/openssl/crypto/poly1305/asm/poly1305-x86_64.pl +++ b/deps/openssl/openssl/crypto/poly1305/asm/poly1305-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2016-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2016-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -95,6 +95,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/deps/openssl/openssl/crypto/rand/rand_lib.c b/deps/openssl/openssl/crypto/rand/rand_lib.c index f03bb2967c43..df70d1c2b1da 100644 --- a/deps/openssl/openssl/crypto/rand/rand_lib.c +++ b/deps/openssl/openssl/crypto/rand/rand_lib.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -674,7 +674,6 @@ static EVP_RAND_CTX *rand_new_drbg(OSSL_LIB_CTX *libctx, EVP_RAND_CTX *parent, EVP_RAND_CTX *ctx; OSSL_PARAM params[9], *p = params; const OSSL_PARAM *settables; - const char *prov_name; char *name, *cipher; int use_df = 1; @@ -686,7 +685,6 @@ static EVP_RAND_CTX *rand_new_drbg(OSSL_LIB_CTX *libctx, EVP_RAND_CTX *parent, ERR_raise(ERR_LIB_RAND, RAND_R_UNABLE_TO_FETCH_DRBG); return NULL; } - prov_name = ossl_provider_name(EVP_RAND_get0_provider(rand)); ctx = EVP_RAND_CTX_new(rand, parent); EVP_RAND_free(rand); if (ctx == NULL) { @@ -704,9 +702,6 @@ static EVP_RAND_CTX *rand_new_drbg(OSSL_LIB_CTX *libctx, EVP_RAND_CTX *parent, && OSSL_PARAM_locate_const(settables, OSSL_DRBG_PARAM_DIGEST)) *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_DIGEST, dgbl->rng_digest, 0); - if (prov_name != NULL) - *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PROV_PARAM_CORE_PROV_NAME, - (char *)prov_name, 0); if (dgbl->rng_propq != NULL) *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_PROPERTIES, dgbl->rng_propq, 0); @@ -864,7 +859,10 @@ static EVP_RAND_CTX *rand_get0_public(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl) return NULL; rand = rand_new_drbg(ctx, primary, SECONDARY_RESEED_INTERVAL, SECONDARY_RESEED_TIME_INTERVAL); - CRYPTO_THREAD_set_local(&dgbl->public, rand); + if (!CRYPTO_THREAD_set_local(&dgbl->public, rand)) { + EVP_RAND_CTX_free(rand); + rand = NULL; + } } return rand; } @@ -903,7 +901,10 @@ static EVP_RAND_CTX *rand_get0_private(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl) return NULL; rand = rand_new_drbg(ctx, primary, SECONDARY_RESEED_INTERVAL, SECONDARY_RESEED_TIME_INTERVAL); - CRYPTO_THREAD_set_local(&dgbl->private, rand); + if (!CRYPTO_THREAD_set_local(&dgbl->private, rand)) { + EVP_RAND_CTX_free(rand); + rand = NULL; + } } return rand; } diff --git a/deps/openssl/openssl/crypto/rsa/rsa_gen.c b/deps/openssl/openssl/crypto/rsa/rsa_gen.c index 554f9d349b85..777a485422dd 100644 --- a/deps/openssl/openssl/crypto/rsa/rsa_gen.c +++ b/deps/openssl/openssl/crypto/rsa/rsa_gen.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -636,7 +636,6 @@ static int rsa_keygen(OSSL_LIB_CTX *libctx, RSA *rsa, int bits, int primes, OSSL_SELF_TEST_get_callback(libctx, &stcb, &stcbarg); ok = rsa_keygen_pairwise_test(rsa, stcb, stcbarg); if (!ok) { - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); /* Clear intermediate results */ BN_clear_free(rsa->d); BN_clear_free(rsa->p); diff --git a/deps/openssl/openssl/crypto/rsa/rsa_ossl.c b/deps/openssl/openssl/crypto/rsa/rsa_ossl.c index 2fcf02a9ab05..73a4b7c20a47 100644 --- a/deps/openssl/openssl/crypto/rsa/rsa_ossl.c +++ b/deps/openssl/openssl/crypto/rsa/rsa_ossl.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -160,6 +160,14 @@ static int rsa_ossl_public_encrypt(int flen, const unsigned char *from, * See SP800-56Br2, section 7.1.1.1 * RSAEP: 1 < f < (n – 1). * (where f is the plaintext). + * + * This bound is somewhat overkill here. RSASVE.GENERATE (7.2.1.2) + * regenerates z until 1 < z < n-1, so on that path the plaintext is in + * range unconditionally. On the OAEP path the leading 0x00 octet of the + * encoding forces m < n-1 unconditionally, while m = 0 or 1 is only + * cryptographically negligible, not impossible. The check is kept to + * mirror the RSADP bound in rsa_ossl_private_decrypt() and to keep RSAEP + * faithful to 7.1.1 of the SP; nothing in the SP relies on it here. */ if (padding == RSA_NO_PADDING) { BIGNUM *nminus1 = BN_CTX_get(ctx); @@ -572,6 +580,12 @@ static int rsa_ossl_private_decrypt(int flen, const unsigned char *from, * See SP800-56Br2, section 7.1.2.1 * RSADP: 1 < f < (n – 1) * (where f is the ciphertext). + * + * Kept under FIPS_MODULE because SP 800-56B KTS-OAEP (section 9.2) also + * decrypts through RSADP and needs this bound in a FIPS build, and there + * is no KTS-OAEP-specific path to attach it to. The non-FIPS RSASVE path + * applies the same 1 < c < n-1 in rsasve_recover() + * (providers/implementations/kem/rsa_kem.c); keep the two in step. */ if (padding == RSA_NO_PADDING) { BIGNUM *nminus1 = BN_CTX_get(ctx); diff --git a/deps/openssl/openssl/crypto/sha/asm/sha1-586.pl b/deps/openssl/openssl/crypto/sha/asm/sha1-586.pl index 00350324a117..81c3658b0adf 100644 --- a/deps/openssl/openssl/crypto/sha/asm/sha1-586.pl +++ b/deps/openssl/openssl/crypto/sha/asm/sha1-586.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 1998-2020 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 1998-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -146,6 +146,9 @@ $ymm=1 if ($xmm && !$ymm && `$ENV{CC} -v 2>&1` =~ /((?:clang|LLVM) version|based on LLVM) ([0-9]+\.[0-9]+)/ && $2>=3.0); # first version supporting AVX +$ymm=1 if ($xmm && !$ymm && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` =~ /#define __clang_major__.([0-9]+)/ && + $1>=11); #icx started with clang 11 + $shaext=$xmm; ### set to zero if compiling for 1.0.1 &external_label("OPENSSL_ia32cap_P") if ($xmm); diff --git a/deps/openssl/openssl/crypto/sha/asm/sha1-mb-x86_64.pl b/deps/openssl/openssl/crypto/sha/asm/sha1-mb-x86_64.pl index d9d1630d16db..59042c90b2fe 100644 --- a/deps/openssl/openssl/crypto/sha/asm/sha1-mb-x86_64.pl +++ b/deps/openssl/openssl/crypto/sha/asm/sha1-mb-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2013-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2013-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -76,6 +76,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/deps/openssl/openssl/crypto/sha/asm/sha1-x86_64.pl b/deps/openssl/openssl/crypto/sha/asm/sha1-x86_64.pl index 30c545cf419a..829fe16a8272 100755 --- a/deps/openssl/openssl/crypto/sha/asm/sha1-x86_64.pl +++ b/deps/openssl/openssl/crypto/sha/asm/sha1-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2006-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2006-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -124,6 +124,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + $shaext=1; ### set to zero if compiling for 1.0.1 $avx=1 if (!$shaext && $avx); diff --git a/deps/openssl/openssl/crypto/sha/asm/sha256-586.pl b/deps/openssl/openssl/crypto/sha/asm/sha256-586.pl index 8e19cd875e3f..3983e55ff9e8 100644 --- a/deps/openssl/openssl/crypto/sha/asm/sha256-586.pl +++ b/deps/openssl/openssl/crypto/sha/asm/sha256-586.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2007-2020 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2007-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -99,6 +99,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if ($xmm && !$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + $shaext=$xmm; ### set to zero if compiling for 1.0.1 $unroll_after = 64*4; # If pre-evicted from L1P cache first spin of diff --git a/deps/openssl/openssl/crypto/sha/asm/sha256-mb-x86_64.pl b/deps/openssl/openssl/crypto/sha/asm/sha256-mb-x86_64.pl index 9398b7954a7f..e53517d787f6 100644 --- a/deps/openssl/openssl/crypto/sha/asm/sha256-mb-x86_64.pl +++ b/deps/openssl/openssl/crypto/sha/asm/sha256-mb-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2013-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2013-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -77,6 +77,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/deps/openssl/openssl/crypto/sha/asm/sha512-x86_64.pl b/deps/openssl/openssl/crypto/sha/asm/sha512-x86_64.pl index b37058ae03fa..cbdd7df67561 100755 --- a/deps/openssl/openssl/crypto/sha/asm/sha512-x86_64.pl +++ b/deps/openssl/openssl/crypto/sha/asm/sha512-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2005-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2005-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -140,6 +140,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + $shaext=1; ### set to zero if compiling for 1.0.1 $avx=1 if (!$shaext && $avx); diff --git a/deps/openssl/openssl/crypto/sha/sha_riscv.c b/deps/openssl/openssl/crypto/sha/sha_riscv.c index 61ceaa22a4bd..dad1b1187671 100644 --- a/deps/openssl/openssl/crypto/sha/sha_riscv.c +++ b/deps/openssl/openssl/crypto/sha/sha_riscv.c @@ -1,5 +1,5 @@ /* - * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2023-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -17,9 +17,9 @@ void sha256_block_data_order_zvkb_zvknha_or_zvknhb(void *ctx, const void *in, size_t num); void sha256_block_data_order_c(void *ctx, const void *in, size_t num); -void sha256_block_data_order(SHA256_CTX *ctx, const void *in, size_t num); +void sha256_block_data_order(void *ctx, const void *in, size_t num); -void sha256_block_data_order(SHA256_CTX *ctx, const void *in, size_t num) +void sha256_block_data_order(void *ctx, const void *in, size_t num) { if (RISCV_HAS_ZVKB() && (RISCV_HAS_ZVKNHA() || RISCV_HAS_ZVKNHB()) && riscv_vlen() >= 128) { sha256_block_data_order_zvkb_zvknha_or_zvknhb(ctx, in, num); @@ -30,9 +30,9 @@ void sha256_block_data_order(SHA256_CTX *ctx, const void *in, size_t num) void sha512_block_data_order_zvkb_zvknhb(void *ctx, const void *in, size_t num); void sha512_block_data_order_c(void *ctx, const void *in, size_t num); -void sha512_block_data_order(SHA512_CTX *ctx, const void *in, size_t num); +void sha512_block_data_order(void *ctx, const void *in, size_t num); -void sha512_block_data_order(SHA512_CTX *ctx, const void *in, size_t num) +void sha512_block_data_order(void *ctx, const void *in, size_t num) { if (RISCV_HAS_ZVKB_AND_ZVKNHB() && riscv_vlen() >= 128) { sha512_block_data_order_zvkb_zvknhb(ctx, in, num); diff --git a/deps/openssl/openssl/crypto/slh_dsa/slh_dsa.c b/deps/openssl/openssl/crypto/slh_dsa/slh_dsa.c index 41fc494048b4..4cf75089920a 100644 --- a/deps/openssl/openssl/crypto/slh_dsa/slh_dsa.c +++ b/deps/openssl/openssl/crypto/slh_dsa/slh_dsa.c @@ -8,6 +8,7 @@ */ #include #include +#include #include #include #include "slh_dsa_local.h" @@ -122,8 +123,13 @@ static int slh_sign_internal(SLH_DSA_HASH_CTX *hctx, err: if (!WPACKET_finish(wpkt)) ret = 0; + OPENSSL_cleanse(m_digest, sizeof(m_digest)); + OPENSSL_cleanse(pk_fors, sizeof(pk_fors)); if (ret) *sig_len = sig_len_expected; + else + /* Erase any partial signature output */ + OPENSSL_cleanse(sig, sig_len_expected); return ret; } @@ -148,6 +154,7 @@ static int slh_verify_internal(SLH_DSA_HASH_CTX *hctx, const uint8_t *msg, size_t msg_len, const uint8_t *sig, size_t sig_len) { + int ret = 0; const SLH_DSA_KEY *pub = hctx->key; SLH_HASH_FUNC_DECLARE(pub, hashf); SLH_ADRS_FUNC_DECLARE(pub, adrsf); @@ -185,7 +192,7 @@ static int slh_verify_internal(SLH_DSA_HASH_CTX *hctx, if (!hashf->H_MSG(hctx, r, pk_seed, pk_root, msg, msg_len, m_digest, sizeof(m_digest))) - return 0; + goto err; /* * Get md (the first md_len bytes of m_digest to use in @@ -195,16 +202,20 @@ static int slh_verify_internal(SLH_DSA_HASH_CTX *hctx, if (!PACKET_buf_init(m_digest_rpkt, m_digest, sizeof(m_digest)) || !PACKET_get_bytes(m_digest_rpkt, &md, md_len) || !get_tree_ids(m_digest_rpkt, params, &tree_id, &leaf_id)) - return 0; + goto err; adrsf->set_tree_address(adrs, tree_id); adrsf->set_type_and_clear(adrs, SLH_ADRS_TYPE_FORS_TREE); adrsf->set_keypair_address(adrs, leaf_id); - return ossl_slh_fors_pk_from_sig(hctx, sig_rpkt, md, pk_seed, adrs, - pk_fors, sizeof(pk_fors)) + ret = ossl_slh_fors_pk_from_sig(hctx, sig_rpkt, md, pk_seed, adrs, + pk_fors, sizeof(pk_fors)) && ossl_slh_ht_verify(hctx, pk_fors, sig_rpkt, pk_seed, tree_id, leaf_id, pk_root) && PACKET_remaining(sig_rpkt) == 0; +err: + OPENSSL_cleanse(m_digest, sizeof(m_digest)); + OPENSSL_cleanse(pk_fors, sizeof(pk_fors)); + return ret; } /** @@ -292,8 +303,13 @@ int ossl_slh_dsa_sign(SLH_DSA_HASH_CTX *slh_ctx, return 0; } ret = slh_sign_internal(slh_ctx, m, m_len, sig, siglen, sigsize, add_rand); - if (m != msg && m != m_tmp) - OPENSSL_free(m); + /* The encoded message may contain confidential message content */ + if (m != msg) { + if (m != m_tmp) + OPENSSL_clear_free(m, m_len); + else + OPENSSL_cleanse(m_tmp, sizeof(m_tmp)); + } return ret; } @@ -317,8 +333,13 @@ int ossl_slh_dsa_verify(SLH_DSA_HASH_CTX *slh_ctx, return 0; ret = slh_verify_internal(slh_ctx, m, m_len, sig, sig_len); - if (m != msg && m != m_tmp) - OPENSSL_free(m); + /* The encoded message may contain confidential message content */ + if (m != msg) { + if (m != m_tmp) + OPENSSL_clear_free(m, m_len); + else + OPENSSL_cleanse(m_tmp, sizeof(m_tmp)); + } return ret; } diff --git a/deps/openssl/openssl/crypto/slh_dsa/slh_dsa_hash_ctx.c b/deps/openssl/openssl/crypto/slh_dsa/slh_dsa_hash_ctx.c index 9dca01acf5ff..513f7f7dafc1 100644 --- a/deps/openssl/openssl/crypto/slh_dsa/slh_dsa_hash_ctx.c +++ b/deps/openssl/openssl/crypto/slh_dsa/slh_dsa_hash_ctx.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -109,5 +109,6 @@ void ossl_slh_dsa_hash_ctx_free(SLH_DSA_HASH_CTX *ctx) if (ctx->md_big_ctx != ctx->md_ctx) EVP_MD_CTX_free(ctx->md_big_ctx); EVP_MAC_CTX_free(ctx->hmac_ctx); - OPENSSL_free(ctx); + /* Erases the |scratch| hash intermediates */ + OPENSSL_clear_free(ctx, sizeof(*ctx)); } diff --git a/deps/openssl/openssl/crypto/slh_dsa/slh_dsa_key.c b/deps/openssl/openssl/crypto/slh_dsa/slh_dsa_key.c index 6d778a39f46d..9e980bf1bfb0 100644 --- a/deps/openssl/openssl/crypto/slh_dsa/slh_dsa_key.c +++ b/deps/openssl/openssl/crypto/slh_dsa/slh_dsa_key.c @@ -313,6 +313,12 @@ int ossl_slh_dsa_key_fromdata(SLH_DSA_KEY *key, const OSSL_PARAM params[], key->pub = p; return 1; err: + /* + * A private key of unexpected length may have been copied into |priv| + * before |has_priv| was set, in which case the reset below would not + * erase it, so cleanse unconditionally. + */ + OPENSSL_cleanse(key->priv, sizeof(key->priv)); ossl_slh_dsa_key_reset(key); return 0; } diff --git a/deps/openssl/openssl/crypto/slh_dsa/slh_dsa_local.h b/deps/openssl/openssl/crypto/slh_dsa/slh_dsa_local.h index 57dfc1eb1301..d2eccdd08a9a 100644 --- a/deps/openssl/openssl/crypto/slh_dsa/slh_dsa_local.h +++ b/deps/openssl/openssl/crypto/slh_dsa/slh_dsa_local.h @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -45,12 +45,24 @@ * NOTE: Any changes to this structure will need updating in * ossl_slh_dsa_hash_ctx_dup(). */ +/* A SHA-512 digest plus two |n| byte node values */ +#define SLH_DSA_HASH_SCRATCH_LEN (64 + 2 * SLH_MAX_N) + struct slh_dsa_hash_ctx_st { const SLH_DSA_KEY *key; /* This key is not owned by this object */ EVP_MD_CTX *md_ctx; /* Either SHAKE OR SHA-256 */ EVP_MD_CTX *md_big_ctx; /* Either SHA-512 or points to |md_ctx| for SHA-256*/ EVP_MAC_CTX *hmac_ctx; /* required by SHA algorithms for PRFmsg() */ int hmac_digest_used; /* Used for lazy init of hmac_ctx digest */ + /* + * Working storage for the SHA2 hash function intermediates, used in + * place of local stack copies, so that potentially sensitive + * intermediate data lives in one place and is erased when this object + * is freed (FIPS 205 section 3.1). The SHAKE hash functions write + * their output directly to the caller's buffer and need no scratch. + * Not used concurrently. + */ + uint8_t scratch[SLH_DSA_HASH_SCRATCH_LEN]; }; __owur int ossl_slh_wots_pk_gen(SLH_DSA_HASH_CTX *ctx, const uint8_t *sk_seed, diff --git a/deps/openssl/openssl/crypto/slh_dsa/slh_fors.c b/deps/openssl/openssl/crypto/slh_dsa/slh_fors.c index 78587589db42..7c8854cc9b38 100644 --- a/deps/openssl/openssl/crypto/slh_dsa/slh_fors.c +++ b/deps/openssl/openssl/crypto/slh_dsa/slh_fors.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -17,8 +17,8 @@ /* a = 6, 8, 9, 12 or 14 - There are (2^a) merkle trees */ #define SLH_MAX_A 9 -#define SLH_MAX_K_TIMES_A (SLH_MAX_A * SLH_MAX_K) -#define SLH_MAX_ROOTS (SLH_MAX_K_TIMES_A * SLH_MAX_N) +/* The FORS public key is computed from the roots of k Merkle trees */ +#define SLH_MAX_ROOTS (SLH_MAX_K * SLH_MAX_N) static void slh_base_2b(const uint8_t *in, uint32_t b, uint32_t *out, size_t out_len); @@ -87,25 +87,25 @@ static int slh_fors_node(SLH_DSA_HASH_CTX *ctx, const uint8_t *sk_seed, if (height == 0) { /* Gets here for leaf nodes */ - if (!slh_fors_sk_gen(ctx, sk_seed, pk_seed, adrs, node_id, sk, sizeof(sk))) - return 0; - adrsf->set_tree_height(adrs, 0); - adrsf->set_tree_index(adrs, node_id); - ret = key->hash_func->F(ctx, pk_seed, adrs, sk, n, node, node_len); + if (slh_fors_sk_gen(ctx, sk_seed, pk_seed, adrs, node_id, sk, sizeof(sk))) { + adrsf->set_tree_height(adrs, 0); + adrsf->set_tree_index(adrs, node_id); + ret = key->hash_func->F(ctx, pk_seed, adrs, sk, n, node, node_len); + } OPENSSL_cleanse(sk, n); - return ret; } else { - if (!slh_fors_node(ctx, sk_seed, pk_seed, adrs, 2 * node_id, height - 1, - lnode, sizeof(rnode)) - || !slh_fors_node(ctx, sk_seed, pk_seed, adrs, 2 * node_id + 1, - height - 1, rnode, sizeof(rnode))) - return 0; - adrsf->set_tree_height(adrs, height); - adrsf->set_tree_index(adrs, node_id); - if (!key->hash_func->H(ctx, pk_seed, adrs, lnode, rnode, node, node_len)) - return 0; + if (slh_fors_node(ctx, sk_seed, pk_seed, adrs, 2 * node_id, height - 1, + lnode, sizeof(lnode)) + && slh_fors_node(ctx, sk_seed, pk_seed, adrs, 2 * node_id + 1, + height - 1, rnode, sizeof(rnode))) { + adrsf->set_tree_height(adrs, height); + adrsf->set_tree_index(adrs, node_id); + ret = key->hash_func->H(ctx, pk_seed, adrs, lnode, rnode, node, node_len); + } + OPENSSL_cleanse(lnode, sizeof(lnode)); + OPENSSL_cleanse(rnode, sizeof(rnode)); } - return 1; + return ret; } /** @@ -132,6 +132,7 @@ int ossl_slh_fors_sign(SLH_DSA_HASH_CTX *ctx, const uint8_t *md, const uint8_t *sk_seed, const uint8_t *pk_seed, uint8_t *adrs, WPACKET *sig_wpkt) { + int ret = 0; const SLH_DSA_KEY *key = ctx->key; uint32_t tree_id, layer, s, tree_offset; uint32_t ids[SLH_MAX_K]; @@ -165,7 +166,7 @@ int ossl_slh_fors_sign(SLH_DSA_HASH_CTX *ctx, const uint8_t *md, if (!slh_fors_sk_gen(ctx, sk_seed, pk_seed, adrs, node_id + tree_id_times_two_power_a, out, sizeof(out)) || !WPACKET_memcpy(sig_wpkt, out, n)) - return 0; + goto err; /* * Traverse from the bottom of the tree (layer = 0) @@ -178,15 +179,18 @@ int ossl_slh_fors_sign(SLH_DSA_HASH_CTX *ctx, const uint8_t *md, s = node_id ^ 1; /* XOR gets the index of the other child in a binary tree */ if (!slh_fors_node(ctx, sk_seed, pk_seed, adrs, s + tree_offset, layer, out, sizeof(out))) - return 0; + goto err; node_id >>= 1; /* Get the parent node id */ tree_offset >>= 1; /* Each layer up has half as many nodes */ if (!WPACKET_memcpy(sig_wpkt, out, n)) - return 0; + goto err; } tree_id_times_two_power_a += two_power_a; } - return 1; + ret = 1; +err: + OPENSSL_cleanse(out, sizeof(out)); + return ret; } /** @@ -288,6 +292,8 @@ int ossl_slh_fors_pk_from_sig(SLH_DSA_HASH_CTX *ctx, PACKET *fors_sig_rpkt, err: if (!WPACKET_finish(wroot_pkt)) ret = 0; + /* At most one |n| byte root per tree was written */ + OPENSSL_cleanse(roots, k * n); return ret; } diff --git a/deps/openssl/openssl/crypto/slh_dsa/slh_hash.c b/deps/openssl/openssl/crypto/slh_dsa/slh_hash.c index bd112f1cb0db..b0023c955c3e 100644 --- a/deps/openssl/openssl/crypto/slh_dsa/slh_hash.c +++ b/deps/openssl/openssl/crypto/slh_dsa/slh_hash.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -92,12 +92,15 @@ slh_prf_msg_shake(SLH_DSA_HASH_CTX *ctx, const uint8_t *sk_prf, const uint8_t *opt_rand, const uint8_t *msg, size_t msg_len, WPACKET *pkt) { + int ret; unsigned char out[SLH_MAX_N]; const SLH_DSA_PARAMS *params = ctx->key->params; size_t n = params->n; - return xof_digest_3(ctx->md_ctx, sk_prf, n, opt_rand, n, msg, msg_len, out, n) + ret = xof_digest_3(ctx->md_ctx, sk_prf, n, opt_rand, n, msg, msg_len, out, n) && WPACKET_memcpy(pkt, out, n); + OPENSSL_cleanse(out, sizeof(out)); + return ret; } static int @@ -151,6 +154,7 @@ slh_hmsg_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *r, const uint8_t *pk_seed, const uint8_t *pk_root, const uint8_t *msg, size_t msg_len, uint8_t *out, size_t out_len) { + int ret; const SLH_DSA_PARAMS *params = hctx->key->params; size_t m = params->m; size_t n = params->n; @@ -163,9 +167,11 @@ slh_hmsg_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *r, const uint8_t *pk_seed, memcpy(seed, r, n); memcpy(seed + n, pk_seed, n); - return digest_4(hctx->md_big_ctx, r, n, pk_seed, n, pk_root, n, msg, msg_len, - seed + 2 * n) + ret = digest_4(hctx->md_big_ctx, r, n, pk_seed, n, pk_root, n, msg, msg_len, + seed + 2 * n) && (PKCS1_MGF1(out, m, seed, seed_len, hctx->key->md_big) == 0); + OPENSSL_cleanse(seed, sizeof(seed)); + return ret; } static int @@ -205,16 +211,23 @@ slh_prf_msg_sha2(SLH_DSA_HASH_CTX *hctx, && EVP_MAC_update(mctx, msg, msg_len) == 1 && EVP_MAC_final(mctx, mac, NULL, sizeof(mac)) == 1 && WPACKET_memcpy(pkt, mac, n); /* Truncate output to n bytes */ + OPENSSL_cleanse(mac, sizeof(mac)); return ret; } +/* + * The |digest| scratch storage in the hash context is used in place of a + * local stack buffer, and is erased when the hash context is freed + * (FIPS 205 section 3.1). On the PRF path it holds a derived chain secret. + */ static ossl_inline int -do_hash(EVP_MD_CTX *ctx, size_t n, const uint8_t *pk_seed, const uint8_t *adrs, +do_hash(SLH_DSA_HASH_CTX *hctx, EVP_MD_CTX *ctx, size_t n, + const uint8_t *pk_seed, const uint8_t *adrs, const uint8_t *m, size_t m_len, size_t b, uint8_t *out, size_t out_len) { int ret; uint8_t zeros[128] = { 0 }; - uint8_t digest[MAX_DIGEST_SIZE]; + uint8_t *digest = hctx->scratch; ret = digest_4(ctx, pk_seed, n, zeros, b - n, adrs, SLH_ADRSC_SIZE, m, m_len, digest); @@ -230,7 +243,7 @@ slh_prf_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *pk_seed, { size_t n = hctx->key->params->n; - return do_hash(hctx->md_ctx, n, pk_seed, adrs, sk_seed, n, + return do_hash(hctx, hctx->md_ctx, n, pk_seed, adrs, sk_seed, n, OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND1, out, out_len); } @@ -238,21 +251,22 @@ static int slh_f_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *pk_seed, const uint8_t *adrs, const uint8_t *m1, size_t m1_len, uint8_t *out, size_t out_len) { - return do_hash(hctx->md_ctx, hctx->key->params->n, pk_seed, adrs, m1, m1_len, - OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND1, out, out_len); + return do_hash(hctx, hctx->md_ctx, hctx->key->params->n, pk_seed, adrs, + m1, m1_len, OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND1, out, out_len); } static int slh_h_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *pk_seed, const uint8_t *adrs, const uint8_t *m1, const uint8_t *m2, uint8_t *out, size_t out_len) { - uint8_t m[SLH_MAX_N * 2]; + /* The concatenated children go in the scratch after the digest */ + uint8_t *m = hctx->scratch + MAX_DIGEST_SIZE; const SLH_DSA_PARAMS *prms = hctx->key->params; size_t n = prms->n; memcpy(m, m1, n); memcpy(m + n, m2, n); - return do_hash(hctx->md_big_ctx, n, pk_seed, adrs, m, 2 * n, + return do_hash(hctx, hctx->md_big_ctx, n, pk_seed, adrs, m, 2 * n, prms->sha2_h_and_t_bound, out, out_len); } @@ -262,7 +276,7 @@ slh_t_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *pk_seed, const uint8_t *adrs, { const SLH_DSA_PARAMS *prms = hctx->key->params; - return do_hash(hctx->md_big_ctx, prms->n, pk_seed, adrs, ml, ml_len, + return do_hash(hctx, hctx->md_big_ctx, prms->n, pk_seed, adrs, ml, ml_len, prms->sha2_h_and_t_bound, out, out_len); } diff --git a/deps/openssl/openssl/crypto/slh_dsa/slh_hypertree.c b/deps/openssl/openssl/crypto/slh_dsa/slh_hypertree.c index bc352bf5bc3a..e1e2901ce5f3 100644 --- a/deps/openssl/openssl/crypto/slh_dsa/slh_hypertree.c +++ b/deps/openssl/openssl/crypto/slh_dsa/slh_hypertree.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -8,6 +8,7 @@ */ #include +#include #include "slh_dsa_local.h" #include "slh_dsa_key.h" @@ -33,6 +34,7 @@ int ossl_slh_ht_sign(SLH_DSA_HASH_CTX *ctx, const uint8_t *pk_seed, uint64_t tree_id, uint32_t leaf_id, WPACKET *sig_wpkt) { + int ret = 0; const SLH_DSA_KEY *key = ctx->key; SLH_ADRS_FUNC_DECLARE(key, adrsf); SLH_ADRS_DECLARE(adrs); @@ -70,7 +72,7 @@ int ossl_slh_ht_sign(SLH_DSA_HASH_CTX *ctx, psig = WPACKET_get_curr(sig_wpkt); if (!ossl_slh_xmss_sign(ctx, root, sk_seed, leaf_id, pk_seed, adrs, sig_wpkt)) - return 0; + goto err; /* * On the last loop it skips getting the public key since it is not needed * to calculate another signature. If this was called it should equal @@ -79,15 +81,18 @@ int ossl_slh_ht_sign(SLH_DSA_HASH_CTX *ctx, if (layer < d - 1) { if (!PACKET_buf_init(xmss_sig_rpkt, psig, WPACKET_get_curr(sig_wpkt) - psig)) - return 0; + goto err; if (!ossl_slh_xmss_pk_from_sig(ctx, leaf_id, xmss_sig_rpkt, root, pk_seed, adrs, root, sizeof(root))) - return 0; + goto err; leaf_id = tree_id & mask; tree_id >>= hm; } } - return 1; + ret = 1; +err: + OPENSSL_cleanse(root, sizeof(root)); + return ret; } /** @@ -108,6 +113,7 @@ int ossl_slh_ht_verify(SLH_DSA_HASH_CTX *ctx, const uint8_t *msg, PACKET *sig_pk const uint8_t *pk_seed, uint64_t tree_id, uint32_t leaf_id, const uint8_t *pk_root) { + int ret = 0; const SLH_DSA_KEY *key = ctx->key; SLH_ADRS_FUNC_DECLARE(key, adrsf); SLH_ADRS_DECLARE(adrs); @@ -127,9 +133,12 @@ int ossl_slh_ht_verify(SLH_DSA_HASH_CTX *ctx, const uint8_t *msg, PACKET *sig_pk adrsf->set_tree_address(adrs, tree_id); if (!ossl_slh_xmss_pk_from_sig(ctx, leaf_id, sig_pkt, node, pk_seed, adrs, node, sizeof(node))) - return 0; + goto err; leaf_id = tree_id & mask; tree_id >>= tree_height; } - return (memcmp(node, pk_root, n) == 0); + ret = (memcmp(node, pk_root, n) == 0); +err: + OPENSSL_cleanse(node, sizeof(node)); + return ret; } diff --git a/deps/openssl/openssl/crypto/slh_dsa/slh_wots.c b/deps/openssl/openssl/crypto/slh_dsa/slh_wots.c index ea278fcd8412..79f3bca8747d 100644 --- a/deps/openssl/openssl/crypto/slh_dsa/slh_wots.c +++ b/deps/openssl/openssl/crypto/slh_dsa/slh_wots.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -244,6 +244,8 @@ int ossl_slh_wots_sign(SLH_DSA_HASH_CTX *ctx, const uint8_t *msg, } ret = 1; err: + OPENSSL_cleanse(sk, sizeof(sk)); + OPENSSL_cleanse(msg_and_csum_nibbles, sizeof(msg_and_csum_nibbles)); return ret; } @@ -311,5 +313,7 @@ int ossl_slh_wots_pk_from_sig(SLH_DSA_HASH_CTX *ctx, err: if (!WPACKET_finish(tmp_pkt)) ret = 0; + OPENSSL_cleanse(tmp, sizeof(tmp)); + OPENSSL_cleanse(msg_and_csum_nibbles, sizeof(msg_and_csum_nibbles)); return ret; } diff --git a/deps/openssl/openssl/crypto/slh_dsa/slh_xmss.c b/deps/openssl/openssl/crypto/slh_dsa/slh_xmss.c index dae036c6a218..a53a6c1e9911 100644 --- a/deps/openssl/openssl/crypto/slh_dsa/slh_xmss.c +++ b/deps/openssl/openssl/crypto/slh_dsa/slh_xmss.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -8,6 +8,7 @@ */ #include +#include #include "slh_dsa_local.h" #include "slh_dsa_key.h" @@ -39,29 +40,31 @@ int ossl_slh_xmss_node(SLH_DSA_HASH_CTX *ctx, const uint8_t *sk_seed, { const SLH_DSA_KEY *key = ctx->key; SLH_ADRS_FUNC_DECLARE(key, adrsf); + int ret = 0; if (h == 0) { /* For leaf nodes generate the public key */ adrsf->set_type_and_clear(adrs, SLH_ADRS_TYPE_WOTS_HASH); adrsf->set_keypair_address(adrs, node_id); - if (!ossl_slh_wots_pk_gen(ctx, sk_seed, pk_seed, adrs, + if (ossl_slh_wots_pk_gen(ctx, sk_seed, pk_seed, adrs, pk_out, pk_out_len)) - return 0; + ret = 1; } else { uint8_t lnode[SLH_MAX_N], rnode[SLH_MAX_N]; - if (!ossl_slh_xmss_node(ctx, sk_seed, 2 * node_id, h - 1, pk_seed, adrs, + if (ossl_slh_xmss_node(ctx, sk_seed, 2 * node_id, h - 1, pk_seed, adrs, lnode, sizeof(lnode)) - || !ossl_slh_xmss_node(ctx, sk_seed, 2 * node_id + 1, h - 1, - pk_seed, adrs, rnode, sizeof(rnode))) - return 0; - adrsf->set_type_and_clear(adrs, SLH_ADRS_TYPE_TREE); - adrsf->set_tree_height(adrs, h); - adrsf->set_tree_index(adrs, node_id); - if (!key->hash_func->H(ctx, pk_seed, adrs, lnode, rnode, pk_out, pk_out_len)) - return 0; + && ossl_slh_xmss_node(ctx, sk_seed, 2 * node_id + 1, h - 1, + pk_seed, adrs, rnode, sizeof(rnode))) { + adrsf->set_type_and_clear(adrs, SLH_ADRS_TYPE_TREE); + adrsf->set_tree_height(adrs, h); + adrsf->set_tree_index(adrs, node_id); + ret = key->hash_func->H(ctx, pk_seed, adrs, lnode, rnode, pk_out, pk_out_len); + } + OPENSSL_cleanse(lnode, sizeof(lnode)); + OPENSSL_cleanse(rnode, sizeof(rnode)); } - return 1; + return ret; } /** diff --git a/deps/openssl/openssl/crypto/threads_win.c b/deps/openssl/openssl/crypto/threads_win.c index 2c0e27ce06eb..158aa2ea91c9 100644 --- a/deps/openssl/openssl/crypto/threads_win.c +++ b/deps/openssl/openssl/crypto/threads_win.c @@ -535,6 +535,20 @@ int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void)) result = InterlockedCompareExchange(lock, ONCE_ININIT, ONCE_UNINITED); if (result == ONCE_UNINITED) { init(); + /* + * On weakly ordered systems, it may happen that the write to *lock + * below completes prior to some writes in whatever the init() + * callback routine above may do. In this case, other threads + * entering here may see unsynchronized data in whatever the init + * routine initializes, leading to erroneous behavior. + * + * We should use InitOnceExecuteOnce here to implement this, but + * doing so requires that we modify the definition of the + * CRYPTO_ONCE type, which is an ABI breakage. So instead + * just insert a memory barrier here to ensure that any pending + * writes are flushed to memory prior to setting ONCE_DONE below + */ + MemoryBarrier(); *lock = ONCE_DONE; return 1; } diff --git a/deps/openssl/openssl/crypto/x509/by_dir.c b/deps/openssl/openssl/crypto/x509/by_dir.c index e8b7ca152b2c..df92e1d1d589 100644 --- a/deps/openssl/openssl/crypto/x509/by_dir.c +++ b/deps/openssl/openssl/crypto/x509/by_dir.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -228,7 +228,7 @@ static int get_cert_by_subject_ex(X509_LOOKUP *xl, X509_LOOKUP_TYPE type, X509 st_x509; X509_CRL crl; } data; - int ok = 0; + int res, ok = 0; int i, j, k; unsigned long h; BUF_MEM *b = NULL; @@ -320,25 +320,35 @@ static int get_cert_by_subject_ex(X509_LOOKUP *xl, X509_LOOKUP_TYPE type, } #ifndef OPENSSL_NO_POSIX_IO #ifdef _WIN32 +#define lstat _stat #define stat _stat #endif { struct stat st; - if (stat(b->data, &st) < 0) - break; - } + if (lstat(b->data, &st) < 0) + break; /* file does not exist, not even a symlink */ +#ifndef _WIN32 + if (stat(b->data, &st) < 0) { + k++; + continue; /* symlink is broken: following it went wrong */ + } #endif - /* found one. */ - if (type == X509_LU_X509) { - if ((X509_load_cert_file_ex(xl, b->data, ent->dir_type, libctx, - propq)) - == 0) - break; - } else if (type == X509_LU_CRL) { - if ((X509_load_crl_file(xl, b->data, ent->dir_type)) == 0) - break; } +#endif + res = 0; + ERR_set_mark(); + if (type == X509_LU_X509) + res = X509_load_cert_file_ex(xl, b->data, ent->dir_type, libctx, propq); + else if (type == X509_LU_CRL) + res = X509_load_crl_file(xl, b->data, ent->dir_type); /* else case will caught higher up */ + ERR_pop_to_mark(); + /* unless OPENSSL_NO_POSIX_IO, gracefully skip found file if cert/CRL fails to load. */ +#ifndef OPENSSL_NO_POSIX_IO + res = 1; +#endif + if (res == 0) + break; k++; } diff --git a/deps/openssl/openssl/crypto/x509/pcy_cache.c b/deps/openssl/openssl/crypto/x509/pcy_cache.c index d1ee35377bda..b3b6a3da1a9a 100644 --- a/deps/openssl/openssl/crypto/x509/pcy_cache.c +++ b/deps/openssl/openssl/crypto/x509/pcy_cache.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2004-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -134,6 +134,7 @@ static int policy_cache_new(X509 *x) /* If not absent some problem with extension */ if (i != -1) goto bad_cache; + POLICY_CONSTRAINTS_free(ext_pcons); return 1; } @@ -141,8 +142,10 @@ static int policy_cache_new(X509 *x) /* NB: ext_cpols freed by policy_cache_set_policies */ - if (i <= 0) + if (i <= 0) { + POLICY_CONSTRAINTS_free(ext_pcons); return i; + } ext_pmaps = X509_get_ext_d2i(x, NID_policy_mappings, &i, NULL); diff --git a/deps/openssl/openssl/crypto/x509/v3_akid.c b/deps/openssl/openssl/crypto/x509/v3_akid.c index 08c751b77cfd..9721518ecc0d 100644 --- a/deps/openssl/openssl/crypto/x509/v3_akid.c +++ b/deps/openssl/openssl/crypto/x509/v3_akid.c @@ -1,5 +1,5 @@ /* - * Copyright 1999-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1999-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -173,7 +173,9 @@ static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method, i = X509_get_ext_by_NID(issuer_cert, NID_subject_key_identifier, -1); if (i >= 0 && (ext = X509_get_ext(issuer_cert, i)) != NULL && !(same_issuer && !ss)) { - ikeyid = X509V3_EXT_d2i(ext); + if ((ikeyid = X509V3_EXT_d2i(ext)) == NULL) + goto err; + if (ASN1_STRING_length(ikeyid) == 0) /* indicating "none" */ { ASN1_OCTET_STRING_free(ikeyid); ikeyid = NULL; diff --git a/deps/openssl/openssl/crypto/x509/v3_ncons.c b/deps/openssl/openssl/crypto/x509/v3_ncons.c index 2d4b23685b0e..a0b97bb7081e 100644 --- a/deps/openssl/openssl/crypto/x509/v3_ncons.c +++ b/deps/openssl/openssl/crypto/x509/v3_ncons.c @@ -1,5 +1,5 @@ /* - * Copyright 2003-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2003-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -613,6 +613,12 @@ static int nc_dn(const X509_NAME *nm, const X509_NAME *base) return X509_V_ERR_OUT_OF_MEM; if (base->canon_enclen > nm->canon_enclen) return X509_V_ERR_PERMITTED_VIOLATION; + /* + * An empty base Name has no canonical encoding (canon_enc == NULL) and is + * a prefix of every Name, so it matches unconditionally. + */ + if (base->canon_enclen == 0) + return X509_V_OK; if (memcmp(base->canon_enc, nm->canon_enc, base->canon_enclen)) return X509_V_ERR_PERMITTED_VIOLATION; return X509_V_OK; @@ -789,6 +795,7 @@ static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base) if (scheme == NULL || *scheme == '\0') { ERR_raise_data(ERR_LIB_X509V3, X509_V_ERR_UNSUPPORTED_NAME_SYNTAX, "x509: missing scheme in URI: %s\n", uri_copy); + OPENSSL_free(scheme); OPENSSL_free(uri_copy); ret = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; goto end; diff --git a/deps/openssl/openssl/crypto/x509/x509_err.c b/deps/openssl/openssl/crypto/x509/x509_err.c index 3d6e8768f8bf..7ed046fef493 100644 --- a/deps/openssl/openssl/crypto/x509/x509_err.c +++ b/deps/openssl/openssl/crypto/x509/x509_err.c @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -26,6 +26,8 @@ static const ERR_STRING_DATA X509_str_reasons[] = { { ERR_PACK(ERR_LIB_X509, 0, X509_R_CERT_ALREADY_IN_HASH_TABLE), "cert already in hash table" }, { ERR_PACK(ERR_LIB_X509, 0, X509_R_CRL_ALREADY_DELTA), "crl already delta" }, + { ERR_PACK(ERR_LIB_X509, 0, X509_R_CRL_SIGNATURE_ALGORITHM_MISMATCH), + "crl signature algorithm mismatch" }, { ERR_PACK(ERR_LIB_X509, 0, X509_R_CRL_VERIFY_FAILURE), "crl verify failure" }, { ERR_PACK(ERR_LIB_X509, 0, X509_R_DUPLICATE_ATTRIBUTE), diff --git a/deps/openssl/openssl/crypto/x509/x509_lu.c b/deps/openssl/openssl/crypto/x509/x509_lu.c index af8035bce844..00fe2bbe0415 100644 --- a/deps/openssl/openssl/crypto/x509/x509_lu.c +++ b/deps/openssl/openssl/crypto/x509/x509_lu.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -590,7 +590,12 @@ static X509_OBJECT *x509_object_dup(const X509_OBJECT *obj) ret->type = obj->type; ret->data = obj->data; - X509_OBJECT_up_ref_count(ret); + + if (!X509_OBJECT_up_ref_count(ret)) { + OPENSSL_free(ret); + return NULL; + } + return ret; } diff --git a/deps/openssl/openssl/crypto/x509/x509_vfy.c b/deps/openssl/openssl/crypto/x509/x509_vfy.c index 0994c32ca533..b3df8c9b71e7 100644 --- a/deps/openssl/openssl/crypto/x509/x509_vfy.c +++ b/deps/openssl/openssl/crypto/x509/x509_vfy.c @@ -1364,6 +1364,12 @@ static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer, /* Invalid IDP cannot be processed */ if ((crl->idp_flags & IDP_INVALID) != 0) return 0; + /* + * Reject delta CRLs unconditionally here. They are considered by + * get_delta_sk() after a base CRL is selected. + */ + if (crl->base_crl_number != NULL) + return 0; /* Reason codes or indirect CRLs need extended CRL support */ if ((ctx->param->flags & X509_V_FLAG_EXTENDED_CRL_SUPPORT) == 0) { if (crl->idp_flags & (IDP_INDIRECT | IDP_REASONS)) @@ -1373,9 +1379,6 @@ static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer, if ((crl->idp_reasons & ~tmp_reasons) == 0) return 0; } - /* Don't process deltas at this stage */ - else if (crl->base_crl_number != NULL) - return 0; /* If issuer name doesn't match certificate need indirect CRL */ if (X509_NAME_cmp(X509_get_issuer_name(x), X509_CRL_get_issuer(crl)) != 0) { if ((crl->idp_flags & IDP_INDIRECT) == 0) diff --git a/deps/openssl/openssl/crypto/x509/x_crl.c b/deps/openssl/openssl/crypto/x509/x_crl.c index 4a93abb8ca3f..1b498ee6b57d 100644 --- a/deps/openssl/openssl/crypto/x509/x_crl.c +++ b/deps/openssl/openssl/crypto/x509/x_crl.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -404,6 +404,10 @@ int X509_CRL_get0_by_cert(X509_CRL *crl, X509_REVOKED **ret, X509 *x) static int def_crl_verify(X509_CRL *crl, EVP_PKEY *r) { + if (X509_ALGOR_cmp(&crl->sig_alg, &crl->crl.sig_alg) != 0) { + ERR_raise(ERR_LIB_X509, X509_R_CRL_SIGNATURE_ALGORITHM_MISMATCH); + return 0; + } return ASN1_item_verify_ex(ASN1_ITEM_rptr(X509_CRL_INFO), &crl->sig_alg, &crl->signature, &crl->crl, NULL, r, crl->libctx, crl->propq); diff --git a/deps/openssl/openssl/crypto/x509/x_pubkey.c b/deps/openssl/openssl/crypto/x509/x_pubkey.c index 03f532ab9cb3..8e0ee3a2197f 100644 --- a/deps/openssl/openssl/crypto/x509/x_pubkey.c +++ b/deps/openssl/openssl/crypto/x509/x_pubkey.c @@ -224,7 +224,7 @@ static int x509_pubkey_ex_d2i_ex(ASN1_VALUE **pval, * bytes. */ ERR_clear_last_mark(); - ERR_raise(ERR_LIB_ASN1, EVP_R_DECODE_ERROR); + ERR_raise(ERR_LIB_ASN1, ASN1_R_DECODE_ERROR); goto end; } } diff --git a/deps/openssl/openssl/doc/build.info b/deps/openssl/openssl/doc/build.info index eb4492ba9c75..ce2125a4d3f3 100644 --- a/deps/openssl/openssl/doc/build.info +++ b/deps/openssl/openssl/doc/build.info @@ -1523,6 +1523,10 @@ DEPEND[html/man3/MDC2_Init.html]=man3/MDC2_Init.pod GENERATE[html/man3/MDC2_Init.html]=man3/MDC2_Init.pod DEPEND[man/man3/MDC2_Init.3]=man3/MDC2_Init.pod GENERATE[man/man3/MDC2_Init.3]=man3/MDC2_Init.pod +DEPEND[html/man3/NAME_CONSTRAINTS_check.html]=man3/NAME_CONSTRAINTS_check.pod +GENERATE[html/man3/NAME_CONSTRAINTS_check.html]=man3/NAME_CONSTRAINTS_check.pod +DEPEND[man/man3/NAME_CONSTRAINTS_check.3]=man3/NAME_CONSTRAINTS_check.pod +GENERATE[man/man3/NAME_CONSTRAINTS_check.3]=man3/NAME_CONSTRAINTS_check.pod DEPEND[html/man3/NCONF_new_ex.html]=man3/NCONF_new_ex.pod GENERATE[html/man3/NCONF_new_ex.html]=man3/NCONF_new_ex.pod DEPEND[man/man3/NCONF_new_ex.3]=man3/NCONF_new_ex.pod @@ -1571,6 +1575,10 @@ DEPEND[html/man3/OPENSSL_LH_stats.html]=man3/OPENSSL_LH_stats.pod GENERATE[html/man3/OPENSSL_LH_stats.html]=man3/OPENSSL_LH_stats.pod DEPEND[man/man3/OPENSSL_LH_stats.3]=man3/OPENSSL_LH_stats.pod GENERATE[man/man3/OPENSSL_LH_stats.3]=man3/OPENSSL_LH_stats.pod +DEPEND[html/man3/OPENSSL_armcap.html]=man3/OPENSSL_armcap.pod +GENERATE[html/man3/OPENSSL_armcap.html]=man3/OPENSSL_armcap.pod +DEPEND[man/man3/OPENSSL_armcap.3]=man3/OPENSSL_armcap.pod +GENERATE[man/man3/OPENSSL_armcap.3]=man3/OPENSSL_armcap.pod DEPEND[html/man3/OPENSSL_config.html]=man3/OPENSSL_config.pod GENERATE[html/man3/OPENSSL_config.html]=man3/OPENSSL_config.pod DEPEND[man/man3/OPENSSL_config.3]=man3/OPENSSL_config.pod @@ -3446,6 +3454,7 @@ html/man3/GENERAL_NAME.html \ html/man3/HMAC.html \ html/man3/MD5.html \ html/man3/MDC2_Init.html \ +html/man3/NAME_CONSTRAINTS_check.html \ html/man3/NCONF_new_ex.html \ html/man3/OBJ_nid2obj.html \ html/man3/OCSP_REQUEST_new.html \ @@ -3458,6 +3467,7 @@ html/man3/OPENSSL_Applink.html \ html/man3/OPENSSL_FILE.html \ html/man3/OPENSSL_LH_COMPFUNC.html \ html/man3/OPENSSL_LH_stats.html \ +html/man3/OPENSSL_armcap.html \ html/man3/OPENSSL_config.html \ html/man3/OPENSSL_fork_prepare.html \ html/man3/OPENSSL_gmtime.html \ @@ -4123,6 +4133,7 @@ man/man3/GENERAL_NAME.3 \ man/man3/HMAC.3 \ man/man3/MD5.3 \ man/man3/MDC2_Init.3 \ +man/man3/NAME_CONSTRAINTS_check.3 \ man/man3/NCONF_new_ex.3 \ man/man3/OBJ_nid2obj.3 \ man/man3/OCSP_REQUEST_new.3 \ @@ -4135,6 +4146,7 @@ man/man3/OPENSSL_Applink.3 \ man/man3/OPENSSL_FILE.3 \ man/man3/OPENSSL_LH_COMPFUNC.3 \ man/man3/OPENSSL_LH_stats.3 \ +man/man3/OPENSSL_armcap.3 \ man/man3/OPENSSL_config.3 \ man/man3/OPENSSL_fork_prepare.3 \ man/man3/OPENSSL_gmtime.3 \ diff --git a/deps/openssl/openssl/fuzz/provider.c b/deps/openssl/openssl/fuzz/provider.c index 8234a7e8dca6..69905223fbb4 100644 --- a/deps/openssl/openssl/fuzz/provider.c +++ b/deps/openssl/openssl/fuzz/provider.c @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2023-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,8 +32,11 @@ { \ STACK_OF(evp) *obj_stack = stack; \ \ - if (sk_##evp##_push(obj_stack, obj) > 0) \ - evp##_up_ref(obj); \ + if (!evp##_up_ref(obj)) \ + return; \ + \ + if (sk_##evp##_push(obj_stack, obj) <= 0) \ + evp##_free(obj); \ } \ static void init_##name(OSSL_LIB_CTX *libctx) \ { \ diff --git a/deps/openssl/openssl/include/internal/hashtable.h b/deps/openssl/openssl/include/internal/hashtable.h index bc44e43678a3..8bfa53923616 100644 --- a/deps/openssl/openssl/include/internal/hashtable.h +++ b/deps/openssl/openssl/include/internal/hashtable.h @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -272,7 +272,7 @@ static void ossl_unused ossl_ht_strcase(char *tgt, const char *src, int len) if (src == NULL) return; - for (i = 0; src[i] != '\0' && i < len; i++) + for (i = 0; i < len && src[i] != '\0'; i++) tgt[i] = case_adjust & src[i]; } diff --git a/deps/openssl/openssl/include/internal/list.h b/deps/openssl/openssl/include/internal/list.h index 8bb0b741bed1..270e3f1dbb93 100644 --- a/deps/openssl/openssl/include/internal/list.h +++ b/deps/openssl/openssl/include/internal/list.h @@ -1,5 +1,5 @@ /* - * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -194,6 +194,35 @@ list->omega = elem; \ list->num_elems++; \ } \ + static ossl_unused ossl_inline void \ + ossl_list_##name##_join(OSSL_LIST(name) * lh, OSSL_LIST(name) * lt) \ + { \ + OSSL_LIST_DBG(type * _p); /* local variable '_p' when debug */ \ + if (lt == NULL || lh == NULL || lt->num_elems == 0 || lh == lt) \ + return; \ + /* \ + * let's be optimistic about size_t overflow here: it can not happen. \ + */ \ + lh->num_elems += lt->num_elems; \ + if (lh->omega == NULL) { \ + assert(lh->alpha == NULL); \ + lh->omega = lt->omega; \ + lh->alpha = lt->alpha; \ + } else { \ + if (lt->alpha != NULL) \ + ((type *)lt->alpha)->ossl_list_##name.prev = lh->omega; \ + ((type *)lh->omega)->ossl_list_##name.next = lt->alpha; \ + } \ + OSSL_LIST_DBG(for (_p = (type *)lt->alpha; \ + assert(_p == NULL || _p->ossl_list_##name.list == lt), _p != NULL; \ + _p = _p->ossl_list_##name.next) \ + _p->ossl_list_##name.list \ + = lh); \ + lh->omega = lt->omega; \ + lt->alpha = NULL; \ + lt->omega = NULL; \ + lt->num_elems = 0; \ + } \ struct ossl_list_st_##name #define DEFINE_LIST_OF(name, type) \ diff --git a/deps/openssl/openssl/include/internal/quic_ackm.h b/deps/openssl/openssl/include/internal/quic_ackm.h index c0617da4855f..5b325e166bd5 100644 --- a/deps/openssl/openssl/include/internal/quic_ackm.h +++ b/deps/openssl/openssl/include/internal/quic_ackm.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -129,6 +129,11 @@ struct ossl_ackm_tx_pkt_st { }; int ossl_ackm_on_tx_packet(OSSL_ACKM *ackm, OSSL_ACKM_TX_PKT *pkt); + +/* + * Records transmission of a packet containing only ACK frames. + */ +int ossl_ackm_on_tx_ack_only_packet(OSSL_ACKM *ackm, OSSL_ACKM_TX_PKT *pkt); int ossl_ackm_on_rx_datagram(OSSL_ACKM *ackm, size_t num_bytes); #define OSSL_ACKM_ECN_NONE 0 diff --git a/deps/openssl/openssl/include/internal/quic_port.h b/deps/openssl/openssl/include/internal/quic_port.h index 5a2c9352378b..88fb126e9949 100644 --- a/deps/openssl/openssl/include/internal/quic_port.h +++ b/deps/openssl/openssl/include/internal/quic_port.h @@ -1,5 +1,5 @@ /* - * Copyright 2023-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2023-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -187,6 +187,10 @@ uint64_t ossl_quic_port_get_net_bio_epoch(const QUIC_PORT *port); void ossl_quic_port_raise_net_error(QUIC_PORT *port, QUIC_CHANNEL *triggering_ch); +uint64_t ossl_quic_port_get_max_pending_channels(const QUIC_PORT *port); + +void ossl_quic_port_set_max_pending_channels(QUIC_PORT *port, uint64_t max_pending_channels); + #endif #endif diff --git a/deps/openssl/openssl/include/internal/quic_record_rx.h b/deps/openssl/openssl/include/internal/quic_record_rx.h index 287837b2a561..a4e9e7cacd25 100644 --- a/deps/openssl/openssl/include/internal/quic_record_rx.h +++ b/deps/openssl/openssl/include/internal/quic_record_rx.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -51,8 +51,9 @@ typedef struct ossl_qrx_args_st { OSSL_QRX *ossl_qrx_new(const OSSL_QRX_ARGS *args); /* - * Frees the QRX. All packets obtained using ossl_qrx_read_pkt must already - * have been released by calling ossl_qrx_release_pkt. + * Frees the QRX/reference to QRX. Frees the QRX object, if all references are + * gone. All packets obtained using ossl_qrx_read_pkt must already have been + * released by calling ossl_qrx_release_pkt. * * You do not need to call ossl_qrx_remove_dst_conn_id first; this function will * unregister the QRX from the demuxer for all registered destination connection @@ -60,6 +61,12 @@ OSSL_QRX *ossl_qrx_new(const OSSL_QRX_ARGS *args); */ void ossl_qrx_free(OSSL_QRX *qrx); +/* + * Obtains a new reference to QRX object. Returns NULL if reference can not + * be obtained. + */ +OSSL_QRX *ossl_qrx_newref(OSSL_QRX *qrx); + /* Setters for the msg_callback and msg_callback_arg */ void ossl_qrx_set_msg_callback(OSSL_QRX *qrx, ossl_msg_cb msg_callback, SSL *msg_callback_ssl); diff --git a/deps/openssl/openssl/include/internal/quic_ssl.h b/deps/openssl/openssl/include/internal/quic_ssl.h index f714d1047716..a9c17e1087a3 100644 --- a/deps/openssl/openssl/include/internal/quic_ssl.h +++ b/deps/openssl/openssl/include/internal/quic_ssl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -179,6 +179,7 @@ int ossl_quic_conn_poll_events(SSL *ssl, uint64_t events, int do_tick, int ossl_quic_get_notifier_fd(SSL *ssl); void ossl_quic_enter_blocking_section(SSL *ssl, QUIC_REACTOR_WAIT_CTX *wctx); void ossl_quic_leave_blocking_section(SSL *ssl, QUIC_REACTOR_WAIT_CTX *wctx); +QUIC_PORT *ossl_quic_listener_get_port(SSL *s); #endif diff --git a/deps/openssl/openssl/include/openssl/ssl.h.in b/deps/openssl/openssl/include/openssl/ssl.h.in index e684f7c42975..90be33cb4f17 100644 --- a/deps/openssl/openssl/include/openssl/ssl.h.in +++ b/deps/openssl/openssl/include/openssl/ssl.h.in @@ -2441,6 +2441,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2688,8 +2689,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2728,12 +2739,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/deps/openssl/openssl/include/openssl/x509err.h b/deps/openssl/openssl/include/openssl/x509err.h index 7123a725e825..4bbff54a380e 100644 --- a/deps/openssl/openssl/include/openssl/x509err.h +++ b/deps/openssl/openssl/include/openssl/x509err.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -27,6 +27,7 @@ #define X509_R_CERTIFICATE_VERIFICATION_FAILED 139 #define X509_R_CERT_ALREADY_IN_HASH_TABLE 101 #define X509_R_CRL_ALREADY_DELTA 127 +#define X509_R_CRL_SIGNATURE_ALGORITHM_MISMATCH 147 #define X509_R_CRL_VERIFY_FAILURE 131 #define X509_R_DUPLICATE_ATTRIBUTE 140 #define X509_R_ERROR_GETTING_MD_BY_NID 141 diff --git a/deps/openssl/openssl/providers/baseprov.c b/deps/openssl/openssl/providers/baseprov.c index 16d2f91bb1ac..ad08765f006c 100644 --- a/deps/openssl/openssl/providers/baseprov.c +++ b/deps/openssl/openssl/providers/baseprov.c @@ -1,5 +1,5 @@ /* - * Copyright 2020-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2020-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -29,10 +29,6 @@ static OSSL_FUNC_provider_gettable_params_fn base_gettable_params; static OSSL_FUNC_provider_get_params_fn base_get_params; static OSSL_FUNC_provider_query_operation_fn base_query; -/* Functions provided by the core */ -static OSSL_FUNC_core_gettable_params_fn *c_gettable_params = NULL; -static OSSL_FUNC_core_get_params_fn *c_get_params = NULL; - /* Parameters we provide to the core */ static const OSSL_PARAM base_param_types[] = { OSSL_PARAM_DEFN(OSSL_PROV_PARAM_NAME, OSSL_PARAM_UTF8_PTR, NULL, 0), @@ -139,15 +135,13 @@ int ossl_base_provider_init(const OSSL_CORE_HANDLE *handle, void **provctx) { OSSL_FUNC_core_get_libctx_fn *c_get_libctx = NULL; + OSSL_FUNC_core_get_params_fn *c_get_params = NULL; BIO_METHOD *corebiometh; if (!ossl_prov_bio_from_dispatch(in)) return 0; for (; in->function_id != 0; in++) { switch (in->function_id) { - case OSSL_FUNC_CORE_GETTABLE_PARAMS: - c_gettable_params = OSSL_FUNC_core_gettable_params(in); - break; case OSSL_FUNC_CORE_GET_PARAMS: c_get_params = OSSL_FUNC_core_get_params(in); break; diff --git a/deps/openssl/openssl/providers/defltprov.c b/deps/openssl/openssl/providers/defltprov.c index a74a048d6f76..de2a46515e11 100644 --- a/deps/openssl/openssl/providers/defltprov.c +++ b/deps/openssl/openssl/providers/defltprov.c @@ -34,10 +34,6 @@ static OSSL_FUNC_provider_query_operation_fn deflt_query; #define ALGC(NAMES, FUNC, CHECK) { { NAMES, "provider=default", FUNC }, CHECK } #define ALG(NAMES, FUNC) ALGC(NAMES, FUNC, NULL) -/* Functions provided by the core */ -static OSSL_FUNC_core_gettable_params_fn *c_gettable_params = NULL; -static OSSL_FUNC_core_get_params_fn *c_get_params = NULL; - /* Parameters we provide to the core */ static const OSSL_PARAM deflt_param_types[] = { OSSL_PARAM_DEFN(OSSL_PROV_PARAM_NAME, OSSL_PARAM_UTF8_PTR, NULL, 0), @@ -733,6 +729,7 @@ int ossl_default_provider_init(const OSSL_CORE_HANDLE *handle, void **provctx) { OSSL_FUNC_core_get_libctx_fn *c_get_libctx = NULL; + OSSL_FUNC_core_get_params_fn *c_get_params = NULL; BIO_METHOD *corebiometh; if (!ossl_prov_bio_from_dispatch(in) @@ -740,9 +737,6 @@ int ossl_default_provider_init(const OSSL_CORE_HANDLE *handle, return 0; for (; in->function_id != 0; in++) { switch (in->function_id) { - case OSSL_FUNC_CORE_GETTABLE_PARAMS: - c_gettable_params = OSSL_FUNC_core_gettable_params(in); - break; case OSSL_FUNC_CORE_GET_PARAMS: c_get_params = OSSL_FUNC_core_get_params(in); break; diff --git a/deps/openssl/openssl/providers/fips-sources.checksums b/deps/openssl/openssl/providers/fips-sources.checksums index a2f5817e26de..85af251d79e2 100644 --- a/deps/openssl/openssl/providers/fips-sources.checksums +++ b/deps/openssl/openssl/providers/fips-sources.checksums @@ -20,12 +20,12 @@ f1d8b7a3da1ec053d38be4fc776fef1e4fba328bfa2bfd928c2a2cd3b14f08ff crypto/aes/asm ee4e8cacef972942d2a89c1a83c984df9cad87c61a54383403c5c4864c403ba1 crypto/aes/asm/aes-sparcv9.pl 391497550eaca253f64b2aba7ba2e53c6bae7dff01583bc6bfc12e930bb7e217 crypto/aes/asm/aes-x86_64.pl 3b5ee174fa52d732d882ab4b2ffe59235d3bff66651714f32e743fcadaf1d970 crypto/aes/asm/aesfx-sparcv9.pl -14359dc32b7f4e5c08227fb9ac8f9232c1287399463b233fec4a2ab0c19f68d1 crypto/aes/asm/aesni-mb-x86_64.pl -f525e1bca51d39adcd411cbf8f874fe1441b23a6f614644da78dfd8544d13b23 crypto/aes/asm/aesni-sha1-x86_64.pl -895f94d7befb90e82f9d300ed8f870e790101f30ba72b249a2c503f07aec7dd2 crypto/aes/asm/aesni-sha256-x86_64.pl +e220d630965eb2672dca757aefcb9654928288772fd495da3a495b405b5f21ff crypto/aes/asm/aesni-mb-x86_64.pl +83a08babb80e15606bb52c6b4fcd1a6416d3b165b9cbfa42678ebe2e27c3b8d4 crypto/aes/asm/aesni-sha1-x86_64.pl +6808938757a489c3827e6da78f9ce227d88efcc29c3467fa0329b50b761523eb crypto/aes/asm/aesni-sha256-x86_64.pl 4ff74d4e629a88ef5a9e3d3f5b340fc0a4793d16d7cc7f1b70da62512a856248 crypto/aes/asm/aesni-x86.pl 25881237d026cebd96877a2ea2729db1ce512875cb2a10ca0cd1d6ddf4b51a3b crypto/aes/asm/aesni-x86_64.pl -6047359ad3967168812fbc8a95cb851b72c09f7846be2f03ec2ab93531a9c2bd crypto/aes/asm/aesni-xts-avx512.pl +00dd3a64df71ebd61fd35d2a6179d07cc86fc156cce1541ef176ecafb815f4bb crypto/aes/asm/aesni-xts-avx512.pl 0489a10fbb1a8ca3652848d5c1e14e519501e189bad3e5827a573c26df359691 crypto/aes/asm/aesp8-ppc.pl e397a5781893e97dd90a5a52049633be12a43f379ec5751bca2a6350c39444c8 crypto/aes/asm/aest4-sparcv9.pl 578142d03bc47353952fca2027eb63ec97ce9a1379c0f3c7ac0fdf110eb3378b crypto/aes/asm/aesv8-armx.pl @@ -39,7 +39,7 @@ c3541865cd02d81101cdbab4877ed82772e6980d2c677b9008b38fa1b26d36d4 crypto/aes/asm c6935d2ab7925022cb3d76446536ff01b1a1b8eb7eac619d034a29aad17ed45f crypto/aes/asm/vpaes-x86_64.pl 2bc67270155e2d6c7da87d9070e005ee79cea18311004907edfd6a078003532a crypto/alphacpuid.pl 269e52f8867c13ca75d2f88ec1f89b692cb8c6c3ee89abe2fd3c1821925191d8 crypto/arm64cpuid.pl -7a7c1d063be476f35442b0b056cfad0cf62190b603304abd283906ab40590167 crypto/armcap.c +b0242943b097f7640f1b3c33313934a98caf45d47d4403e9e53d826f6d2dc0c4 crypto/armcap.c d9f923daabe7537d1063b182f9f220655abd182ef4c55a0194a7ee8d6030b5bd crypto/armv4cpuid.pl e886d814c34492504cc9a2451c67fd8c0b4e83e8618f931632400cfe522b6e4d crypto/asn1_dsa.c 819c9fd2b0cae9aab81c3cbd1815c2e22949d75f132f649b5883812d0bbaa39a crypto/bn/asm/alpha-mont.pl @@ -58,14 +58,14 @@ b27ec5181e387e812925bb26823b830f49d7a6e4971b6d11ea583f5632a1504b crypto/bn/asm/ 59cd27e1e10c4984b7fb684b27f491e7634473b1bcff197a07e0ca653124aa9a crypto/bn/asm/ppc.pl 0b3350f56d423a4df918a08e90c7c66227c4449a9f9c44096eacc254ebc65f9f crypto/bn/asm/ppc64-mont-fixed.pl a25be64867ab837d93855af232e2bfa71b85b2c6f00e35e620fdc5618187fb6f crypto/bn/asm/ppc64-mont.pl -b3aad31ab658eceaa9c5e734e19f39c33991f4839ab55b0cec8018020b1a305e crypto/bn/asm/rsaz-2k-avx512.pl -03f6cc678f377c5cd953e8da135c5d76dc1cd011565118c99e25bff91e7271df crypto/bn/asm/rsaz-2k-avxifma.pl -e914311420ae4486ab6000cc6ab424f04d8a042bda40ab8f288348dc9f0eb595 crypto/bn/asm/rsaz-3k-avx512.pl -95b11e0b04c38bde06d152dfde5ab970dab27cccdfeac998e1bc293e01520474 crypto/bn/asm/rsaz-3k-avxifma.pl -e13bd2df8c591052ddf16a839072f43353841f9f35e0ac95f836511838dbc771 crypto/bn/asm/rsaz-4k-avx512.pl -cf92b66c4032703b7ce03ff6aa36887d14e31a8861e7aa21c46a466ea4802851 crypto/bn/asm/rsaz-4k-avxifma.pl -6e47bf041e51d8086c4933c2a5da3ce6d1b136592984754461d59aa81e4995a6 crypto/bn/asm/rsaz-avx2.pl -b42f6cf0fbf9eae58343df9629e7a9e5b8814195ea0c9882d7b143a0841cc018 crypto/bn/asm/rsaz-x86_64.pl +d48aded8547aa44a4af0d76d4675320628c66ba54e6fda865804953eefa8e853 crypto/bn/asm/rsaz-2k-avx512.pl +ae2e714dc003867c31136f939f8d47eb35eac3de36dbeea8f028a48d03b964ec crypto/bn/asm/rsaz-2k-avxifma.pl +6b5f35bf328f19b3add87a9715736ca92a8165920264311e20d3477a41a90a82 crypto/bn/asm/rsaz-3k-avx512.pl +b0ef4c3bb3a835066e9f7cafab22efc9d668b6debf5b9b9ec312cabae9412631 crypto/bn/asm/rsaz-3k-avxifma.pl +ca2d4486ee67f2015a8580664f3bbc28c23201205a2422d3a972cdf6ba59147a crypto/bn/asm/rsaz-4k-avx512.pl +80b0e7aca0ebee78fb3c651723e7f0eaac43a5b6a2bcf87b98a454a248abb945 crypto/bn/asm/rsaz-4k-avxifma.pl +7d686b484ea2bb65091c6ed3e74d5f4063ed4a8ecc09b7bef8d3a3aa57c4121e crypto/bn/asm/rsaz-avx2.pl +bec7e89c5a33652bbff20c95a6fe82bd96f7f2f61a3544c122f3af6f4f162110 crypto/bn/asm/rsaz-x86_64.pl 30fedf48dfc5fec1c2044b6c226dd9fc42a92522cc589797a23a79d452bdd2cf crypto/bn/asm/s390x-gf2m.pl 590388d69d7ac3a0e9af4014792f4f0fdb9552719e8fb48ebc7e5dfca2a491d4 crypto/bn/asm/s390x-mont.pl aa02597f3dc09cfbc190aedb75711859ba0f3efff87067ebfba1ec78ebee40d7 crypto/bn/asm/s390x.S @@ -81,9 +81,9 @@ d24f3e97239c8eed5efc721521b025b7256c15e67a54ea6b5c4cf8f7cd0f89ea crypto/bn/asm/ 90d4ae234c08267adce9ed38d56e0edc223f7480cb9605f5d7399d0b3914c6be crypto/bn/asm/x86-mont.pl 0e3e572cd864bcb9222cdad7ca4e8dae4250f6f76c2b66e1f0e46df1cc0cf371 crypto/bn/asm/x86_64-gcc.c 709ddee92e9222ee0ed27bfb90db556e85e2d302e4a9131afa25fdc14c4d858f crypto/bn/asm/x86_64-gf2m.pl -da7f7780d27eed164797e5334cd45b35d9c113e86afaca051463aef9a8fd787c crypto/bn/asm/x86_64-mont.pl -efe70ef06b5d92539f8a239c98c0261d93a15b3e418ca87d97ec569da9e6e9d3 crypto/bn/asm/x86_64-mont5.pl -0ea8185a037a2951bb3d1e590bbbdeac305176d5e618f3e43a04c09733a9de34 crypto/bn/bn_add.c +4ad5e97a7ed376d2cc079a3eabfbdc0cce3fe6e61751324ef18b72d24f7851d6 crypto/bn/asm/x86_64-mont.pl +11eebbeb8ae59158e780d74300b333de9705aefdde73cff280286c053c8743da crypto/bn/asm/x86_64-mont5.pl +7c81cd72fbf6f2dd85cbcbf40027301c98c1701928d3199edb2b8fdf04a5ca5e crypto/bn/bn_add.c 529933a6592cf82abde515dae10db17833a16ec29cb89ec577c0a184838fe27b crypto/bn/bn_asm.c feef3a84a40034291286882d483ac23ab55631c3c93f40ba0ea98944916ff3ec crypto/bn/bn_blind.c 1b8f89064c287669a834fe032ef823796f7355ed7e6da08d6c56c0a4cd0bba01 crypto/bn/bn_const.c @@ -91,13 +91,13 @@ eee3d2710144b0e860c57e84f5adc6b2bf64fc27cbd202a8ca2630aefed3b84c crypto/bn/bn_c 282f06fbdeb991d90337787c6407020e940b6d5e187a06866f1a7787c10a0c1b crypto/bn/bn_ctx.c b1b1c5fb8a45fde5755dfd5da62b68100b94f8c492c950719c108c384ea7f3c4 crypto/bn/bn_dh.c 4824f271f0ddc487b5991fbd92f7f7695aeeac234e076078f37da027999cdd88 crypto/bn/bn_div.c -d36b2be05469f144f52173616e413a7bdd836607fccf94cf543cc7f5a343b962 crypto/bn/bn_exp.c +f1e98f178356791a3d54f586c19d1639d8e89b2cf6e6a4de783327ceada296a2 crypto/bn/bn_exp.c ce5219203bf869561297978d6d416357a441864cd801865503dfd455c481960c crypto/bn/bn_exp2.c 18ac3f6fe64225f72243689199839ea2ce2aa61d80b084bc4cd9efe1c7cc9d89 crypto/bn/bn_gcd.c b643fdcd91ad7dfcfa97a0bb235221b024b8a77faa7890f0bcb9681ea2c64c49 crypto/bn/bn_gf2m.c 73ee247467879d4ec984c9900dfe7761233c5b889b8762be37c7e8fdd6d1d210 crypto/bn/bn_intern.c ff147e5e032cc7c772b73a91fc6e24d8d9516e642d29354445d1f82d64b1d924 crypto/bn/bn_kron.c -df9aebbdcca87fc5715dde430687fb516d8de0dac70c8910409fb73d6dd2305b crypto/bn/bn_lib.c +c4bae573e4e7132106b1151e8983cb63200dd9e49dc464e805f0fc50d55374d0 crypto/bn/bn_lib.c cd7bade0f2e223fe34f6e2f8cc87098ac8f0af96ec62ada5e67f6a2344d48ef0 crypto/bn/bn_local.h b494fd85387afa7816422922e52987e0faefc3c890c972e7d4fe04f620dfc59a crypto/bn/bn_mod.c 39a8fe0bb625b4c11b74998ce6fd99b7655228aaa7d7ad3076f61741937ae14d crypto/bn/bn_mont.c @@ -126,7 +126,7 @@ ab29529cca1308302d852999f2790c404a4dc0ef8cd6653260739f70b2f22758 crypto/core_fe 0e3519aec0d93b0700d1175616b8bfca9c045989fad515d2202dd7dff9caa5ac crypto/core_namemap.c a62f653b8a6ee765be704980425617e04e1d242f9735efaf35fc6e00815ff2a7 crypto/cpuid.c a73118d14eeb232ff250ae908204ddd7cf33deba5f3ca68a2dbb51b020946b0e crypto/cryptlib.c -66dbfc58916709d5a6913777346083247942a8d9458ee9b2bf443f0ea4988d64 crypto/ctype.c +0145299d43dbb60e85ef6b97cf7496dec55cc37b75433e1403c11adfa3e90c5f crypto/ctype.c b9fabcf8480b8c9c7847a0c9af0fcc13b6c4b4a4558d5e445e6409221e6f8113 crypto/der_writer.c 135ef65f7602432f8c87ad18fdd90b867f1c46b1c631522d56181fbed2106b05 crypto/des/des_enc.c 7c2cea4c850398158b4aff172b242de0cc436b66f62fc701ccca3fe5489925a5 crypto/des/des_local.h @@ -136,7 +136,7 @@ c1e015556147b40c854bf0ab275c54235f99001d04c6d49f158fba6865eb5439 crypto/des/fcr dc2e7899593032fdf0fcab18f5549c52f12bad2225aac9a08c4622ffee34b193 crypto/des/set_key.c 41b7fc5e67814311b878684e3f29cff60e228f1516f670d81bf43130f2668ae8 crypto/des/spr.h b842e39f34996d74cdc9b9be5fc93c27fc91ef6141fae83163e09f6b0eff1e09 crypto/dh/dh_backend.c -091ec05b6316cce34305ae8f8014043c7c9b72098aa1abe9c35dcbcdb4b77cd0 crypto/dh/dh_check.c +380d55ea09a50ba3ece173e64db90782efae08ca56ac51cb4d31b9a303b429ea crypto/dh/dh_check.c c117ac4fd24369c7813ac9dc9685640700a82bb32b0f7e038e85afd6c8db75c7 crypto/dh/dh_gen.c 1149e214ed664540434912e284730a3c87385172e4c6d1c944ea56659e2dd762 crypto/dh/dh_group_params.c a539a8930035fee3b723d74a1d13e931ff69a2b523c83d4a2d0d9db6c78ba902 crypto/dh/dh_kdf.c @@ -146,7 +146,7 @@ a9166c3cc60f4281e9d471c64145e0a78fc9dc43b8bc9e5de96d91eb7d277da3 crypto/dh/dh_l 40065939139ac28aa52838aa54d257da82fce73504557f7a9ad34d13824e0cb9 crypto/dsa/dsa_backend.c 786d6c65ced7ee4e25f5dd7c3150259ec95b6aa321a7590d905757b8139f8230 crypto/dsa/dsa_check.c ae727bf6319eb57e682de35d75ea357921987953b3688365c710e7fba51c7c58 crypto/dsa/dsa_gen.c -dee83cb278b3f712a62bd3477bdecf7b83e6df38ada2f3e1ca043d37327e2da4 crypto/dsa/dsa_key.c +43f8fba4f50fbc94b1532a7667c9cfdc91b357e8658fd5fe0dcd302ea93ae9a0 crypto/dsa/dsa_key.c 7d44106570c0ff9a44de874ea2daeaa87ea4c814fef6af0a26f655120a54f529 crypto/dsa/dsa_lib.c 98ce52d325d2409d7851f1e1226755136f115c884d227d2ae3e4f9b61fc323b8 crypto/dsa/dsa_local.h 3428bc7602f344f8b8d4a5807b0a7e982cbead1ec28be73ad77b5f849b034993 crypto/dsa/dsa_ossl.c @@ -159,9 +159,9 @@ d9722ad8c6b6e209865a921f3cda831d09bf54a55cacd1edd9802edb6559190a crypto/ec/asm/ 3715ddd921425f3018741037f01455ed26a840ace08691a800708170a66cf4d2 crypto/ec/asm/ecp_nistz256-ppc64.pl cfe7e75a2fddc87a7251684469a8808b9da82b2f5725eafad5806920f89932bd crypto/ec/asm/ecp_nistz256-sparcv9.pl 922725c4761cfa567af6ed9ecab04f2c7729ae2595f2fc0fa46dc67879dc87b0 crypto/ec/asm/ecp_nistz256-x86.pl -afa4497cfbf9ef7805e42ae6a61c7d983e8a789b270d498a07785570ab85a9fa crypto/ec/asm/ecp_nistz256-x86_64.pl +f5c4f8c74a44c8723293e3bb64c0c2cf75dc354466ac9f93ebfdab1df34b64c4 crypto/ec/asm/ecp_nistz256-x86_64.pl cc727533130f5f1a29229929b3d4e8454585d647be25d6344f3c6a0240998368 crypto/ec/asm/x25519-ppc64.pl -ee897e230964511baa0d1bf95fb938312407a40a88ebe01476879c2763e5f732 crypto/ec/asm/x25519-x86_64.pl +ee576a748991bb2cf0a37437e46a23dd55dfd35d989e087d122c7cf0f332eb2a crypto/ec/asm/x25519-x86_64.pl 2e7b5d2a3eff0b8a90c1de3f28a7bf59b1057e7694c0e36909e774343cef609f crypto/ec/curve25519.c 784c03c3f81fd0c363cd0500fbd95f3e49c65f47a249f7ba25fad42a41d3eea2 crypto/ec/curve448/arch_32/f_impl32.c 8e75602d4d492316d318bac147eaa09d87b0eeda0d450e18683d935673ab61b0 crypto/ec/curve448/arch_64/arch_intrinsics.h @@ -185,7 +185,7 @@ dfbccf591879eecbd9ed75da1fbe6c7b1672d07648fd43b37755dfe248253bb2 crypto/ec/ec_b 3a3c4f4767513b4fbbabdea2918d7c7d105eb573334a7fd893b866989463c4d2 crypto/ec/ec_check.c f3991bfc65a7371b84afd0cc328e3cbd4736edf7267e4b731dd82677bfab047a crypto/ec/ec_curve.c 8cfd0dcfb5acbf6105691a2d5e2826dba1ff3906707bc9dd6ff9bffcc306468f crypto/ec/ec_cvt.c -add58bcaf43a28e66b3a6ec1f70ed9b0b4a4a0d40230e903a26a1ff1129649e0 crypto/ec/ec_key.c +b94eb087740dde2bf697cfbc5e8a17efd80e84c5072c9c72f8ed2f9155976d37 crypto/ec/ec_key.c 35515133fb3c33c5736a9f744e835b9fc0775193357ab2492f11d0f63503c65e crypto/ec/ec_kmeth.c 652a1544120bf0fecde46a8e18cc28fffcb7cd864be2e2b84c99d571ba320e64 crypto/ec/ec_lib.c 0d113ac5dbdb420ba3d1c060f4fa3300fc0a81b571a919c2b176022fdca89878 crypto/ec/ec_local.h @@ -214,7 +214,7 @@ ed0217e7c2049b44a454b40e7e18385eadb34bce1bcf54337f420cbf988775da crypto/evp/asy e997e921669076c51e230ccb2e36b1c6755fe408c61b1177d2aa67529cab15f3 crypto/evp/evp_local.h 8963ef06e4d228f7067917434f60f0502dc4bbdf3b271649498b734f4074bfb0 crypto/evp/evp_rand.c 0bdae4714221662282dccd5b1f2485370d24e463c11bdbb71a310f34616954fe crypto/evp/evp_utils.c -8f4194bcc2e0de69236925aa7515bc31f36ed113dcd3cee5d71167ac770cdfdd crypto/evp/exchange.c +1d78745866dde8224eec50c8553a15b51aa14bc3313969479806b3c3024c7282 crypto/evp/exchange.c 294284ad040fe4b74845f91b1903c961c757e1ef3fcc2ffa35f43f37f1655e64 crypto/evp/kdf_lib.c 532f0ff4ab32068f160016f39cd520fadfbd09b81b3b3b562bf543acafb38889 crypto/evp/kdf_meth.c d911878128b90b98f3a4a1fb844ef3a20d35eafda3f80773dac8ce93c55bc352 crypto/evp/kem.c @@ -239,7 +239,7 @@ bb208ef3a2c7ebdc518bd38f2f07a17cff356040f1c5d68eea13bd9275897a52 crypto/ffc/ffc e9a500ddbe96cb5b302fd2db74fac0924a6ac45732df5ee1c09e82b19d06ccfd crypto/ffc/ffc_params_validate.c f172c8c2112ee82716a7bc3a3e05d5cc26188c66b9d768ac1ff906845063d2cc crypto/hashtable/hashfunc.c ed523d9793ff9db947857bca354067d17b8de5a4b28604dbf902320e62d93e33 crypto/hashtable/hashtable.c -7a9af0b14f1463b36de0689bc434a318adcb7990bb23862bf1d2a0adf510583a crypto/hmac/hmac.c +9a63ec43c8b9a55e0b135394a659026c1d1236978ebbb5df0e3c4c5c58b62ef4 crypto/hmac/hmac.c 907dd44e0bf873eebefcb4d82975b72ecec9e0f3c348c79314450fdaa78d4073 crypto/hmac/hmac_local.h 0e2d6129504d15ffaf5baa63158ccec0e4b6193a8275333956d8f868ef35127e crypto/ia64cpuid.S 29c020cf599c24ef9969a42e00e690a7b463c20dd90356b0a4117ca31b13db6f crypto/initthread.c @@ -248,28 +248,28 @@ ed523d9793ff9db947857bca354067d17b8de5a4b28604dbf902320e62d93e33 crypto/hashtab 899ba6a9049a61d5b175637907f747f58863cd8950409cefac8fbc8f574f970c crypto/loongarch64cpuid.pl 460a7af09cde89a820b091522ada1310cfcec99c60aee505f94c48c35e9a29e8 crypto/loongarchcap.c f866aafae928db1b439ac950dc90744a2397dfe222672fe68b3798396190c8b0 crypto/mem_clr.c -23ff635daa1a3149e14de6c2a41b82a7587801581bdf39b8a82e9c624da95471 crypto/ml_dsa/ml_dsa_encoders.c +1812ee360303b9fdcebe6dd0690944646bd9605ee67e3554c691cf5993293c46 crypto/ml_dsa/ml_dsa_encoders.c 825105b0a2c4844b2b4229001650ff7e61e1348e52f1072210f70b97cd4adb71 crypto/ml_dsa/ml_dsa_hash.h -2fbef0188a8606c56f2ffffecfbbbd13ccd454c2af949d6e37fb7c929974f1d4 crypto/ml_dsa/ml_dsa_key.c +2bebd01093de6f77dabb8b6e5ac3deaad9104904956691e22d80f105a3e526c2 crypto/ml_dsa/ml_dsa_key.c 579c1a12a5c5f014476a6bf695dc271f63074fb187e23ffc3f9ccb5b7ea044f1 crypto/ml_dsa/ml_dsa_key.h 3f98eb0467033d0a40867ef1c1036dcfea5d231eeac2321196f7d7c7243edace crypto/ml_dsa/ml_dsa_key_compress.c 170292bfc8761e39b688ccfb21b3660af6e1a875aa38ff7448cc22f71f5874c5 crypto/ml_dsa/ml_dsa_local.h -0490a89372b79d98c2fdc294f836fddd7a54a148202ffbd50c2d4371816a94d8 crypto/ml_dsa/ml_dsa_matrix.c +6ac18f9ef27efc7fddc38ad5edec94fcf76a972ca9fcb6bdc5472673d885d238 crypto/ml_dsa/ml_dsa_matrix.c ff65c82c56e341f47df03d0c74de7fb537de0e68a4fa23fa07a9fdb51c511f1c crypto/ml_dsa/ml_dsa_matrix.h c2652262227348b8bb053a239e8491b26f08d6fadc47ba3471302f5797ae1c62 crypto/ml_dsa/ml_dsa_ntt.c 3e0980e67842c4d8637fa449ac41e9d650c614c1074c29f1021605d229a4f73d crypto/ml_dsa/ml_dsa_params.c 10e37ab3ee09a45d99007665e073efb2b062c819f30af8694c6b0f411eb33822 crypto/ml_dsa/ml_dsa_poly.h -26be5266a9f1a33999a5a68c96cffc7932ba64521d9554dabe7397591611c852 crypto/ml_dsa/ml_dsa_sample.c -26ce39dd4cdac0a1c00cee24d53e156c16a1577c71a8a96bce3e2b4130afa6f5 crypto/ml_dsa/ml_dsa_sign.c +abb4f2263fb9b6d08911e1b8e2df2c2de636d6255f7cf3eee594f50dedcefc0c crypto/ml_dsa/ml_dsa_sample.c +f1cbf5ebe46fe456e338a496193bf028d48a28bb3d4804591094babe84d83b25 crypto/ml_dsa/ml_dsa_sign.c 5217ef237e21872205703b95577290c34898423466a465c7bd609b2eb4627964 crypto/ml_dsa/ml_dsa_sign.h -8311e08d9d0e2e073092d0cfaf64851fb8d0f0708dfc2707422f525f87f269d0 crypto/ml_dsa/ml_dsa_vector.h -0fbbb11e30b7e3f4e5366334e273dcc3f6440ed04a0758f0c99279c25b8c0baf crypto/ml_kem/ml_kem.c +afc44b2cdf6a03555cebcc0398179b44f5810098d0b17dcb2b0c0c62023d6964 crypto/ml_dsa/ml_dsa_vector.h +dd95a5261fd1624e1e93270b0dc9404c887506a402d55521a5074975db833fd6 crypto/ml_kem/ml_kem.c 36e24eae5d38cc9666ae40e4e8a2dc12328e1159fea68447cb19dab174d25adf crypto/modes/asm/aes-gcm-armv8-unroll8_64.pl 33357356cd739d4ae89d52f0804b6900e4b94d8829323819c6f64c8908e978df crypto/modes/asm/aes-gcm-armv8_64.pl -a91995f81b384b175ecf252690030bb068d6af64bfcdab2fe753484b2d07a184 crypto/modes/asm/aes-gcm-avx512.pl +573c286991352233cb068d0e218c5cb1e6fe5d07a924496dbccca95fa82e1d4d crypto/modes/asm/aes-gcm-avx512.pl 8fab6574aa99ee635d564dbe68b014562b61af37fa4f151210690837cdae6707 crypto/modes/asm/aes-gcm-ppc.pl dd0de5ca8913a941cfff781a42fba43227e133976a24d0fddebf63909f7e010a crypto/modes/asm/aes-gcm-riscv64-zvkb-zvkg-zvkned.pl -9dcd3be86cda832ebe0394f5a859a761f4b711f2010fb606457f754722c5fb84 crypto/modes/asm/aesni-gcm-x86_64.pl +a4fad5a5cb112929323632e4f3f5fce7d6f0ceb6ea2e3ed1a4a2165f05fbf0b5 crypto/modes/asm/aesni-gcm-x86_64.pl c2e874a8deb418b5d8c935b2e256370566a5150e040c9fa008cdb5b463c26904 crypto/modes/asm/ghash-alpha.pl 6bc7d63569c73d7020ede481f2de05221ac92403c7cc11e7263ada7644f6aa9b crypto/modes/asm/ghash-armv4.pl 097975df63370de7ebea012d17de14fc1f361fb83acf03b432a99ae7d5bceb24 crypto/modes/asm/ghash-c64xplus.pl @@ -281,7 +281,7 @@ e6d6ce559210aee1e97f098683e290c221cc90f6f4f8047b331e8071a8387559 crypto/modes/a 92071f9c046f312c4eb7df483f385bc71ade863392e1acf3e821912bcc5cfaa7 crypto/modes/asm/ghash-s390x.pl 6af1a05981e1d41e4dea51e58938360e3abc4a4f58e179908242466d032b1a8a crypto/modes/asm/ghash-sparcv9.pl 26f55a57e77f774d17dfba93d757f78edfa3a03f68a71ffa37ccf3bfc468b1e2 crypto/modes/asm/ghash-x86.pl -487e23973c9c782d375a956da6231e91f450182d8822d3f86fd4924e143fed70 crypto/modes/asm/ghash-x86_64.pl +3d746cc0cf6cca866e34cdbbd79f5660244033fa440ed82aaaa9dd16cebf821f crypto/modes/asm/ghash-x86_64.pl a4e9f2e496bd9362b17a1b5989aa4682647cefcff6117f0607122a9e11a9dfd9 crypto/modes/asm/ghashp8-ppc.pl 92f17ee53bd40123358ce5b37bcd6063bfa7d6860dd734d4ac585249c03a6b32 crypto/modes/asm/ghashv8-armx.pl ca4be187fc1805d498f2adb823509f0519e214644029c18d331b5b01a0891a9d crypto/modes/cbc128.c @@ -312,7 +312,7 @@ ed6956c34da5127fbf8f1a067654b617c261039743a12fd1d296a1dd01b05c26 crypto/params_ fcafd9ac56254e921f43dda47aa6d19ff42b3461ff3a72e0bff1840793f96701 crypto/provider_core.c aa58d7800d3ccf2989b0de3c2e2710dfac36c88dc51659129897b0dfd2162527 crypto/provider_local.h 5ba2e1c74ddcd0453d02e32612299d1eef18eff8493a7606c15d0dc3738ad1d9 crypto/provider_predefined.c -5f077b3d3c0127c9051907f91b7184d18ad045452e0cd891937932c8fb1f129f crypto/rand/rand_lib.c +1e919f7f3c860eb21bf2f6f868dae076c64c53f1ad794c6764f69329724c3fc2 crypto/rand/rand_lib.c 9e162caba63741e3df4d0f1c49a7555263ebc120cfb643546ea7e34d3f5eb862 crypto/rand/rand_local.h dce7413b4c4e588c9a099c6fd7c6c9a397e034f259a2027d4ea8bdfe149164fa crypto/rcu_internal.h 0c1d3e0e857e9e4f84752a8ef0b619d8af0d81427b52facbd0174e685dac9a47 crypto/riscv32cpuid.pl @@ -322,7 +322,7 @@ f0c8792a99132e0b9c027cfa7370f45594a115934cdc9e8f23bdd64abecaf7fd crypto/rsa/rsa b1584c4a1a5f83a1fd43d854ce72bb11735aa34945f2b2f983228f36f27fdad2 crypto/rsa/rsa_backend.c 38a102cd1da1f6ca5a46e6a22f018237964336274385f5c70cbedcaa6997647e crypto/rsa/rsa_chk.c e762c599b17d5c89f4b1c9eb7d0ca1f04a95d815c86a3e72c30b231ce57fb199 crypto/rsa/rsa_crpt.c -e666568eadfd01ff3e435364dee2575fca7ff3e6855b2c258fa1e4d04239d933 crypto/rsa/rsa_gen.c +157eec6c45b95ed974324055f594885c50e33616af3af06efb558d651a786c69 crypto/rsa/rsa_gen.c f22bc4e2c3acab83e67820c906c1caf048ec1f0d4fcb7472c1bec753c75f8e93 crypto/rsa/rsa_lib.c 969a13b951b8a77337fef84437b1aeec49ab1c73ecbceeb4b0df2174ae16a9a2 crypto/rsa/rsa_local.h cf0b75cd54b61b9b9a290ef18d0ddce9fb26a029a54eb3f720d9b25188440f00 crypto/rsa/rsa_mp_names.c @@ -350,13 +350,13 @@ be1e7dd9998e3f31cfa6e1b17bc198aeec584a8b76820e38f71d51b05f8a9f2a crypto/sha/asm 79dec13ccbee4a6758a22d92bfd5694565416219e48b6894dfb63c6b0029ae28 crypto/sha/asm/keccak1600-s390x.pl 3fb93b9440f5c3008b5c876a8106acc5f8d38f1afedd79381f0befec7dd7d72b crypto/sha/asm/keccak1600-x86_64.pl 831b8b02ab25d78ba6300ce960d96c13439bfba5844e13061e19c4e25cbacc3d crypto/sha/asm/keccak1600p8-ppc.pl -75d832db9bf0e98e7a5c522169060a6dd276c5118cfb297fc3f1111f55cd4007 crypto/sha/asm/sha1-586.pl +131d338bc716d9b5d4c1d3e8de213aa621f7581f91ec0ee7e2e56a9a94f1822b crypto/sha/asm/sha1-586.pl c96e87d4f5311cd73bbdf499acc03418588be12426d878e157dd67e0099e0219 crypto/sha/asm/sha1-alpha.pl 695ef6f8041f37f4b39cb7099e9c7c3a29d6f823823df7333530d375f5f5e01b crypto/sha/asm/sha1-armv4-large.pl cb32284af92d99d7046b99dd5bbd894d53531f7b99d351235a939c542680193b crypto/sha/asm/sha1-armv8.pl 11d332b4e058e9fa418d6633316d2e9f9bf520a08b2d933e877bdf38b2edefcf crypto/sha/asm/sha1-c64xplus.pl 32ff0e701a7b8f25bcfe8477b20795de54f536527bd87d3ce694fd9aaae356d4 crypto/sha/asm/sha1-ia64.pl -de6c7e8c1e27779a8cf1ce2a04f487a3d4dc510d5ba240cd06128ecc8574e424 crypto/sha/asm/sha1-mb-x86_64.pl +9fdde42e62c5a5c0457316ac35e6f6f940061634ab1e44a1ef5cdbacb656d738 crypto/sha/asm/sha1-mb-x86_64.pl 0f5c63cf09e950d1b488935ab3b5562e3e9d5cd1a563fb88a41e3dae90a35e6d crypto/sha/asm/sha1-mips.pl b5ffd7b6dbb04c05de7efa2945adb67ea845e7e61a3bf163a532f7b6acdf4267 crypto/sha/asm/sha1-parisc.pl 482cd23ca6ec38d6f62b90c68f9f20643579c50f2c0fbb0dab1c10a0e35efe77 crypto/sha/asm/sha1-ppc.pl @@ -364,11 +364,11 @@ b5ffd7b6dbb04c05de7efa2945adb67ea845e7e61a3bf163a532f7b6acdf4267 crypto/sha/asm 7fd355b412ddfa1c510e0ba3284f75b1c0d621b6db2ecb1d2a935d5cdb706628 crypto/sha/asm/sha1-sparcv9.pl 24554e68b0e7b7db7b635ff149549015f623ca0bcd9ae90439586a2076f6ae80 crypto/sha/asm/sha1-sparcv9a.pl 74d197cdd72400cabbff7e173f72c8976723081508b095dc995e8cd1abf3daa6 crypto/sha/asm/sha1-thumb.pl -dc363497de4fa3bc88b16e834ddf4967aecabdba5ea3ddd6113cf00da7e278bd crypto/sha/asm/sha1-x86_64.pl -c099059ef107f548ea2c2bab64a4eb8c277070ce6d74c4d32bb9808dc19c5fa3 crypto/sha/asm/sha256-586.pl +a579c0ab82151f8879bac23ef1ffb198dfbf9b02d2015c500a232baafc6a3722 crypto/sha/asm/sha1-x86_64.pl +494390ee974a00a0bfdb0ee46116efa45379b5e63988c0a3be9ff6183be2359d crypto/sha/asm/sha256-586.pl 0f01f7b5b0699f1e8ca260439d009febfa5b85b9e7b0933d236467e383aaaa2e crypto/sha/asm/sha256-armv4.pl 93ddc97651ee3e779144a3c6b3e46a1bc4aa81e75cd7b9df068a2aef8743d25f crypto/sha/asm/sha256-c64xplus.pl -9a68b6642b20e3cdccd636c4a934a6e0114160506784583f684ad65aefac2872 crypto/sha/asm/sha256-mb-x86_64.pl +478035fb599566f468f68ae9a3c5311b1e9c6257de6c47a7a32082c8aee41c8d crypto/sha/asm/sha256-mb-x86_64.pl b14670492f24cd0d2fedf8780e981b7da123203395c085334d4571b619b0a610 crypto/sha/asm/sha256-riscv64-zvkb-zvknha_or_zvknhb.pl dd82e1311703abb019975fc7b61fb87d67e1ed916dddd065aced051e851114b9 crypto/sha/asm/sha512-586.pl 16e68ac669860c5bf8e4db81cd3d64fc2c22168e129c2597e94b0f56fafcdfa8 crypto/sha/asm/sha512-armv4.pl @@ -381,7 +381,7 @@ fb06844e7c3b014a58dccc8ec6020c71843cfdc5be08288bc7d204f0a840c474 crypto/sha/asm 07804b96dda856cffaef291641c4ae7f59288ed1e65e38823cfdcb74f8ac5295 crypto/sha/asm/sha512-riscv64-zvkb-zvknhb.pl 38e0455fd6a2b93a7a5385379ca92bc6526585ca1eb4af365fac4c78f7285c72 crypto/sha/asm/sha512-s390x.pl 0611845c52091b0208dd41f22ddef9dd1e68d3d92fa4c4360738b840a6314de6 crypto/sha/asm/sha512-sparcv9.pl -473874a27b031e3d6c3dd0388c7231aa299e07c5832fa7499a081488e6f5680a crypto/sha/asm/sha512-x86_64.pl +14b563ed790d9bd76b0f45e27b75b5fa46d393d7bea8704d2894004adc3f4ac6 crypto/sha/asm/sha512-x86_64.pl 8725cabb8d695c576619f19283b034074a3fa0f1c0be952a9dbe9793be15b907 crypto/sha/asm/sha512p8-ppc.pl 93858e3b530333a129127b8df8cd3326cf55b770238b4fff2474c4e6e3def1dd crypto/sha/keccak1600.c 306cacd3f86e5cacaca74c58ef862516515e5c0cafaff48636d537fd84f1c2fb crypto/sha/sha1dgst.c @@ -391,19 +391,19 @@ a7e074a2f2cea0c33e7875eacc8adb465b5802e4c1d100cda79ac3dd52cdb453 crypto/sha/sha 61ab6d7d7da9e65120ec59cfa9f5ede785502ae371696c3e4e04e039743ca111 crypto/sha/sha_local.h dfd99e02830973ab349409ac6ba0ee901ba7736216030965bd7e5a54356abd7c crypto/slh_dsa/slh_adrs.c c9b270de1259d9fa71a4d352786357bcf1dd3d22075edab84501e2f8e550b271 crypto/slh_dsa/slh_adrs.h -95d42ca839ff34a050a7006734a06c157ad259512c1a10b978e9f899efe69f12 crypto/slh_dsa/slh_dsa.c -ab7b580b1cba302c5675918b457794a3b3d00aac42297312d9447bc6f6a40b09 crypto/slh_dsa/slh_dsa_hash_ctx.c -892a5ed5213c0898882bfc42f72be2864b363cd62d08a3b337c20b4fa557bef0 crypto/slh_dsa/slh_dsa_key.c +26566d0e641456101bd17338dbbb16f59dfacd34f76cff5882133a0ab7323130 crypto/slh_dsa/slh_dsa.c +6b88a8ca514dd2ead7808bf08ea7c7e89125cdcfae8f0db4f3518069382fdfa0 crypto/slh_dsa/slh_dsa_hash_ctx.c +924e686178fdc5984d1a09b02d91e04d4b9c4eb818ee384107ca64357c237e39 crypto/slh_dsa/slh_dsa_key.c 4c7981f7db69025f52495c549fb3b3a76be62b9e13072c3f3b7f1dedeaf8cc91 crypto/slh_dsa/slh_dsa_key.h -5dcb631891eb6afcd27a6b19d2de4d493c71dab159e53620d86d9b96642e97e8 crypto/slh_dsa/slh_dsa_local.h -adb3f4dea52396935b8442df7b36ed99324d3f3e8ce3fdf714d6dfd683e1f9f0 crypto/slh_dsa/slh_fors.c -5d3855cb2927efa4b28fec4357694bf863ac8dc6556009bdfa800ba16cb80b4d crypto/slh_dsa/slh_hash.c +f8007c0f93908810f138f872809cd49013e22192907f4c38d290b6c4566230f5 crypto/slh_dsa/slh_dsa_local.h +6d3f3c0be706c1dd871db863f2344f709a2b7fbb60a0d91298aeb2222f767a87 crypto/slh_dsa/slh_fors.c +f6f5286c6ce9f37cbb527144ec09fd86ae796ac3e71f0bdbb45b5a08a0692122 crypto/slh_dsa/slh_hash.c 3af167addbfd97f831f2a1981133bf4e2b62b95dc9477767797f7e4a653556db crypto/slh_dsa/slh_hash.h -6402664fbb259808a6f7b5a5d6be2b4a3cc8a905399d97b160cdb3e4a97c02c4 crypto/slh_dsa/slh_hypertree.c +1eebf59ebd0859be5a8deddd2f664f99158060904234532af608a44dd6d92d19 crypto/slh_dsa/slh_hypertree.c 1ce9b4f4f90a6f82005c9cdc0ea1f6b6876556c76f8bfd95f4c003a1c195a266 crypto/slh_dsa/slh_params.c 86b16a2c36d708cb880ba49648bb3051c2997188c8ea6aec9292534b97232c7f crypto/slh_dsa/slh_params.h -1aa9dc1c6fe59d024485df9a6b782ac4d0656a31b12faee749fe098911799eaf crypto/slh_dsa/slh_wots.c -59db81a3342c0c89b030756168b9a7f09c938b2cd3498335108e0a32c041b6e7 crypto/slh_dsa/slh_xmss.c +668a2431034f8c604970ed531e32b7b20b6b710e258d1db0a8eb06a13d900f0e crypto/slh_dsa/slh_wots.c +37fff5f88dd8bcd0ad8cdbab130c5a9a018422fe59b141bdb11bcee8fd1b046f crypto/slh_dsa/slh_xmss.c 9ef5a01caccc2eb15f72e367d0424737040ac8018479bbbbce3d216c655765c2 crypto/sparccpuid.S b462d1efe0acd798e1ec5f37fd1c824a587e1773e6a6f984d5a332581573ecbc crypto/sparcv9cap.c 9e16e8641ac5ec2cb2fcc8e4796af5b698d6fa4ce85e374bd8f5b4edb51e6428 crypto/sparse_array.c @@ -417,7 +417,7 @@ f06b08138d73b834471abc4a3ba43b2be838f7196c937c3e933694d6cd69f74d crypto/thread/ 2e5955d706b96c487e4875ffbe208fac15bdca06b33cee916d5343978c14efa1 crypto/threads_lib.c b3743dfd1c13fe70dc57a5a0b2ec540ab3afa748699eb6ef36f56f4d36d06ef3 crypto/threads_none.c 7b97b0f57f6b7cac89c1b8bd03bee34fb39d33cfae1632e75571ba106a5b9442 crypto/threads_pthread.c -9dac146cda57fb53d9b9eb30ff1fc81090f5e62dbe05d4cd97ed11cf501fc78c crypto/threads_win.c +a4692ad34bd148e06344672e08a3ba928719ca5af4d11ba54d97926759dcda0b crypto/threads_win.c 93f8fe09f96492a6be6772ddbf0cc37912fc2a90acb7faea378da1735fe20f6f crypto/time.c 88c5f9f4d2611223d283ebd2ae10ae5ecbb9972d00f747d93fcb74b62641e3f9 crypto/x86_64cpuid.pl 085d9fe93adf232f1ff838be9235046c2c2abe2daeb0e6342921d8f2e955dc18 crypto/x86cpuid.pl @@ -468,7 +468,7 @@ b41a5d9a7bdf60df169e327b41f16489830b82393dd663d1f89f81da4483eaa7 include/intern 9bafa62442fdeda25b97fdbe8e8bf8ea62a5b5167adb2ac7ebbb13db271673f9 include/internal/ffc.h 0a82ff0abab6ab815f9cb523b9643854346b47ff276f8868d1cbe48efc1b20ee include/internal/fips.h 923d4fb14a08f9b251b9bf9727bc50930d0279e8b63243faf85374bdcbbfc4e0 include/internal/hashfunc.h -a37a58d887ae4331a19179900b8d077afa1174c5152d53dc1533c37a65f319d6 include/internal/hashtable.h +d76c942d91e97f8954852ec7ae5a790a591b44762bba31930af585ed5f861fe0 include/internal/hashtable.h f6f30785e3eced1ccdd4b149286ff2b8bbb860eb7e070cbe54c997aa022854da include/internal/namemap.h c367e6120d26a2b629f4db7e179973e33fb095e1102d5c7a69c744b88ebe4469 include/internal/nelem.h eef3ec603b9877bd24a8fa1dbcd7752618fa74943b045515720bb0ca61394ae5 include/internal/numbers.h @@ -568,7 +568,7 @@ a481e8762c694b3dac0e74aac8626fe60fa94962a14914f1f6969ea1214c40b1 include/openss 9e04a3e9ca5352adffbdd75a5ea5237e8ff96a8c0a842368cc3a29de006b2ee7 include/openssl/types.h 62e0cddeedfc217ac02bf37f3669ccea8d0822a88a74a8ec82b844a85b2700aa include/openssl/x509.h.in 869959c3d557d2ace84f38b7a8d0f23b3b0854de7f952f46310e828af04554dd include/openssl/x509_vfy.h.in -5dbee881fe4e1f08a773e8bd34eeda7639be7c474a3d4d6e7c8d779e19c7eb2a include/openssl/x509err.h +53a45ca5d00026ef0a256f7ff27f5708d5af0a44177a0fc4b209ec054d44e18c include/openssl/x509err.h c0a9551efccf43f3dd748d4fd8ec897ddaabbc629c00ec1ad76ce983e1195a13 providers/common/bio_prov.c 6d25e1b61731cc558c2f801350d0cd874d3c19a3b0a03f52394c11fcaf2d51a5 providers/common/capabilities.c f94b7435d4ec888ec30df1c611afa8b9eedbb59e905a2c7cb17cfc8c4b9b85b8 providers/common/der/der_digests_gen.c.in @@ -611,7 +611,7 @@ b10730f4d302344579c09f43d5f9c5538bb6b4acd60de7430c24269fc522d5a5 providers/comm e2f8f00519d81aa16f1c30e8cbf9a0d8e898a1cb5c8b38bb01dd9ab513e34c9e providers/common/securitycheck_fips.c abd5997bc33b681a4ab275978b92aebca0806a4a3f0c2f41dacf11b3b6f4e101 providers/fips/fips_entry.c d8cb05784ae8533a7d9569d4fbaaea4175b63a7c9f4fb0f254215224069dea6b providers/fips/fipsindicator.c -0c473190a4b6809caed57997e44ee9ec949bcf01c542633e2881d07c809d3a51 providers/fips/fipsprov.c +f0f1486219ddb5817b5105c36f384cb9ef095ddceec50966fe178f4b4177028c providers/fips/fipsprov.c 8f52eead96febbce9e7f2bf5aaea557efe8f94ce078044959e80e5ae78432539 providers/fips/include/fips/fipsindicator.h ef204adc49776214dbb299265bc4f2c40b48848cbea4c25b8029f2b46a5c9797 providers/fips/include/fips_indicator_params.inc f2581d7b4e105f2bb6d30908f3c2d9959313be08cec6dbeb49030c125a7676d3 providers/fips/include/fips_selftest_params.inc @@ -639,7 +639,7 @@ be18c20e0197f25fe7b9e0268657a2271a69d216b89cb100f082fa5fcaad1e07 providers/impl 60c4f604cf9b5457be48f31cc24ca21729660381081b2dbf99f362a013a09684 providers/implementations/ciphers/cipher_aes_gcm_hw_vaes_avx512.inc e2886780637db72b12c9bc488d81647ed55a7f5c850efd4bdbf88ef7127e1913 providers/implementations/ciphers/cipher_aes_hw.c 89de794c090192459d99d95bc4a422e7782e62192cd0fdb3bdef4128cfedee68 providers/implementations/ciphers/cipher_aes_hw_aesni.inc -eac58fff6aa9918d657228c2707f1b3f0ef8f1210c97575f3c264db78bfd996f providers/implementations/ciphers/cipher_aes_ocb.c +b88e88831695dfc165ce83e64802ffb8240f1f696d9c67f350b9ff1b2e913212 providers/implementations/ciphers/cipher_aes_ocb.c 88138a1aff9705e608c0557653be92eb4de65b152555a2b79ec8b2a8fae73e8f providers/implementations/ciphers/cipher_aes_ocb.h 6c3a89771719b36d6917d23464be5441836378393731af96ba165fd788df1a41 providers/implementations/ciphers/cipher_aes_ocb_hw.c c7aac28a9dca1ad46e5bce4de93e07dffec1f89fab82394c3ff7cf1bda8b483f providers/implementations/ciphers/cipher_aes_wrp.c @@ -655,7 +655,7 @@ dc4626becaabc3990549483d9ef5f05c7dd9a9c2cf9be96ade3ba6a6e203f7f5 providers/impl cca34f1c7baf3a98964f7ce19a59e06d1eaf2ada121a0d4a438f4078a072b325 providers/implementations/ciphers/cipher_tdes_hw.c d2f418806c7ed45f118683bc13329573804592684e522efced0fd0921f4548fd providers/implementations/ciphers/ciphercommon.c ab9a2edb23aa61cf31da6addd8674a6028f93399eceeeee35a56ee770338fd6c providers/implementations/ciphers/ciphercommon_block.c -6b6090c233ddf29d819f2559361aeeae03505de7626a127628d5f0f6d3bce295 providers/implementations/ciphers/ciphercommon_ccm.c +fafb07c3fd77a89cff1d2efbb6edc0767132fc30c57f9e282080da04e6762499 providers/implementations/ciphers/ciphercommon_ccm.c 6632a555d5bcd5af67d0355ce46c2906bb3a0dcdf1651595b29189c40a5ca675 providers/implementations/ciphers/ciphercommon_ccm_hw.c ab51261da6aea5a3cca74a7561e4b89e6ce83f2ac497a5c766ecd3c3bff95152 providers/implementations/ciphers/ciphercommon_gcm.c bb67eaa7a98494ca938726f9218213870fc97dd87b56bda950626cc794baf20b providers/implementations/ciphers/ciphercommon_gcm_hw.c @@ -692,39 +692,39 @@ abe2b0f3711eaa34846e155cffc9242e4051c45de896f747afd5ac9d87f637dc providers/impl a9a5a3ba575b1a372f5a09135667ac1b0e303f8b19b0707804390aba9e266eca providers/implementations/kdfs/sskdf.c f01cbd7c5351d4aa9ae667627503b2cfef6fc0695e7a42296b7bf015c9a418b3 providers/implementations/kdfs/tls1_prf.c 39207243a84beb670cb0e64b6d0fe7bfc6a3dd84000617b647a3ecf52a1da3c2 providers/implementations/kdfs/x942kdf.c -748af266d06006da10524f3a621c65b8c3eeddf8b1ccd06ecdc6b689564d220c providers/implementations/kem/ml_kem_kem.c -35549cec7031452bb5b46aa8a86028abc7a3a2b39f9f6564fa4bd402451bc647 providers/implementations/kem/mlx_kem.c -e89b894af920504160abfc11860b89b505d116d978162a02213f72500180903b providers/implementations/kem/rsa_kem.c -aa13d72bc69a374db72b6d44e2f2c2ddd5f7bddbe16b950e3c4666d876c63735 providers/implementations/keymgmt/dh_kmgmt.c +b1431361b8a3448b73f4a46c48b3a4f9fd378c2abba67563f4407b1c7f007fca providers/implementations/kem/ml_kem_kem.c +926e08e60171cc867220e0f106533ed155132a034690bddea1e7793a879ebf73 providers/implementations/kem/mlx_kem.c +ff22e920552b82db3dab51b09f9dd2fd038ef0d57fb76cea5578e703653d28c9 providers/implementations/kem/rsa_kem.c +6599ad60eef3554741e049c3ff1bd9cc6064d4f3d1835e1ea5dec3a0c14c80bb providers/implementations/keymgmt/dh_kmgmt.c c0446d1b2101ddd977063516b87d23f424cdca33473f293db4c3974b674169b0 providers/implementations/keymgmt/dsa_kmgmt.c -2b98ba2124a86eae2adc7b88bfa26e47b548e9628b99180cc2cd841eed5ed8da providers/implementations/keymgmt/ec_kmgmt.c +45480796e6ea50cbe9529c17f9fa04228a9126dc7e7e32971519eeb6d6ac267c providers/implementations/keymgmt/ec_kmgmt.c 258ae17bb2dd87ed1511a8eb3fe99eed9b77f5c2f757215ff6b3d0e8791fc251 providers/implementations/keymgmt/ec_kmgmt_imexport.inc -167cd7df056bf46f3481cf6101fb6cfca55dea592f896c2b29649df1939885c4 providers/implementations/keymgmt/ecx_kmgmt.c +c559f1f265388e7b1c8195188fcc71ac8af09b3398530ec8ed7a9afd7b41281e providers/implementations/keymgmt/ecx_kmgmt.c daf35a7ab961ef70aefca981d80407935904c5da39dca6692432d6e6bc98759d providers/implementations/keymgmt/kdf_legacy_kmgmt.c 69b509e9c7fe9692622d1059917c3adb991c0047e11bc116f0a393a3a0539445 providers/implementations/keymgmt/mac_legacy_kmgmt.c -3c63e65bd1a6a2e853828205c015a50c38a82f2fee9bf6787dce6dab7331bb91 providers/implementations/keymgmt/ml_dsa_kmgmt.c -5c95eb8192483b2d81435e52aef6b2c96180bb22a67f717c29661a13b5861b02 providers/implementations/keymgmt/ml_kem_kmgmt.c -f37c8b7bb59d4b199889044992cb1b18ad39f2eafc87029f5348c55a95195e8c providers/implementations/keymgmt/mlx_kmgmt.c +7d197679dc4ae59f0e697749c56cb76399fc5eed88e94585dfd5ebdb23466e53 providers/implementations/keymgmt/ml_dsa_kmgmt.c +2df9ca1a68a9b6e1d1b108148b54ccf5454da3afa34e510beb2f4516e473e4c6 providers/implementations/keymgmt/ml_kem_kmgmt.c +4cec24edda3df01c08bef98a0a177ccdd1f8ba84e37c399dc568e010d7c0b29f providers/implementations/keymgmt/mlx_kmgmt.c cd4b8129eaccbd77f9b6c725d3cb57b71109c4649115ec786b6495100afaddf2 providers/implementations/keymgmt/rsa_kmgmt.c -d640cff1c46911b69866eb83f48beba42a1741bb1d3f1db6e7201077a57761fc providers/implementations/keymgmt/slh_dsa_kmgmt.c -9d02d481b9c7c0c9e0932267d1a3e1fef00830aaa03093f000b88aa042972b9f providers/implementations/macs/cmac_prov.c +92621573e975489b821884151d2de751e462fcf91efa83cb3bf8f4fd40cd241b providers/implementations/keymgmt/slh_dsa_kmgmt.c +2a66bc54579cb1fcd72674a1e60a7a1f798c13ab964a45e5603bed699268354f providers/implementations/macs/cmac_prov.c a3bb4d7914f45cf82f86cd92135e20a712274ca153d9ed5ad24db7f33710726c providers/implementations/macs/gmac_prov.c 2d6b8c42c67e3e43d8d0035463cbff590dabb7da815f9e437a3a72d4b6596319 providers/implementations/macs/hmac_prov.c 40686337be4261685f176bb10042d903d46ab10c90e10ac42d3842e9b5ddd960 providers/implementations/macs/kmac_prov.c 0ebc5a48655a697231918644397308e64914c32421e9b8ee7afd7779b6a2fdb8 providers/implementations/rands/drbg.c -d9e41abc1780bb253bdca6c58cc32af7d0a774e52c91fc5d64577f71defc52c2 providers/implementations/rands/drbg_ctr.c -cf98646defb0b385d6ce4bedcd51559c9a03424491f4576ea7eb41e3db8a18b3 providers/implementations/rands/drbg_hash.c -57561d4bd3a79e6a250310a989958409437dfa68b2818d5f0dbb8a5e7ef04bb7 providers/implementations/rands/drbg_hmac.c +d2805527aa28c27dc0d10f3e35b64e18626691b3c864806dd644b7dd1640ec49 providers/implementations/rands/drbg_ctr.c +e624059b1c9f878655d6a21a4c295c43d147ea913f638a2d007a1a68379180f8 providers/implementations/rands/drbg_hash.c +3aa1dd31f0db1ab0a7a5a3037f722e284587c244126810268622fae65bef77d7 providers/implementations/rands/drbg_hmac.c 841617c81d6d5eae5ea59064e8b45947d436d3e53b49283329d17016866d8f34 providers/implementations/rands/drbg_local.h 355bd437dde9ecd1da89f42691147f2b5cf9a012ff5f55062bf83b6bead1e181 providers/implementations/rands/fips_crng_test.c -4913fec58a2648fcec0e5a94dba9decab0505a6d725bed6eb861ce854db81df8 providers/implementations/rands/test_rng.c +90ea602ec88f7c0a78f3e7c801cdd3574a221f04497121a9ea7dcb05b7ee6765 providers/implementations/rands/test_rng.c c6c709dfd8b1be036e2a5232d3b21dc25f0150f2aae24cc7db6b09cd790a04ee providers/implementations/signature/dsa_sig.c d10d611713a6d9aa5cdbe636f1ba90404043431fd1df01fc1a1ce8499bf96ad0 providers/implementations/signature/ecdsa_sig.c a837f69cb1aa5d0327372e26a63a8492b6ffb1156325f66e880c202011d07cbe providers/implementations/signature/eddsa_sig.c e0e67e402ff19b0d2eb5228d7ebd70b9477c12595ac34d6f201373d7c8a516f4 providers/implementations/signature/mac_legacy_sig.c 51251a1ca4c0b6faea059de5d5268167fe47565163317177d09db39978134f78 providers/implementations/signature/ml_dsa_sig.c -94725f9e466c60c710900ca9878196f359e8421f46d5fb62fda91f5f845caff3 providers/implementations/signature/rsa_sig.c -539d3f55b8fd28826c786cb4e5c0e735173dc0faf268527ea007052be623cd37 providers/implementations/signature/slh_dsa_sig.c +6b293ca81102cd2f234d60f52f839e5bd7a746a42df3fe8a4489e6c214108f50 providers/implementations/signature/rsa_sig.c +ec630d49078bdd901132e7651eaf3478ff3b04e5558c435ffd7c77dcb62e46b3 providers/implementations/signature/slh_dsa_sig.c 21f537f9083f0341d9d1b0ace090a8d8f0b2b9e9cf76771c359b6ea00667a469 providers/implementations/skeymgmt/aes_skmgmt.c 2dbf9b8e738fad556c3248fb554ff4cc269ade3c86fa3d2786ba9b6d6016bf22 providers/implementations/skeymgmt/generic.c 9ba8db9b0e18847ef79ecb77fbc383d8762694be29dfb7d269df6f02dc977222 providers/implementations/skeymgmt/skeymgmt_lcl.h diff --git a/deps/openssl/openssl/providers/fips.checksum b/deps/openssl/openssl/providers/fips.checksum index 7d8252550bd4..f236b8ff81a4 100644 --- a/deps/openssl/openssl/providers/fips.checksum +++ b/deps/openssl/openssl/providers/fips.checksum @@ -1 +1 @@ -f24213807982cf5d2859d5d1b78caa54c249ec28725645d1af28f092d543962d providers/fips-sources.checksums +ee77588030ee4df89ad9ff70a12118a9b89ebc4fde306fd25e9c01ef719d0b26 providers/fips-sources.checksums diff --git a/deps/openssl/openssl/providers/fips/fipsprov.c b/deps/openssl/openssl/providers/fips/fipsprov.c index 419878719e98..3c749018bcfc 100644 --- a/deps/openssl/openssl/providers/fips/fipsprov.c +++ b/deps/openssl/openssl/providers/fips/fipsprov.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -56,7 +56,6 @@ extern OSSL_FUNC_core_thread_start_fn *c_thread_start; */ /* Functions provided by the core */ -static OSSL_FUNC_core_gettable_params_fn *c_gettable_params; static OSSL_FUNC_core_get_params_fn *c_get_params; OSSL_FUNC_core_thread_start_fn *c_thread_start; static OSSL_FUNC_core_new_error_fn *c_new_error; @@ -541,7 +540,7 @@ static const OSSL_ALGORITHM fips_asym_kem[] = { { PROV_NAMES_ML_KEM_1024, FIPS_DEFAULT_PROPERTIES, ossl_ml_kem_asym_kem_functions }, #if !defined(OPENSSL_NO_ECX) { "X25519MLKEM768", FIPS_DEFAULT_PROPERTIES, ossl_mlx_kem_asym_kem_functions }, - { "X448MLKEM1024", FIPS_DEFAULT_PROPERTIES, ossl_mlx_kem_asym_kem_functions }, + { "X448MLKEM1024", FIPS_UNAPPROVED_PROPERTIES, ossl_mlx_kem_asym_kem_functions }, #endif #if !defined(OPENSSL_NO_EC) { "SecP256r1MLKEM768", FIPS_DEFAULT_PROPERTIES, ossl_mlx_kem_asym_kem_functions }, @@ -608,7 +607,7 @@ static const OSSL_ALGORITHM fips_keymgmt[] = { #if !defined(OPENSSL_NO_ECX) { PROV_NAMES_X25519MLKEM768, FIPS_DEFAULT_PROPERTIES, ossl_mlx_x25519_kem_kmgmt_functions, PROV_DESCS_X25519MLKEM768 }, - { PROV_NAMES_X448MLKEM1024, FIPS_DEFAULT_PROPERTIES, ossl_mlx_x448_kem_kmgmt_functions, + { PROV_NAMES_X448MLKEM1024, FIPS_UNAPPROVED_PROPERTIES, ossl_mlx_x448_kem_kmgmt_functions, PROV_DESCS_X448MLKEM1024 }, #endif #if !defined(OPENSSL_NO_EC) @@ -771,9 +770,6 @@ int OSSL_provider_init_int(const OSSL_CORE_HANDLE *handle, case OSSL_FUNC_CORE_GET_LIBCTX: set_func(c_get_libctx, OSSL_FUNC_core_get_libctx(in)); break; - case OSSL_FUNC_CORE_GETTABLE_PARAMS: - set_func(c_gettable_params, OSSL_FUNC_core_gettable_params(in)); - break; case OSSL_FUNC_CORE_GET_PARAMS: set_func(c_get_params, OSSL_FUNC_core_get_params(in)); break; diff --git a/deps/openssl/openssl/providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c b/deps/openssl/openssl/providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c index bf3275f97b38..c1079e0e7874 100644 --- a/deps/openssl/openssl/providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c +++ b/deps/openssl/openssl/providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c @@ -267,11 +267,17 @@ static int aes_gcm_siv_finish(PROV_AES_GCM_SIV_CTX *ctx) { int ret = 0; - if (ctx->enc) + if (ctx->enc) { + /* Generate the tag when Final is the first empty-message operation. */ + if (ctx->generated_tag == 0 + && aes_gcm_siv_encrypt(ctx, NULL, NULL, 0) == 0) + return 0; return ctx->generated_tag; - if (!ctx->generated_tag) - aes_gcm_siv_decrypt(ctx, NULL, NULL, 0); - ret = !CRYPTO_memcmp(ctx->tag, ctx->user_tag, sizeof(ctx->tag)); + } + if (ctx->generated_tag == 0 + && aes_gcm_siv_decrypt(ctx, NULL, NULL, 0) == 0) + return 0; + ret = CRYPTO_memcmp(ctx->tag, ctx->user_tag, sizeof(ctx->tag)) == 0; ret &= ctx->have_user_tag; return ret; } diff --git a/deps/openssl/openssl/providers/implementations/ciphers/cipher_aes_ocb.c b/deps/openssl/openssl/providers/implementations/ciphers/cipher_aes_ocb.c index 99254cb49a88..62e5a0c1a766 100644 --- a/deps/openssl/openssl/providers/implementations/ciphers/cipher_aes_ocb.c +++ b/deps/openssl/openssl/providers/implementations/ciphers/cipher_aes_ocb.c @@ -509,6 +509,10 @@ static int aes_ocb_cipher(void *vctx, unsigned char *out, size_t *outl, if (!ossl_prov_is_running()) return 0; + /* NULL input indicates Final, which must generate or check the tag. */ + if (in == NULL) + return aes_ocb_block_final(vctx, out, outl, outsize); + if (outsize < inl) { ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); return 0; diff --git a/deps/openssl/openssl/providers/implementations/ciphers/cipher_chacha20_poly1305.c b/deps/openssl/openssl/providers/implementations/ciphers/cipher_chacha20_poly1305.c index 977f7000c289..673e18702cf7 100644 --- a/deps/openssl/openssl/providers/implementations/ciphers/cipher_chacha20_poly1305.c +++ b/deps/openssl/openssl/providers/implementations/ciphers/cipher_chacha20_poly1305.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -30,11 +30,11 @@ static OSSL_FUNC_cipher_get_params_fn chacha20_poly1305_get_params; static OSSL_FUNC_cipher_get_ctx_params_fn chacha20_poly1305_get_ctx_params; static OSSL_FUNC_cipher_set_ctx_params_fn chacha20_poly1305_set_ctx_params; static OSSL_FUNC_cipher_cipher_fn chacha20_poly1305_cipher; +static OSSL_FUNC_cipher_update_fn chacha20_poly1305_update; static OSSL_FUNC_cipher_final_fn chacha20_poly1305_final; static OSSL_FUNC_cipher_gettable_ctx_params_fn chacha20_poly1305_gettable_ctx_params; static OSSL_FUNC_cipher_settable_ctx_params_fn chacha20_poly1305_settable_ctx_params; #define chacha20_poly1305_gettable_params ossl_cipher_generic_gettable_params -#define chacha20_poly1305_update chacha20_poly1305_cipher static void *chacha20_poly1305_newctx(void *provctx) { @@ -301,11 +301,6 @@ static int chacha20_poly1305_cipher(void *vctx, unsigned char *out, if (!ossl_prov_is_running()) return 0; - if (inl == 0) { - *outl = 0; - return 1; - } - if (outsize < inl) { ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); return 0; @@ -317,6 +312,24 @@ static int chacha20_poly1305_cipher(void *vctx, unsigned char *out, return 1; } +static int chacha20_poly1305_update(void *vctx, unsigned char *out, + size_t *outl, size_t outsize, + const unsigned char *in, size_t inl) +{ + /* + * A zero-length update is a no-op. Only EVP_Cipher() and Final produce or + * check the authentication tag. + */ + if (inl == 0) { + if (!ossl_prov_is_running()) + return 0; + *outl = 0; + return 1; + } + + return chacha20_poly1305_cipher(vctx, out, outl, outsize, in, inl); +} + static int chacha20_poly1305_final(void *vctx, unsigned char *out, size_t *outl, size_t outsize) { diff --git a/deps/openssl/openssl/providers/implementations/ciphers/cipher_chacha20_poly1305_hw.c b/deps/openssl/openssl/providers/implementations/ciphers/cipher_chacha20_poly1305_hw.c index 733547a7e732..1bd0d6a5fc81 100644 --- a/deps/openssl/openssl/providers/implementations/ciphers/cipher_chacha20_poly1305_hw.c +++ b/deps/openssl/openssl/providers/implementations/ciphers/cipher_chacha20_poly1305_hw.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -301,6 +301,8 @@ static int chacha20_poly1305_aead_cipher(PROV_CIPHER_CTX *bctx, if (in != NULL) { /* aad or text */ if (out == NULL) { /* aad */ + if (ctx->len.text != 0) + goto err; Poly1305_Update(poly, in, inl); ctx->len.aad += inl; ctx->aad = 1; diff --git a/deps/openssl/openssl/providers/implementations/ciphers/ciphercommon_ccm.c b/deps/openssl/openssl/providers/implementations/ciphers/ciphercommon_ccm.c index 2b5bddddeb78..7a70b1b09995 100644 --- a/deps/openssl/openssl/providers/implementations/ciphers/ciphercommon_ccm.c +++ b/deps/openssl/openssl/providers/implementations/ciphers/ciphercommon_ccm.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -288,13 +288,19 @@ int ossl_ccm_stream_final(void *vctx, unsigned char *out, size_t *outl, size_t outsize) { PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx; - int i; + unsigned char dummy_in = 0, dummy_out = 0; if (!ossl_prov_is_running()) return 0; - i = ccm_cipher_internal(ctx, out, outl, NULL, 0); - if (i <= 0) + /* + * Encryption sets tag_set after processing the payload, while successful + * decryption clears iv_set. Use those transitions to avoid processing an + * operation twice. + */ + if (!ctx->key_set + || (ctx->iv_set && (!ctx->enc || !ctx->tag_set) + && ccm_cipher_internal(ctx, &dummy_out, outl, &dummy_in, 0) <= 0)) return 0; *outl = 0; @@ -309,6 +315,9 @@ int ossl_ccm_cipher(void *vctx, unsigned char *out, size_t *outl, size_t outsize if (!ossl_prov_is_running()) return 0; + if (in == NULL) + return ossl_ccm_stream_final(vctx, out, outl, outsize); + if (outsize < inl) { ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); return 0; diff --git a/deps/openssl/openssl/providers/implementations/encode_decode/encode_key2ms.c b/deps/openssl/openssl/providers/implementations/encode_decode/encode_key2ms.c index 362a806589e6..2c9bff42bbba 100644 --- a/deps/openssl/openssl/providers/implementations/encode_decode/encode_key2ms.c +++ b/deps/openssl/openssl/providers/implementations/encode_decode/encode_key2ms.c @@ -1,5 +1,5 @@ /* - * Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2020-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -65,10 +65,11 @@ static int write_pvk(struct key2ms_ctx_st *ctx, OSSL_CORE_BIO *cout, return ret; } +static OSSL_FUNC_encoder_newctx_fn key2ms_newctx; static OSSL_FUNC_encoder_freectx_fn key2ms_freectx; static OSSL_FUNC_encoder_does_selection_fn key2ms_does_selection; -static struct key2ms_ctx_st *key2ms_newctx(void *provctx) +static void *key2ms_newctx(void *provctx) { struct key2ms_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); diff --git a/deps/openssl/openssl/providers/implementations/kem/ml_kem_kem.c b/deps/openssl/openssl/providers/implementations/kem/ml_kem_kem.c index 722eadf22897..14c670784c54 100644 --- a/deps/openssl/openssl/providers/implementations/kem/ml_kem_kem.c +++ b/deps/openssl/openssl/providers/implementations/kem/ml_kem_kem.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -125,6 +125,7 @@ static int ml_kem_set_ctx_params(void *vctx, const OSSL_PARAM params[]) /* Possibly, but much less likely wrong type */ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SEED_LENGTH); + OPENSSL_cleanse((void *)ctx->entropy_buf, sizeof(ctx->entropy_buf)); ctx->entropy = NULL; return 0; } diff --git a/deps/openssl/openssl/providers/implementations/kem/mlx_kem.c b/deps/openssl/openssl/providers/implementations/kem/mlx_kem.c index 376b3342ddfa..a917fa93d5ca 100644 --- a/deps/openssl/openssl/providers/implementations/kem/mlx_kem.c +++ b/deps/openssl/openssl/providers/implementations/kem/mlx_kem.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -118,7 +118,7 @@ static int mlx_kem_encapsulate(void *vctx, unsigned char *ctext, size_t *clen, if (!mlx_kem_have_pubkey(key)) { ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); - goto end; + return 0; } encap_clen = key->minfo->ctext_bytes + key->xinfo->pubkey_bytes; encap_slen = ML_KEM_SHARED_SECRET_BYTES + key->xinfo->shsec_bytes; @@ -236,6 +236,10 @@ static int mlx_kem_encapsulate(void *vctx, unsigned char *ctext, size_t *clen, ret = 1; end: + /* Erase any partial shared secret on failure */ + if (ret == 0) + OPENSSL_cleanse(shsec, + ML_KEM_SHARED_SECRET_BYTES + key->xinfo->shsec_bytes); EVP_PKEY_free(xkey); EVP_PKEY_CTX_free(ctx); return ret; @@ -324,6 +328,10 @@ static int mlx_kem_decapsulate(void *vctx, uint8_t *shsec, size_t *slen, ret = 1; end: + /* Erase any partial shared secret on failure */ + if (ret == 0) + OPENSSL_cleanse(shsec, + ML_KEM_SHARED_SECRET_BYTES + key->xinfo->shsec_bytes); EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(xkey); return ret; diff --git a/deps/openssl/openssl/providers/implementations/kem/rsa_kem.c b/deps/openssl/openssl/providers/implementations/kem/rsa_kem.c index 78925809d985..47f0c80c9443 100644 --- a/deps/openssl/openssl/providers/implementations/kem/rsa_kem.c +++ b/deps/openssl/openssl/providers/implementations/kem/rsa_kem.c @@ -131,6 +131,7 @@ static int rsakem_init(void *vprsactx, void *vrsa, const char *desc) { PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + const BIGNUM *e = NULL; int protect = 0; if (!ossl_prov_is_running()) @@ -146,6 +147,18 @@ static int rsakem_init(void *vprsactx, void *vrsa, RSA_free(prsactx->rsa); prsactx->rsa = vrsa; + /* + * Reject the trivial public exponent e <= 1. The FIPS module enforces the + * full SP 800-56B §6.4.1.1 constraints via ossl_fips_ind_rsa_key_check() + * below; non-FIPS callers wanting the complete §6.4.2 vetting can use + * EVP_PKEY_public_check(). + */ + RSA_get0_key(prsactx->rsa, NULL, &e, NULL); + if (e == NULL || BN_cmp(e, BN_value_one()) <= 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return 0; + } + OSSL_FIPS_IND_SET_APPROVED(prsactx) if (!rsakem_set_ctx_params(prsactx, params)) return 0; @@ -389,6 +402,44 @@ static int rsasve_recover(PROV_RSA_CTX *prsactx, return 0; } +#ifndef FIPS_MODULE + /* + * Reject clearly degenerate ciphertexts, c in {0, 1, n-1}. + * + * SP 800-56B Rev 2, 7.1.2.1 requires RSADP to enforce 1 < c < n-1. In a + * FIPS build that bound is applied by the RSADP primitive itself (see + * crypto/rsa/rsa_ossl.c, guarded by FIPS_MODULE), where it is also needed + * for KTS-OAEP; the primitive does not apply it in a non-FIPS build, so + * enforce it here for RSASVE. Raise the same errors as the primitive so + * the behaviour matches in both builds; keep the two sites in step. + */ + { + const BIGNUM *n = RSA_get0_n(prsactx->rsa); + BIGNUM *c = BN_new(); + BIGNUM *nminus1 = BN_new(); + int reason = 0; + + if (n == NULL || c == NULL || nminus1 == NULL + || BN_bin2bn(in, (int)inlen, c) == NULL + || BN_copy(nminus1, n) == NULL + || !BN_sub_word(nminus1, 1)) { + BN_free(c); + BN_free(nminus1); + return 0; + } + if (BN_ucmp(c, BN_value_one()) <= 0) + reason = RSA_R_DATA_TOO_SMALL; + else if (BN_ucmp(c, nminus1) >= 0) + reason = RSA_R_DATA_TOO_LARGE_FOR_MODULUS; + BN_free(c); + BN_free(nminus1); + if (reason != 0) { + ERR_raise(ERR_LIB_RSA, reason); + return 0; + } + } +#endif + /* Step (3): out = RSADP((n,d), in) */ ret = RSA_private_decrypt(inlen, in, out, prsactx->rsa, RSA_NO_PADDING); if (ret > 0 && outlen != NULL) diff --git a/deps/openssl/openssl/providers/implementations/keymgmt/dh_kmgmt.c b/deps/openssl/openssl/providers/implementations/keymgmt/dh_kmgmt.c index 8a1afe7907b1..eac99a4fed07 100644 --- a/deps/openssl/openssl/providers/implementations/keymgmt/dh_kmgmt.c +++ b/deps/openssl/openssl/providers/implementations/keymgmt/dh_kmgmt.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -793,10 +793,8 @@ static void *dh_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) #ifdef FIPS_MODULE if (!ossl_fips_self_testing()) { ret = ossl_dh_check_pairwise(dh, 0); - if (ret <= 0) { - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); + if (ret <= 0) goto end; - } } #endif /* FIPS_MODULE */ } diff --git a/deps/openssl/openssl/providers/implementations/keymgmt/ec_kmgmt.c b/deps/openssl/openssl/providers/implementations/keymgmt/ec_kmgmt.c index 305dc3a6b831..1d740307f6a4 100644 --- a/deps/openssl/openssl/providers/implementations/keymgmt/ec_kmgmt.c +++ b/deps/openssl/openssl/providers/implementations/keymgmt/ec_kmgmt.c @@ -1,5 +1,5 @@ /* - * Copyright 2020-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2020-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -847,8 +847,8 @@ static const OSSL_PARAM sm2_known_gettable_params[] = { OSSL_PARAM_int(OSSL_PKEY_PARAM_EC_DECODED_FROM_EXPLICIT_PARAMS, NULL), EC_IMEXPORTABLE_DOM_PARAMETERS, EC_IMEXPORTABLE_PUBLIC_KEY, - OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_EC_PUB_X, NULL, 0), - OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_EC_PUB_Y, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_PUB_X, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_PUB_Y, NULL, 0), EC_IMEXPORTABLE_PRIVATE_KEY, OSSL_PARAM_END }; @@ -1298,20 +1298,6 @@ static void *ec_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) if (gctx->group_check != NULL) ret = ret && ossl_ec_set_check_group_type_from_name(ec, gctx->group_check); -#ifdef FIPS_MODULE - if (ret > 0 - && !ossl_fips_self_testing() - && EC_KEY_get0_public_key(ec) != NULL - && EC_KEY_get0_private_key(ec) != NULL - && EC_KEY_get0_group(ec) != NULL) { - BN_CTX *bnctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(ec)); - - ret = bnctx != NULL && ossl_ec_key_pairwise_check(ec, bnctx); - BN_CTX_free(bnctx); - if (ret <= 0) - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); - } -#endif /* FIPS_MODULE */ if (ret) return ec; diff --git a/deps/openssl/openssl/providers/implementations/keymgmt/ecx_kmgmt.c b/deps/openssl/openssl/providers/implementations/keymgmt/ecx_kmgmt.c index 54af7a6a3956..42a0b9d7aa67 100644 --- a/deps/openssl/openssl/providers/implementations/keymgmt/ecx_kmgmt.c +++ b/deps/openssl/openssl/providers/implementations/keymgmt/ecx_kmgmt.c @@ -811,7 +811,6 @@ static void *ed25519_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) if (!key || ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)) return key; if (ecd_fips140_pairwise_test(key, ECX_KEY_TYPE_ED25519, 1) != 1) { - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); ossl_ecx_key_free(key); return NULL; } @@ -844,7 +843,6 @@ static void *ed448_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) if (!key || ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)) return key; if (ecd_fips140_pairwise_test(key, ECX_KEY_TYPE_ED448, 1) != 1) { - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); ossl_ecx_key_free(key); return NULL; } diff --git a/deps/openssl/openssl/providers/implementations/keymgmt/ml_dsa_kmgmt.c b/deps/openssl/openssl/providers/implementations/keymgmt/ml_dsa_kmgmt.c index 5ebeaae662bf..70e943ff5a03 100644 --- a/deps/openssl/openssl/providers/implementations/keymgmt/ml_dsa_kmgmt.c +++ b/deps/openssl/openssl/providers/implementations/keymgmt/ml_dsa_kmgmt.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -96,6 +96,7 @@ static int ml_dsa_pairwise_test(const ML_DSA_KEY *key) err: OSSL_SELF_TEST_onend(st, ret); OSSL_SELF_TEST_free(st); + OPENSSL_cleanse(sig, sizeof(sig)); return ret; } #endif @@ -283,10 +284,8 @@ static int ml_dsa_import(void *keydata, int selection, const OSSL_PARAM params[] #ifdef FIPS_MODULE if (res > 0) { res = ml_dsa_pairwise_test(key); - if (!res) { + if (!res) ossl_ml_dsa_key_reset(key); - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT_IMPORT); - } } #endif /* FIPS_MODULE */ return res; @@ -483,10 +482,8 @@ static void *ml_dsa_gen(void *genctx, int evp_type) goto err; } #ifdef FIPS_MODULE - if (!ml_dsa_pairwise_test(key)) { - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); + if (!ml_dsa_pairwise_test(key)) goto err; - } #endif return key; err: @@ -541,7 +538,7 @@ static void ml_dsa_gen_cleanup(void *genctx) if (gctx == NULL) return; - OPENSSL_cleanse(gctx->entropy, gctx->entropy_len); + OPENSSL_cleanse(gctx->entropy, sizeof(gctx->entropy)); OPENSSL_free(gctx->propq); OPENSSL_free(gctx); } diff --git a/deps/openssl/openssl/providers/implementations/keymgmt/ml_kem_kmgmt.c b/deps/openssl/openssl/providers/implementations/keymgmt/ml_kem_kmgmt.c index d95f021eef70..1422a3775c74 100644 --- a/deps/openssl/openssl/providers/implementations/keymgmt/ml_kem_kmgmt.c +++ b/deps/openssl/openssl/providers/implementations/keymgmt/ml_kem_kmgmt.c @@ -109,10 +109,6 @@ static int ml_kem_pairwise_test(const ML_KEM_KEY *key, int key_flags) memset(out, 0, sizeof(out)); - /* - * The pairwise test is skipped unless either RANDOM or FIXED entropy PCTs - * are enabled. - */ if (key_flags & ML_KEM_KEY_RANDOM_PCT) { operation_result = ossl_ml_kem_encap_rand(ctext, v->ctext_bytes, secret, sizeof(secret), key); @@ -147,7 +143,10 @@ static int ml_kem_pairwise_test(const ML_KEM_KEY *key, int key_flags) v->algorithm_name); } #endif - OPENSSL_free(ctext); + OPENSSL_cleanse((void *)entropy, sizeof(entropy)); + OPENSSL_cleanse((void *)secret, sizeof(secret)); + OPENSSL_cleanse((void *)out, sizeof(out)); + OPENSSL_clear_free(ctext, v->ctext_bytes); return ret; } @@ -237,7 +236,7 @@ static int ml_kem_export(void *vkey, int selection, OSSL_CALLBACK *param_cb, { ML_KEM_KEY *key = vkey; OSSL_PARAM_BLD *tmpl = NULL; - OSSL_PARAM *params = NULL; + OSSL_PARAM *params = NULL, *p; const ML_KEM_VINFO *v; uint8_t *pubenc = NULL, *prvenc = NULL, *seedenc = NULL; size_t prvlen = 0, seedlen = 0; @@ -316,13 +315,19 @@ static int ml_kem_export(void *vkey, int selection, OSSL_CALLBACK *param_cb, goto err; ret = param_cb(params, cbarg); + /* + * OSSL_PARAM_free() only wipes the secure-heap data block, + * so wipe the key material copies held in the params first. + */ + for (p = params; p->key != NULL; p++) + OPENSSL_cleanse(p->data, p->data_size); OSSL_PARAM_free(params); err: OSSL_PARAM_BLD_free(tmpl); OPENSSL_secure_clear_free(seedenc, seedlen); OPENSSL_secure_clear_free(prvenc, prvlen); - OPENSSL_free(pubenc); + OPENSSL_clear_free(pubenc, v->pubkey_bytes); return ret; } @@ -477,9 +482,6 @@ static int ml_kem_import(void *vkey, int selection, const OSSL_PARAM params[]) res = ml_kem_key_fromdata(key, params, include_private); if (res > 0 && include_private && !ml_kem_pairwise_test(key, key->prov_flags)) { -#ifdef FIPS_MODULE - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT_IMPORT); -#endif ossl_ml_kem_key_reset(key); res = 0; } @@ -542,12 +544,15 @@ static void *ml_kem_load(const void *reference, size_t reference_sz) if (!ml_kem_pairwise_test(key, key->prov_flags)) goto err; } - OPENSSL_free(encoded_dk); + OPENSSL_clear_free(encoded_dk, key->vinfo->prvkey_bytes); + OPENSSL_cleanse((void *)seed, sizeof(seed)); return key; } err: - OPENSSL_free(encoded_dk); + if (key != NULL && key->vinfo != NULL) + OPENSSL_clear_free(encoded_dk, key->vinfo->prvkey_bytes); + OPENSSL_cleanse((void *)seed, sizeof(seed)); ossl_ml_kem_key_free(key); return NULL; } @@ -708,6 +713,7 @@ static int ml_kem_gen_set_params(void *vgctx, const OSSL_PARAM params[]) /* Possibly, but less likely wrong data type */ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SEED_LENGTH); + OPENSSL_cleanse((void *)gctx->seedbuf, sizeof(gctx->seedbuf)); gctx->seed = NULL; return 0; } @@ -768,8 +774,10 @@ static void *ml_kem_gen(void *vgctx, OSSL_CALLBACK *osslcb, void *cbarg) if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) return key; - if (seed != NULL && !ossl_ml_kem_set_seed(seed, ML_KEM_SEED_BYTES, key)) + if (seed != NULL && !ossl_ml_kem_set_seed(seed, ML_KEM_SEED_BYTES, key)) { + ossl_ml_kem_key_free(key); return NULL; + } genok = ossl_ml_kem_genkey(nopub, 0, key); /* Erase the single-use seed */ @@ -780,7 +788,6 @@ static void *ml_kem_gen(void *vgctx, OSSL_CALLBACK *osslcb, void *cbarg) if (genok) { #ifdef FIPS_MODULE if (!ml_kem_pairwise_test(key, ML_KEM_KEY_FIXED_PCT)) { - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); ossl_ml_kem_key_free(key); return NULL; } diff --git a/deps/openssl/openssl/providers/implementations/keymgmt/mlx_kmgmt.c b/deps/openssl/openssl/providers/implementations/keymgmt/mlx_kmgmt.c index 5d1902ce637c..75267f88e761 100644 --- a/deps/openssl/openssl/providers/implementations/keymgmt/mlx_kmgmt.c +++ b/deps/openssl/openssl/providers/implementations/keymgmt/mlx_kmgmt.c @@ -245,7 +245,7 @@ static int mlx_kem_export(void *vkey, int selection, OSSL_CALLBACK *param_cb, { MLX_KEY *key = vkey; OSSL_PARAM_BLD *tmpl = NULL; - OSSL_PARAM *params = NULL; + OSSL_PARAM *params = NULL, *p; size_t publen; size_t prvlen; int ret = 0; @@ -307,12 +307,18 @@ static int mlx_kem_export(void *vkey, int selection, OSSL_CALLBACK *param_cb, goto err; ret = param_cb(params, cbarg); + /* + * OSSL_PARAM_free() only wipes the secure-heap data block, + * so wipe the key material copies held in the params first. + */ + for (p = params; p->key != NULL; p++) + OPENSSL_cleanse(p->data, p->data_size); OSSL_PARAM_free(params); err: OSSL_PARAM_BLD_free(tmpl); OPENSSL_secure_clear_free(sub_arg.prvenc, prvlen); - OPENSSL_free(sub_arg.pubenc); + OPENSSL_clear_free(sub_arg.pubenc, publen); return ret; } @@ -562,12 +568,18 @@ static int mlx_kem_get_params(void *vkey, OSSL_PARAM params[]) selection |= OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS; /* Extract sub-component key material */ - if (!export_sub(&sub_arg, selection, key)) - return 0; - - if ((pub != NULL && sub_arg.pubcount != 2) - || (prv != NULL && sub_arg.prvcount != 2)) + if (!export_sub(&sub_arg, selection, key) + || (pub != NULL && sub_arg.pubcount != 2) + || (prv != NULL && sub_arg.prvcount != 2)) { + /* Erase any partial key material on failure */ + if (sub_arg.pubenc != NULL) + OPENSSL_cleanse(sub_arg.pubenc, + key->minfo->pubkey_bytes + key->xinfo->pubkey_bytes); + if (sub_arg.prvenc != NULL) + OPENSSL_cleanse(sub_arg.prvenc, + key->minfo->prvkey_bytes + key->xinfo->prvkey_bytes); return 0; + } return 1; } diff --git a/deps/openssl/openssl/providers/implementations/keymgmt/slh_dsa_kmgmt.c b/deps/openssl/openssl/providers/implementations/keymgmt/slh_dsa_kmgmt.c index 8a676213903f..8799df6be6d5 100644 --- a/deps/openssl/openssl/providers/implementations/keymgmt/slh_dsa_kmgmt.c +++ b/deps/openssl/openssl/providers/implementations/keymgmt/slh_dsa_kmgmt.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -223,7 +223,7 @@ static int slh_dsa_export(void *keydata, int selection, OSSL_CALLBACK *param_cb, { SLH_DSA_KEY *key = keydata; OSSL_PARAM_BLD *tmpl; - OSSL_PARAM *params = NULL; + OSSL_PARAM *params = NULL, *p; int ret = 0; if (!ossl_prov_is_running() || key == NULL) @@ -244,6 +244,12 @@ static int slh_dsa_export(void *keydata, int selection, OSSL_CALLBACK *param_cb, goto err; ret = param_cb(params, cbarg); + /* + * OSSL_PARAM_free() only wipes the secure-heap data block, + * so wipe the key material copies held in the params first. + */ + for (p = params; p->key != NULL; p++) + OPENSSL_cleanse(p->data, p->data_size); OSSL_PARAM_free(params); err: OSSL_PARAM_BLD_free(tmpl); @@ -298,7 +304,7 @@ static int slh_dsa_fips140_pairwise_test(const SLH_DSA_KEY *key, uint8_t msg[16] = { 0 }; size_t msg_len = sizeof(msg); uint8_t *sig = NULL; - size_t sig_len; + size_t sig_len = 0; OSSL_LIB_CTX *lib_ctx; int alloc_ctx = 0; @@ -341,7 +347,7 @@ static int slh_dsa_fips140_pairwise_test(const SLH_DSA_KEY *key, err: if (alloc_ctx) ossl_slh_dsa_hash_ctx_free(ctx); - OPENSSL_free(sig); + OPENSSL_clear_free(sig, sig_len); OSSL_SELF_TEST_onend(st, ret); OSSL_SELF_TEST_free(st); return ret; @@ -366,10 +372,8 @@ static void *slh_dsa_gen(void *genctx, const char *alg) gctx->entropy, gctx->entropy_len)) goto err; #ifdef FIPS_MODULE - if (!slh_dsa_fips140_pairwise_test(key, ctx)) { - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); + if (!slh_dsa_fips140_pairwise_test(key, ctx)) goto err; - } #endif /* FIPS_MODULE */ ossl_slh_dsa_hash_ctx_free(ctx); return key; @@ -428,7 +432,7 @@ static void slh_dsa_gen_cleanup(void *genctx) if (gctx == NULL) return; - OPENSSL_cleanse(gctx->entropy, gctx->entropy_len); + OPENSSL_cleanse(gctx->entropy, sizeof(gctx->entropy)); OPENSSL_free(gctx->propq); OPENSSL_free(gctx); } diff --git a/deps/openssl/openssl/providers/implementations/macs/cmac_prov.c b/deps/openssl/openssl/providers/implementations/macs/cmac_prov.c index 58a842776233..14542c6716f2 100644 --- a/deps/openssl/openssl/providers/implementations/macs/cmac_prov.c +++ b/deps/openssl/openssl/providers/implementations/macs/cmac_prov.c @@ -1,5 +1,5 @@ /* - * Copyright 2018-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2018-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -275,7 +275,7 @@ static int cmac_set_ctx_params(void *vmacctx, const OSSL_PARAM params[]) && !EVP_CIPHER_is_a(cipher, "AES-192-CBC") && !EVP_CIPHER_is_a(cipher, "AES-128-CBC") && !EVP_CIPHER_is_a(cipher, "DES-EDE3-CBC")) { - ERR_raise(ERR_LIB_PROV, EVP_R_UNSUPPORTED_CIPHER); + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_SUPPORTED); return 0; } } diff --git a/deps/openssl/openssl/providers/implementations/macs/poly1305_prov.c b/deps/openssl/openssl/providers/implementations/macs/poly1305_prov.c index 22ff0a283739..69d4444a58d7 100644 --- a/deps/openssl/openssl/providers/implementations/macs/poly1305_prov.c +++ b/deps/openssl/openssl/providers/implementations/macs/poly1305_prov.c @@ -82,7 +82,7 @@ static size_t poly1305_size(void) static int poly1305_setkey(struct poly1305_data_st *ctx, const unsigned char *key, size_t keylen) { - if (keylen != POLY1305_KEY_SIZE) { + if (key == NULL || keylen != POLY1305_KEY_SIZE) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); return 0; } @@ -111,6 +111,10 @@ static int poly1305_update(void *vmacctx, const unsigned char *data, { struct poly1305_data_st *ctx = vmacctx; + if (!ctx->key_set) { + ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET); + return 0; + } ctx->updated = 1; if (datalen == 0) return 1; diff --git a/deps/openssl/openssl/providers/implementations/rands/drbg_ctr.c b/deps/openssl/openssl/providers/implementations/rands/drbg_ctr.c index d42f08585713..57da1cfdf33d 100644 --- a/deps/openssl/openssl/providers/implementations/rands/drbg_ctr.c +++ b/deps/openssl/openssl/providers/implementations/rands/drbg_ctr.c @@ -1,5 +1,5 @@ /* - * Copyright 2011-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2011-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -588,6 +588,18 @@ static int drbg_ctr_init(PROV_DRBG *drbg) drbg->strength = keylen * 8; drbg->seedlen = keylen + 16; +#ifdef FIPS_MODULE + /* + * FIPS requires that we use a derivation function since our + * entropy source is outside the fips boundary + */ + if (ctr->use_df == 0) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_DERIVATION_FUNCTION_INIT_FAILED, + "FIPS requires the use of a derivation function"); + goto err; + } +#endif + if (ctr->use_df) { /* df initialisation */ static const unsigned char df_key[32] = { @@ -713,7 +725,6 @@ static int drbg_ctr_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[]) PROV_DRBG *ctx = (PROV_DRBG *)vctx; PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)ctx->data; OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); - OSSL_PROVIDER *prov = NULL; const OSSL_PARAM *p; char *ecb; const char *propquery = NULL; @@ -731,19 +742,14 @@ static int drbg_ctr_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[]) != NULL) { if (p->data_type != OSSL_PARAM_UTF8_STRING) return 0; - propquery = (const char *)p->data; } - if ((p = OSSL_PARAM_locate_const(params, - OSSL_PROV_PARAM_CORE_PROV_NAME)) - != NULL) { - if (p->data_type != OSSL_PARAM_UTF8_STRING) - return 0; - if ((prov = ossl_provider_find(libctx, - (const char *)p->data, 1)) - == NULL) - return 0; - } +#ifndef FIPS_MODULE + propquery = "provider=default"; + if (p != NULL + && p->data_type == OSSL_PARAM_UTF8_STRING) + propquery = (const char *)p->data; +#endif if ((p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_CIPHER)) != NULL) { const char *base = (const char *)p->data; @@ -752,50 +758,33 @@ static int drbg_ctr_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[]) if (p->data_type != OSSL_PARAM_UTF8_STRING || p->data_size < ctr_str_len) { - ossl_provider_free(prov); return 0; } if (OPENSSL_strcasecmp("CTR", base + p->data_size - ctr_str_len) != 0) { ERR_raise(ERR_LIB_PROV, PROV_R_REQUIRE_CTR_MODE_CIPHER); - ossl_provider_free(prov); return 0; } if ((ecb = OPENSSL_strndup(base, p->data_size)) == NULL) { - ossl_provider_free(prov); return 0; } strcpy(ecb + p->data_size - ecb_str_len, "ECB"); EVP_CIPHER_free(ctr->cipher_ecb); EVP_CIPHER_free(ctr->cipher_ctr); + ctr->cipher_ctr = NULL; + ctr->cipher_ecb = NULL; /* * Try to fetch algorithms from our own provider code, fallback * to generic fetch only if that fails */ - (void)ERR_set_mark(); - ctr->cipher_ctr = evp_cipher_fetch_from_prov(prov, base, NULL); - if (ctr->cipher_ctr == NULL) { - (void)ERR_pop_to_mark(); - ctr->cipher_ctr = EVP_CIPHER_fetch(libctx, base, propquery); - } else { - (void)ERR_clear_last_mark(); - } - (void)ERR_set_mark(); - ctr->cipher_ecb = evp_cipher_fetch_from_prov(prov, ecb, NULL); - if (ctr->cipher_ecb == NULL) { - (void)ERR_pop_to_mark(); - ctr->cipher_ecb = EVP_CIPHER_fetch(libctx, ecb, propquery); - } else { - (void)ERR_clear_last_mark(); - } + ctr->cipher_ctr = EVP_CIPHER_fetch(libctx, base, propquery); + ctr->cipher_ecb = EVP_CIPHER_fetch(libctx, ecb, propquery); OPENSSL_free(ecb); if (ctr->cipher_ctr == NULL || ctr->cipher_ecb == NULL) { ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_FIND_CIPHERS); - ossl_provider_free(prov); return 0; } cipher_init = 1; } - ossl_provider_free(prov); if (cipher_init && !drbg_ctr_init(ctx)) return 0; diff --git a/deps/openssl/openssl/providers/implementations/rands/drbg_hash.c b/deps/openssl/openssl/providers/implementations/rands/drbg_hash.c index 92eb443c6e82..504af87d5e13 100644 --- a/deps/openssl/openssl/providers/implementations/rands/drbg_hash.c +++ b/deps/openssl/openssl/providers/implementations/rands/drbg_hash.c @@ -1,5 +1,5 @@ /* - * Copyright 2011-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2011-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -508,23 +508,22 @@ static const OSSL_PARAM *drbg_hash_gettable_ctx_params(ossl_unused void *vctx, static int drbg_fetch_digest_from_prov(const OSSL_PARAM params[], OSSL_LIB_CTX *libctx, - EVP_MD **digest) + EVP_MD **digest, + const char *propq) { - OSSL_PROVIDER *prov = NULL; const OSSL_PARAM *p; EVP_MD *md = NULL; int ret = 0; + const char *propquery = NULL; - if (digest == NULL) - return 0; +#ifndef FIPS_MODULE + if (propq == NULL) + propquery = "provider=default"; + else + propquery = propq; +#endif - if ((p = OSSL_PARAM_locate_const(params, - OSSL_PROV_PARAM_CORE_PROV_NAME)) - == NULL) - return 0; - if (p->data_type != OSSL_PARAM_UTF8_STRING) - return 0; - if ((prov = ossl_provider_find(libctx, (const char *)p->data, 1)) == NULL) + if (digest == NULL) return 0; p = OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_DIGEST); @@ -536,15 +535,13 @@ static int drbg_fetch_digest_from_prov(const OSSL_PARAM params[], if (p->data_type != OSSL_PARAM_UTF8_STRING) goto done; - md = evp_digest_fetch_from_prov(prov, (const char *)p->data, NULL); + md = EVP_MD_fetch(libctx, p->data, propquery); if (md) { EVP_MD_free(*digest); *digest = md; ret = 1; } - done: - ossl_provider_free(prov); return ret; } @@ -556,15 +553,24 @@ static int drbg_hash_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[] EVP_MD *prov_md = NULL; const EVP_MD *md; int md_size; + const OSSL_PARAM *p; if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE0, params, OSSL_DRBG_PARAM_FIPS_DIGEST_CHECK)) return 0; /* try to fetch digest from provider */ + p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_PROPERTIES); (void)ERR_set_mark(); - if (!drbg_fetch_digest_from_prov(params, libctx, &prov_md)) { + if (!drbg_fetch_digest_from_prov(params, libctx, &prov_md, + (p != NULL && p->data_type == OSSL_PARAM_UTF8_STRING) ? p->data : NULL)) { (void)ERR_pop_to_mark(); + /* + * Its possible for drbg_fetch_digest_from_prov to return 0 after having set prov_md + * so we need to ensure we free it here + */ + EVP_MD_free(prov_md); + /* fall back to full implementation search */ if (!ossl_prov_digest_load_from_params(&hash->digest, params, libctx)) return 0; diff --git a/deps/openssl/openssl/providers/implementations/rands/drbg_hmac.c b/deps/openssl/openssl/providers/implementations/rands/drbg_hmac.c index d3191e55a929..87050764fe46 100644 --- a/deps/openssl/openssl/providers/implementations/rands/drbg_hmac.c +++ b/deps/openssl/openssl/providers/implementations/rands/drbg_hmac.c @@ -412,27 +412,25 @@ static const OSSL_PARAM *drbg_hmac_gettable_ctx_params(ossl_unused void *vctx, static int drbg_fetch_algs_from_prov(const OSSL_PARAM params[], OSSL_LIB_CTX *libctx, EVP_MAC_CTX **macctx, - EVP_MD **digest) + EVP_MD **digest, const char *propq) { - OSSL_PROVIDER *prov = NULL; const OSSL_PARAM *p; const char *digest_name = NULL; const char *hmac_name = NULL; EVP_MD *md = NULL; EVP_MAC *mac = NULL; - OSSL_PARAM mac_params[2], *mp = mac_params; + OSSL_PARAM mac_params[3], *mp = mac_params; int ret = 0; + const char *propquery = NULL; - if (macctx == NULL || digest == NULL) - return 0; +#ifndef FIPS_MODULE + if (propq == NULL) + propquery = "provider=default"; + else + propquery = propq; +#endif - if ((p = OSSL_PARAM_locate_const(params, - OSSL_PROV_PARAM_CORE_PROV_NAME)) - == NULL) - return 0; - if (p->data_type != OSSL_PARAM_UTF8_STRING) - return 0; - if ((prov = ossl_provider_find(libctx, (const char *)p->data, 1)) == NULL) + if (macctx == NULL || digest == NULL) return 0; p = OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_DIGEST); @@ -441,7 +439,7 @@ static int drbg_fetch_algs_from_prov(const OSSL_PARAM params[], ERR_raise(ERR_LIB_PROV, PROV_R_VALUE_ERROR); goto done; } - md = evp_digest_fetch_from_prov(prov, digest_name, NULL); + md = EVP_MD_fetch(libctx, p->data, propquery); if (md) { EVP_MD_free(*digest); *digest = md; @@ -467,12 +465,14 @@ static int drbg_fetch_algs_from_prov(const OSSL_PARAM params[], EVP_MAC_CTX_free(*macctx); *macctx = NULL; - mac = evp_mac_fetch_from_prov(prov, hmac_name, NULL); + mac = EVP_MAC_fetch(libctx, hmac_name, propquery); if (mac) { *macctx = EVP_MAC_CTX_new(mac); /* The context holds on to the MAC */ EVP_MAC_free(mac); *mp++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, (char *)digest_name, 0); + if (propquery) + *mp++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_PROPERTIES, (char *)propquery, 0); *mp = OSSL_PARAM_construct_end(); if (!EVP_MAC_CTX_set_params(*macctx, mac_params)) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MAC); @@ -484,7 +484,6 @@ static int drbg_fetch_algs_from_prov(const OSSL_PARAM params[], } done: - ossl_provider_free(prov); return ret; } @@ -496,15 +495,23 @@ static int drbg_hmac_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[] EVP_MD *prov_md = NULL; const EVP_MD *md; int md_size; + const OSSL_PARAM *p; if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE0, params, OSSL_DRBG_PARAM_FIPS_DIGEST_CHECK)) return 0; /* try to fetch mac and digest from provider */ + p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_PROPERTIES); (void)ERR_set_mark(); - if (!drbg_fetch_algs_from_prov(params, libctx, &hmac->ctx, &prov_md)) { + if (!drbg_fetch_algs_from_prov(params, libctx, &hmac->ctx, &prov_md, + (p != NULL && p->data_type == OSSL_PARAM_UTF8_STRING) ? p->data : NULL)) { (void)ERR_pop_to_mark(); + /* + * Its possible for drbg_fetch_algs_from_prov to return 0 and set prov_md here + * so we need to free prov_md to be leak free + */ + EVP_MD_free(prov_md); /* fall back to full implementation search */ if (!ossl_prov_digest_load_from_params(&hmac->digest, params, libctx)) return 0; diff --git a/deps/openssl/openssl/providers/implementations/rands/seeding/rand_unix.c b/deps/openssl/openssl/providers/implementations/rands/seeding/rand_unix.c index 80ae8173131d..0b8a9ec341d9 100644 --- a/deps/openssl/openssl/providers/implementations/rands/seeding/rand_unix.c +++ b/deps/openssl/openssl/providers/implementations/rands/seeding/rand_unix.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -394,7 +394,7 @@ static ssize_t syscall_random(void *buf, size_t buflen) return getrandom(buf, buflen, 0); #elif (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(KERN_ARND) return sysctl_random(buf, buflen); -#elif defined(__wasi__) +#elif defined(__wasi__) || defined(__EMSCRIPTEN__) if (getentropy(buf, buflen) == 0) return (ssize_t)buflen; return -1; diff --git a/deps/openssl/openssl/providers/implementations/rands/test_rng.c b/deps/openssl/openssl/providers/implementations/rands/test_rng.c index 7942537879f1..88e5fb982aed 100644 --- a/deps/openssl/openssl/providers/implementations/rands/test_rng.c +++ b/deps/openssl/openssl/providers/implementations/rands/test_rng.c @@ -1,5 +1,5 @@ /* - * Copyright 2020-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2020-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include "prov/securitycheck.h" #include "prov/providercommon.h" #include "prov/provider_ctx.h" @@ -305,7 +305,7 @@ static int test_rng_enable_locking(void *vtest) if (t != NULL && t->lock == NULL) { t->lock = CRYPTO_THREAD_lock_new(); if (t->lock == NULL) { - ERR_raise(ERR_LIB_PROV, RAND_R_FAILED_TO_CREATE_LOCK); + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_CREATE_LOCK); return 0; } } diff --git a/deps/openssl/openssl/providers/implementations/signature/rsa_sig.c b/deps/openssl/openssl/providers/implementations/signature/rsa_sig.c index 28f3e15b5985..4980474ac03d 100644 --- a/deps/openssl/openssl/providers/implementations/signature/rsa_sig.c +++ b/deps/openssl/openssl/providers/implementations/signature/rsa_sig.c @@ -591,7 +591,7 @@ rsa_signverify_init(PROV_RSA_CTX *prsactx, void *vrsa, break; default: - ERR_raise(ERR_LIB_RSA, PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + ERR_raise(ERR_LIB_PROV, PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return 0; } @@ -1015,7 +1015,13 @@ static int rsa_verify_recover(void *vprsactx, } ret = RSA_public_decrypt((int)siglen, sig, rout, prsactx->rsa, prsactx->pad_mode); - if (ret <= 0) { + /* + * RSA_public_decrypt() returns -1 on error and otherwise the number + * of recovered bytes, which may legitimately be zero for a raw + * PKCS#1 v1.5 signature that encodes an empty payload. Treat only + * a negative result as an error. + */ + if (ret < 0) { ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB); return 0; } @@ -1947,7 +1953,7 @@ static int rsa_sigalg_signverify_init(void *vprsactx, void *vrsa, /* PSS is currently not supported as a sigalg */ if (prsactx->pad_mode == RSA_PKCS1_PSS_PADDING) { - ERR_raise(ERR_LIB_RSA, PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + ERR_raise(ERR_LIB_PROV, PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return 0; } diff --git a/deps/openssl/openssl/providers/implementations/signature/slh_dsa_sig.c b/deps/openssl/openssl/providers/implementations/signature/slh_dsa_sig.c index c6d4e04c1b84..6d43be32f4d2 100644 --- a/deps/openssl/openssl/providers/implementations/signature/slh_dsa_sig.c +++ b/deps/openssl/openssl/providers/implementations/signature/slh_dsa_sig.c @@ -61,7 +61,7 @@ static void slh_dsa_freectx(void *vctx) ossl_slh_dsa_hash_ctx_free(ctx->hash_ctx); OPENSSL_free(ctx->propq); - OPENSSL_cleanse(ctx->add_random, ctx->add_random_len); + OPENSSL_cleanse(ctx->add_random, sizeof(ctx->add_random)); OPENSSL_free(ctx); } diff --git a/deps/openssl/openssl/providers/implementations/storemgmt/file_store_any2obj.c b/deps/openssl/openssl/providers/implementations/storemgmt/file_store_any2obj.c index f5553b97da37..03560ab4902d 100644 --- a/deps/openssl/openssl/providers/implementations/storemgmt/file_store_any2obj.c +++ b/deps/openssl/openssl/providers/implementations/storemgmt/file_store_any2obj.c @@ -1,5 +1,5 @@ /* - * Copyright 2020-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2020-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -191,6 +191,10 @@ static int msblob2obj_decode(void *vctx, OSSL_CORE_BIO *cin, int selection, ok = 0; mem_want = ossl_blob_length(bitlen, isdss, ispub); + + if (mem_want > BLOB_MAX_LENGTH) { + goto next; + } if (!BUF_MEM_grow(mem, mem_len + mem_want)) { ERR_raise(ERR_LIB_PEM, ERR_R_BUF_LIB); goto err; diff --git a/deps/openssl/openssl/ssl/quic/quic_ackm.c b/deps/openssl/openssl/ssl/quic/quic_ackm.c index 58318a123a85..5da8af882ade 100644 --- a/deps/openssl/openssl/ssl/quic/quic_ackm.c +++ b/deps/openssl/openssl/ssl/quic/quic_ackm.c @@ -1003,6 +1003,7 @@ static void ackm_on_pkts_acked(OSSL_ACKM *ackm, const OSSL_ACKM_TX_PKT *apkt) const OSSL_ACKM_TX_PKT *anext; QUIC_PN last_pn_acked = 0; OSSL_CC_ACK_INFO ainfo = { 0 }; + unsigned int is_inflight; for (; apkt != NULL; apkt = anext) { if (apkt->is_inflight) { @@ -1027,10 +1028,11 @@ static void ackm_on_pkts_acked(OSSL_ACKM *ackm, const OSSL_ACKM_TX_PKT *apkt) ainfo.tx_time = apkt->time; ainfo.tx_size = apkt->num_bytes; + is_inflight = apkt->is_inflight; anext = apkt->anext; apkt->on_acked(apkt->cb_arg); /* may free apkt */ - if (apkt->is_inflight) + if (is_inflight) ackm->cc_method->on_data_acked(ackm->cc_data, &ainfo); } } @@ -1133,6 +1135,38 @@ int ossl_ackm_on_tx_packet(OSSL_ACKM *ackm, OSSL_ACKM_TX_PKT *pkt) return 1; } +int ossl_ackm_on_tx_ack_only_packet(OSSL_ACKM *ackm, OSSL_ACKM_TX_PKT *pkt) +{ + struct tx_pkt_history_st *h; + unsigned int pkt_space; + + if (pkt == NULL || pkt->pkt_space >= QUIC_PN_SPACE_NUM) + return 0; + + /* + * A packet containing only an ACK frame must not be treated as + * in-flight or ack-eliciting; if it were, ossl_ackm_on_tx_packet() + * below would (correctly) perform bytes-in-flight/timer/CC bookkeeping + * for a packet we are about to discard from history, which would be + * incorrect. + */ + if (pkt->is_inflight || pkt->is_ack_eliciting) + return 0; + + pkt_space = pkt->pkt_space; + + /* + * No one can expect ACK for packet which carries ACK frames only + * (ack_only packet). The ACKM does not need to keep record for ack_only + * packet. For ack_only packet the ACKM manager must be updated by the + * highest packet number which got sent. + */ + h = get_tx_history(ackm, pkt_space); + h->highest_sent = pkt->pkt_num; + + return 1; +} + int ossl_ackm_on_rx_datagram(OSSL_ACKM *ackm, size_t num_bytes) { /* No-op on the client. */ @@ -1167,8 +1201,21 @@ int ossl_ackm_on_rx_ack_frame(OSSL_ACKM *ackm, const OSSL_QUIC_FRAME_ACK *ack, int pkt_space, OSSL_TIME rx_time) { OSSL_ACKM_TX_PKT *na_pkts, *lost_pkts; + struct tx_pkt_history_st *h = get_tx_history(ackm, pkt_space); int must_set_timer = 0; + /* + * RFC 9000 s. 13.1 recommends treating an acknowledgment for a packet we + * did not send as a PROTOCOL_VIOLATION, where detectable. The largest + * acknowledged PN is ack_ranges[0].end; if it exceeds the highest PN we have + * sent in this space, reject the ACK. Otherwise the peer-controlled value is + * stored into largest_acked_pkt below, which only ever increases and drives + * loss detection, so a single such ACK would permanently force every + * in-flight and subsequently-sent packet to be declared lost. + */ + if (ack->ack_ranges[0].end > h->highest_sent) + return 0; + if (ackm->largest_acked_pkt[pkt_space] == QUIC_PN_INVALID) ackm->largest_acked_pkt[pkt_space] = ack->ack_ranges[0].end; else diff --git a/deps/openssl/openssl/ssl/quic/quic_impl.c b/deps/openssl/openssl/ssl/quic/quic_impl.c index 97efa4908a49..13bb007fa49b 100644 --- a/deps/openssl/openssl/ssl/quic/quic_impl.c +++ b/deps/openssl/openssl/ssl/quic/quic_impl.c @@ -410,6 +410,11 @@ static int expect_quic_cs(const SSL *s, QCTX *ctx) return expect_quic_as(s, ctx, QCTX_C | QCTX_S); } +static int expect_quic_cl(const SSL *s, QCTX *ctx) +{ + return expect_quic_as(s, ctx, QCTX_C | QCTX_L); +} + static int expect_quic_csl(const SSL *s, QCTX *ctx) { return expect_quic_as(s, ctx, QCTX_C | QCTX_S | QCTX_L); @@ -3643,6 +3648,33 @@ static int qc_getset_idle_timeout(QCTX *ctx, uint32_t class_, return ret; } +QUIC_TAKES_LOCK +static int qc_getset_max_pending_channels(QCTX *ctx, uint32_t class_, + uint64_t *p_value_out, uint64_t *p_value_in) +{ + int ret = 0; + uint64_t value_out = 0; + + qctx_lock(ctx); + + if (class_ == SSL_VALUE_CLASS_GENERIC && ctx->is_listener) { + value_out = ossl_quic_port_get_max_pending_channels(ctx->ql->port); + if (p_value_in != NULL) + ossl_quic_port_set_max_pending_channels(ctx->ql->port, *p_value_in); + ret = 1; + } else { + QUIC_RAISE_NON_NORMAL_ERROR(ctx, SSL_R_UNSUPPORTED_CONFIG_VALUE_CLASS, NULL); + ret = 0; + } + + qctx_unlock(ctx); + + if (ret && p_value_out != NULL) + *p_value_out = value_out; + + return ret; +} + QUIC_TAKES_LOCK static int qc_get_stream_avail(QCTX *ctx, uint32_t class_, int is_uni, int is_remote, @@ -3778,6 +3810,8 @@ static int expect_quic_for_value(SSL *s, QCTX *ctx, uint32_t id) case SSL_VALUE_STREAM_WRITE_BUF_USED: case SSL_VALUE_STREAM_WRITE_BUF_AVAIL: return expect_quic_cs(s, ctx); + case SSL_VALUE_QUIC_MAX_PENDING_CONNS: + return expect_quic_cl(s, ctx); default: return expect_quic_conn_only(s, ctx); } @@ -3799,6 +3833,8 @@ int ossl_quic_get_value_uint(SSL *s, uint32_t class_, uint32_t id, switch (id) { case SSL_VALUE_QUIC_IDLE_TIMEOUT: return qc_getset_idle_timeout(&ctx, class_, value, NULL); + case SSL_VALUE_QUIC_MAX_PENDING_CONNS: + return qc_getset_max_pending_channels(&ctx, class_, value, NULL); case SSL_VALUE_QUIC_STREAM_BIDI_LOCAL_AVAIL: return qc_get_stream_avail(&ctx, class_, /*uni=*/0, /*remote=*/0, value); @@ -3845,6 +3881,8 @@ int ossl_quic_set_value_uint(SSL *s, uint32_t class_, uint32_t id, case SSL_VALUE_EVENT_HANDLING_MODE: return qc_getset_event_handling(&ctx, class_, NULL, &value); + case SSL_VALUE_QUIC_MAX_PENDING_CONNS: + return qc_getset_max_pending_channels(&ctx, class_, NULL, &value); default: return QUIC_RAISE_NON_NORMAL_ERROR(&ctx, @@ -4915,6 +4953,11 @@ int ossl_quic_set_peer_token(SSL_CTX *ctx, BIO_ADDR *peer, ossl_quic_free_peer_token(old); } lh_QUIC_TOKEN_insert(c->cache, tok); + if (lh_QUIC_TOKEN_error(c->cache)) { + ossl_quic_free_peer_token(tok); + ossl_crypto_mutex_unlock(c->mutex); + return 0; + } ossl_crypto_mutex_unlock(c->mutex); return 1; @@ -5406,6 +5449,19 @@ QUIC_CHANNEL *ossl_quic_conn_get_channel(SSL *s) return ctx.qc->ch; } +QUIC_PORT *ossl_quic_listener_get_port(SSL *s) +{ + QCTX ctx; + + /* + * expect listerner only + */ + if (!expect_quic_listener(s, &ctx)) + return NULL; + + return ctx.ql->port; +} + int ossl_quic_set_diag_title(SSL_CTX *ctx, const char *title) { #ifndef OPENSSL_NO_QLOG diff --git a/deps/openssl/openssl/ssl/quic/quic_port.c b/deps/openssl/openssl/ssl/quic/quic_port.c index 200022ac2c56..aad9c3a5b3d5 100644 --- a/deps/openssl/openssl/ssl/quic/quic_port.c +++ b/deps/openssl/openssl/ssl/quic/quic_port.c @@ -93,6 +93,8 @@ typedef struct validation_token { */ #define ENCRYPTED_TOKEN_MAX_LEN (MARSHALLED_TOKEN_MAX_LEN + 16 + 12) +#define DEFAULT_MAX_PENDING_CONNS 256 + DEFINE_LIST_OF_IMPL(ch, QUIC_CHANNEL); DEFINE_LIST_OF_IMPL(incoming_ch, QUIC_CHANNEL); DEFINE_LIST_OF_IMPL(port, QUIC_PORT); @@ -110,6 +112,7 @@ QUIC_PORT *ossl_quic_port_new(const QUIC_PORT_ARGS *args) port->validate_addr = args->do_addr_validation; port->get_conn_user_ssl = args->get_conn_user_ssl; port->user_ssl_arg = args->user_ssl_arg; + port->max_pending_channels = DEFAULT_MAX_PENDING_CONNS; if (!port_init(port)) { OPENSSL_free(port); @@ -531,8 +534,10 @@ static QUIC_CHANNEL *port_make_channel(QUIC_PORT *port, SSL *tls, OSSL_QRX *qrx, * start by allocation and provisioning as much of the channel as we can */ ch = ossl_quic_channel_alloc(&args); - if (ch == NULL) + if (ch == NULL) { + ossl_qrx_free(qrx); return NULL; + } /* * Fixup the channel tls connection here before we init the channel @@ -1488,7 +1493,7 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg, QUIC_CHANNEL *ch = NULL, *new_ch = NULL; QUIC_CONN_ID odcid; uint8_t gen_new_token = 0; - OSSL_QRX *qrx = NULL; + OSSL_QRX *qrx = NULL, *qrx_ref; OSSL_QRX *qrx_src = NULL; OSSL_QRX_ARGS qrx_args = { 0 }; uint64_t cause_flags = 0; @@ -1581,6 +1586,9 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg, if (hdr.type != QUIC_PKT_TYPE_INITIAL) goto undesirable; + if (port->max_pending_channels > 0 && ossl_list_incoming_ch_num(&port->incoming_channel_list) >= port->max_pending_channels) + goto undesirable; + odcid.id_len = 0; /* @@ -1678,8 +1686,22 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg, } } + qrx_ref = NULL; + if (qrx != NULL) { + /* + * if we are here, then client is validated via retry packet + * (client sent a valid token). In this case the qrx has valid + * secrets set for QUIC initial level encryption. We can pass + * reference to qrx to newly created channel. + * + * Note: port_bind_channel()/channel becomes owner of qrx_ref. + */ + qrx_ref = ossl_qrx_newref(qrx); + if (qrx_ref == NULL) + goto undesirable; + } port_bind_channel(port, &e->peer, &hdr.dst_conn_id, - &odcid, qrx, &new_ch); + &odcid, qrx_ref, &new_ch); /* * if packet validates it gets moved to channel, we've just bound @@ -1694,19 +1716,19 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg, if (gen_new_token == 1) generate_new_token(new_ch, &e->peer); - if (qrx != NULL) { + if (qrx_src != NULL) { /* - * The qrx belongs to channel now, so don't free it. - */ - qrx = NULL; - } else { - /* - * We still need to salvage packets from almost forgotten qrx - * and pass them to channel. + * Time to reinject packets from qrx to channel before + * qrx will be destroyed here. */ while (ossl_qrx_read_pkt(qrx_src, &qrx_pkt) == 1) ossl_quic_channel_inject_pkt(new_ch, qrx_pkt); ossl_qrx_update_pn_space(qrx_src, new_ch->qrx); + /* + * transfer ownership back to qrx; + */ + qrx = qrx_src; + qrx_src = NULL; } /* @@ -1723,7 +1745,7 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg, */ undesirable: - ossl_qrx_free(qrx); + ossl_qrx_free(qrx); /* releases reference */ ossl_qrx_free(qrx_src); ossl_quic_demux_release_urxe(port->demux, e); } @@ -1760,3 +1782,13 @@ void ossl_quic_port_restore_err_state(const QUIC_PORT *port) ERR_clear_error(); OSSL_ERR_STATE_restore(port->err_state); } + +uint64_t ossl_quic_port_get_max_pending_channels(const QUIC_PORT *port) +{ + return port->max_pending_channels; +} + +void ossl_quic_port_set_max_pending_channels(QUIC_PORT *port, uint64_t max_pending_channels) +{ + port->max_pending_channels = max_pending_channels; +} diff --git a/deps/openssl/openssl/ssl/quic/quic_port_local.h b/deps/openssl/openssl/ssl/quic/quic_port_local.h index 3bad3fc3a3aa..0cfc75da0ba1 100644 --- a/deps/openssl/openssl/ssl/quic/quic_port_local.h +++ b/deps/openssl/openssl/ssl/quic/quic_port_local.h @@ -1,5 +1,5 @@ /* - * Copyright 2023-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2023-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -118,6 +118,7 @@ struct quic_port_st { /* AES-256 GCM context for token encryption */ EVP_CIPHER_CTX *token_ctx; + uint64_t max_pending_channels; }; #endif diff --git a/deps/openssl/openssl/ssl/quic/quic_record_rx.c b/deps/openssl/openssl/ssl/quic/quic_record_rx.c index 8897cc6c2df0..0065f1c1e573 100644 --- a/deps/openssl/openssl/ssl/quic/quic_record_rx.c +++ b/deps/openssl/openssl/ssl/quic/quic_record_rx.c @@ -171,6 +171,8 @@ struct ossl_qrx_st { ossl_msg_cb msg_callback; void *msg_callback_arg; SSL *msg_callback_ssl; + + uint32_t refcount; }; static RXE *qrx_ensure_free_rxe(OSSL_QRX *qrx, size_t alloc_len); @@ -212,6 +214,7 @@ OSSL_QRX *ossl_qrx_new(const OSSL_QRX_ARGS *args) qrx->short_conn_id_len = args->short_conn_id_len; qrx->init_key_phase_bit = args->init_key_phase_bit; qrx->max_deferred = args->max_deferred; + qrx->refcount = 1; return qrx; } @@ -247,13 +250,10 @@ void ossl_qrx_update_pn_space(OSSL_QRX *src, OSSL_QRX *dst) return; } -void ossl_qrx_free(OSSL_QRX *qrx) +static void qrx_destroy(OSSL_QRX *qrx) { uint32_t i; - if (qrx == NULL) - return; - /* Free RXE queue data. */ qrx_cleanup_rxl(&qrx->rx_free); qrx_cleanup_rxl(&qrx->rx_pending); @@ -267,6 +267,30 @@ void ossl_qrx_free(OSSL_QRX *qrx) OPENSSL_free(qrx); } +void ossl_qrx_free(OSSL_QRX *qrx) +{ + if (qrx == NULL) + return; + + qrx->refcount--; + if (qrx->refcount == 0) + qrx_destroy(qrx); +} + +OSSL_QRX *ossl_qrx_newref(OSSL_QRX *qrx) +{ + OSSL_QRX *rv_qrx; + + if (qrx != NULL && qrx->refcount != (uint32_t)~0) { + qrx->refcount++; + rv_qrx = qrx; + } else { + rv_qrx = NULL; + } + + return rv_qrx; +} + void ossl_qrx_inject_urxe(OSSL_QRX *qrx, QUIC_URXE *urxe) { /* Initialize our own fields inside the URXE and add to the pending list. */ diff --git a/deps/openssl/openssl/ssl/quic/quic_rx_depack.c b/deps/openssl/openssl/ssl/quic/quic_rx_depack.c index 7ab59f01a1cd..59d16b2f362c 100644 --- a/deps/openssl/openssl/ssl/quic/quic_rx_depack.c +++ b/deps/openssl/openssl/ssl/quic/quic_rx_depack.c @@ -125,8 +125,19 @@ static int depack_do_frame_ack(PACKET *pkt, QUIC_CHANNEL *ch, } if (!ossl_ackm_on_rx_ack_frame(ch->ackm, &ack, - packet_space, received)) - goto malformed; + packet_space, received)) { + /* + * The ACK manager rejects the frame if it acknowledges a packet number + * we have not sent. RFC 9000 s. 13.1 recommends treating this as a + * PROTOCOL_VIOLATION connection error (distinct from a frame decoding + * error, which is handled at the malformed label below). + */ + ossl_quic_channel_raise_protocol_error(ch, + OSSL_QUIC_ERR_PROTOCOL_VIOLATION, + frame_type, + "ACK for unsent packet number"); + return 0; + } ++ch->diag_num_rx_ack; return 1; diff --git a/deps/openssl/openssl/ssl/quic/quic_stream_map.c b/deps/openssl/openssl/ssl/quic/quic_stream_map.c index 84ac6b714e38..da53d4b8054f 100644 --- a/deps/openssl/openssl/ssl/quic/quic_stream_map.c +++ b/deps/openssl/openssl/ssl/quic/quic_stream_map.c @@ -168,6 +168,10 @@ QUIC_STREAM *ossl_quic_stream_map_alloc(QUIC_STREAM_MAP *qsm, s->send_final_size = UINT64_MAX; lh_QUIC_STREAM_insert(qsm->map, s); + if (lh_QUIC_STREAM_error(qsm->map)) { + OPENSSL_free(s); + return NULL; + } return s; } diff --git a/deps/openssl/openssl/ssl/quic/quic_txp.c b/deps/openssl/openssl/ssl/quic/quic_txp.c index 5ce8e77f61e0..24314f6b34b7 100644 --- a/deps/openssl/openssl/ssl/quic/quic_txp.c +++ b/deps/openssl/openssl/ssl/quic/quic_txp.c @@ -2935,6 +2935,20 @@ static int txp_generate_for_el(OSSL_QUIC_TX_PACKETISER *txp, return TXP_ERR_INTERNAL; } +static int txp_pkt_is_ack_only(const QUIC_TXPIM_PKT *tpkt) +{ + return tpkt->had_ack_frame + && !tpkt->ackm_pkt.is_inflight + && !tpkt->ackm_pkt.is_ack_eliciting + && !tpkt->had_handshake_done_frame + && !tpkt->had_max_data_frame + && !tpkt->had_max_streams_bidi_frame + && !tpkt->had_max_streams_uni_frame + && !tpkt->had_conn_close + && tpkt->retx_head == NULL + && ossl_quic_txpim_pkt_get_num_chunks(tpkt) == 0; +} + /* * Commits and queues a packet for transmission. There is no backing out after * this. @@ -2943,8 +2957,9 @@ static int txp_generate_for_el(OSSL_QUIC_TX_PACKETISER *txp, * * - Sends the packet to the QTX for encryption and transmission; * - * - Records the packet as having been transmitted in FIFM. ACKM is informed, - * etc. and the TXPIM record is filed. + * - Records non-ACK-only packets as having been transmitted in FIFM. ACKM is + * informed, etc. and the TXPIM record is filed only when later callbacks + * need it. * * - Informs various subsystems of frames that were sent and clears frame * wanted flags so that we do not generate the same frames again. @@ -2971,7 +2986,7 @@ static int txp_pkt_commit(OSSL_QUIC_TX_PACKETISER *txp, uint32_t archetype, int *txpim_pkt_reffed) { - int rc = 1; + int ack_only, rc = 1; uint32_t enc_level = pkt->h.enc_level; uint32_t pn_space = ossl_quic_enc_level_to_pn_space(enc_level); QUIC_TXPIM_PKT *tpkt = pkt->tpkt; @@ -3015,28 +3030,35 @@ static int txp_pkt_commit(OSSL_QUIC_TX_PACKETISER *txp, return 0; /* alloc error */ } - /* Dispatch to FIFD. */ - if (!ossl_quic_fifd_pkt_commit(&txp->fifd, tpkt)) + ack_only = txp_pkt_is_ack_only(tpkt); + + /* Dispatch packets that need loss/retransmit callbacks to FIFD. */ + if (!ack_only && !ossl_quic_fifd_pkt_commit(&txp->fifd, tpkt)) return 0; /* * Transmission and Post-Packet Generation Bookkeeping * =================================================== * - * No backing out anymore - at this point the ACKM has recorded the packet - * as having been sent, so we need to increment our next PN counter, or - * the ACKM will complain when we try to record a duplicate packet with - * the same PN later. At this point actually sending the packet may still - * fail. In this unlikely event it will simply be handled as though it - * were a lost packet. + * No backing out anymore - at this point we need to increment our next PN + * counter, or the ACKM will complain when we try to record a duplicate + * packet with the same PN later. Non-ACK-only packets have also been + * recorded in ACKM, so if QTX write fails they are handled as though they + * were lost. ACK-only packets are not recorded and will be cleaned up by + * the caller. */ ++txp->next_pn[pn_space]; - *txpim_pkt_reffed = 1; + if (!ack_only) + *txpim_pkt_reffed = 1; /* Send the packet. */ if (!ossl_qtx_write_pkt(txp->args.qtx, &txpkt)) return 0; + if (ack_only + && !ossl_ackm_on_tx_ack_only_packet(txp->args.ackm, &tpkt->ackm_pkt)) + rc = 0; + /* * Record FC and stream abort frames as sent; deactivate streams which no * longer have anything to do. diff --git a/deps/openssl/openssl/ssl/record/methods/dtls_meth.c b/deps/openssl/openssl/ssl/record/methods/dtls_meth.c index 8cbd7678e193..c282efc5ca07 100644 --- a/deps/openssl/openssl/ssl/record/methods/dtls_meth.c +++ b/deps/openssl/openssl/ssl/record/methods/dtls_meth.c @@ -1,5 +1,5 @@ /* - * Copyright 2018-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2018-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -287,7 +287,7 @@ static int dtls_rlayer_buffer_record(OSSL_RECORD_LAYER *rl, struct pqueue_st *qu pitem *item; /* Limit the size of the queue to prevent DOS attacks */ - if (pqueue_size(queue) >= 100) + if (pqueue_size(queue) >= 16) return 0; rdata = OPENSSL_malloc(sizeof(*rdata)); @@ -299,29 +299,26 @@ static int dtls_rlayer_buffer_record(OSSL_RECORD_LAYER *rl, struct pqueue_st *qu return -1; } - rdata->packet = rl->packet; + /* + * Take a copy of just this record's on-wire bytes (header + ciphertext) + * rather than the whole (much larger) read buffer. The live rl->rbuf is + * left untouched and continues to be used for subsequent reads. + */ rdata->packet_length = rl->packet_length; - memcpy(&(rdata->rbuf), &rl->rbuf, sizeof(TLS_BUFFER)); - memcpy(&(rdata->rrec), &rl->rrec[0], sizeof(TLS_RL_RECORD)); - - item->data = rdata; - - rl->packet = NULL; - rl->packet_length = 0; - memset(&rl->rbuf, 0, sizeof(TLS_BUFFER)); - memset(&rl->rrec[0], 0, sizeof(rl->rrec[0])); - - if (!tls_setup_read_buffer(rl)) { - /* RLAYERfatal() already called */ - OPENSSL_free(rdata->rbuf.buf); + rdata->packet = OPENSSL_memdup(rl->packet, rl->packet_length); + if (rdata->packet == NULL) { OPENSSL_free(rdata); pitem_free(item); + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_CRYPTO_LIB); return -1; } + memcpy(&(rdata->rrec), &rl->rrec[0], sizeof(TLS_RL_RECORD)); + + item->data = rdata; if (pqueue_insert(queue, item) == NULL) { /* Must be a duplicate so ignore it */ - OPENSSL_free(rdata->rbuf.buf); + OPENSSL_free(rdata->packet); OPENSSL_free(rdata); pitem_free(item); } @@ -329,44 +326,6 @@ static int dtls_rlayer_buffer_record(OSSL_RECORD_LAYER *rl, struct pqueue_st *qu return 1; } -/* copy buffered record into OSSL_RECORD_LAYER structure */ -static int dtls_copy_rlayer_record(OSSL_RECORD_LAYER *rl, pitem *item) -{ - DTLS_RLAYER_RECORD_DATA *rdata; - - rdata = (DTLS_RLAYER_RECORD_DATA *)item->data; - - ossl_tls_buffer_release(&rl->rbuf); - - rl->packet = rdata->packet; - rl->packet_length = rdata->packet_length; - memcpy(&rl->rbuf, &(rdata->rbuf), sizeof(TLS_BUFFER)); - memcpy(&rl->rrec[0], &(rdata->rrec), sizeof(TLS_RL_RECORD)); - - /* Set proper sequence number for mac calculation */ - memcpy(&(rl->sequence[2]), &(rdata->packet[5]), 6); - - return 1; -} - -static int dtls_retrieve_rlayer_buffered_record(OSSL_RECORD_LAYER *rl, - struct pqueue_st *queue) -{ - pitem *item; - - item = pqueue_pop(queue); - if (item) { - dtls_copy_rlayer_record(rl, item); - - OPENSSL_free(item->data); - pitem_free(item); - - return 1; - } - - return 0; -} - /*- * Call this to get a new input record. * It will return <= 0 if more data is needed, normally due to an error @@ -400,12 +359,6 @@ int dtls_get_more_records(OSSL_RECORD_LAYER *rl) } again: - /* if we're renegotiating, then there may be buffered records */ - if (dtls_retrieve_rlayer_buffered_record(rl, rl->processed_rcds)) { - rl->num_recs = 1; - return OSSL_RECORD_RETURN_SUCCESS; - } - /* get something from the wire */ /* check if we have the header */ @@ -607,23 +560,13 @@ static int dtls_free(OSSL_RECORD_LAYER *rl) /* Push to the next record layer */ ret &= BIO_write_ex(rl->next, rdata->packet, rdata->packet_length, &written); - OPENSSL_free(rdata->rbuf.buf); + OPENSSL_free(rdata->packet); OPENSSL_free(item->data); pitem_free(item); } pqueue_free(rl->unprocessed_rcds); } - if (rl->processed_rcds != NULL) { - while ((item = pqueue_pop(rl->processed_rcds)) != NULL) { - rdata = (DTLS_RLAYER_RECORD_DATA *)item->data; - OPENSSL_free(rdata->rbuf.buf); - OPENSSL_free(item->data); - pitem_free(item); - } - pqueue_free(rl->processed_rcds); - } - return tls_free(rl) && ret; } @@ -653,10 +596,8 @@ dtls_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers, return ret; (*retrl)->unprocessed_rcds = pqueue_new(); - (*retrl)->processed_rcds = pqueue_new(); - if ((*retrl)->unprocessed_rcds == NULL - || (*retrl)->processed_rcds == NULL) { + if ((*retrl)->unprocessed_rcds == NULL) { dtls_free(*retrl); *retrl = NULL; ERR_raise(ERR_LIB_SSL, ERR_R_SSL_LIB); diff --git a/deps/openssl/openssl/ssl/record/methods/recmethod_local.h b/deps/openssl/openssl/ssl/record/methods/recmethod_local.h index 4ffce8d66385..5e3fdd1d0587 100644 --- a/deps/openssl/openssl/ssl/record/methods/recmethod_local.h +++ b/deps/openssl/openssl/ssl/record/methods/recmethod_local.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -344,9 +344,8 @@ struct ossl_record_layer_st { size_t taglen; - /* DTLS received handshake records (processed and unprocessed) */ + /* DTLS received handshake records awaiting the next epoch */ struct pqueue_st *unprocessed_rcds; - struct pqueue_st *processed_rcds; /* records being received in the current epoch */ DTLS_BITMAP bitmap; @@ -374,7 +373,6 @@ struct ossl_record_layer_st { typedef struct dtls_rlayer_record_data_st { unsigned char *packet; size_t packet_length; - TLS_BUFFER rbuf; TLS_RL_RECORD rrec; } DTLS_RLAYER_RECORD_DATA; diff --git a/deps/openssl/openssl/ssl/record/methods/tls_common.c b/deps/openssl/openssl/ssl/record/methods/tls_common.c index 9f957b7cc656..e00ad084cbd9 100644 --- a/deps/openssl/openssl/ssl/record/methods/tls_common.c +++ b/deps/openssl/openssl/ssl/record/methods/tls_common.c @@ -497,7 +497,7 @@ static int tls_record_app_data_waiting(OSSL_RECORD_LAYER *rl) static int rlayer_early_data_count_ok(OSSL_RECORD_LAYER *rl, size_t length, size_t overhead, int send) { - uint32_t max_early_data = rl->max_early_data; + uint64_t max_early_data = rl->max_early_data; if (max_early_data == 0) { RLAYERfatal(rl, send ? SSL_AD_INTERNAL_ERROR : SSL_AD_UNEXPECTED_MESSAGE, @@ -1919,13 +1919,14 @@ int tls_retry_write_records(OSSL_RECORD_LAYER *rl) { int i, ret; TLS_BUFFER *thiswb; - size_t tmpwrit = 0; + size_t tmpwrit = 0, left; if (rl->nextwbuf >= rl->numwpipes) return OSSL_RECORD_RETURN_SUCCESS; for (;;) { thiswb = &rl->wbuf[rl->nextwbuf]; + left = TLS_BUFFER_get_left(thiswb); clear_sys_error(); if (rl->bio != NULL) { @@ -1935,13 +1936,24 @@ int tls_retry_write_records(OSSL_RECORD_LAYER *rl) return ret; } i = BIO_write(rl->bio, (char *)&(TLS_BUFFER_get_buf(thiswb)[TLS_BUFFER_get_offset(thiswb)]), - (unsigned int)TLS_BUFFER_get_left(thiswb)); + (unsigned int)left); if (i >= 0) { tmpwrit = i; - if (i == 0 && BIO_should_retry(rl->bio)) - ret = OSSL_RECORD_RETURN_RETRY; - else + if (i == 0 && left != 0) { + if (BIO_should_retry(rl->bio)) { + ret = OSSL_RECORD_RETURN_RETRY; + } else { + /* + * Treat this as a fatal I/O condition. Do not queue an + * SSL reason: a zero return with no retry flag may come + * from a custom BIO and does not imply an SSL library + * or protocol error. + */ + ret = OSSL_RECORD_RETURN_FATAL; + } + } else { ret = OSSL_RECORD_RETURN_SUCCESS; + } } else { if (BIO_should_retry(rl->bio)) { ret = OSSL_RECORD_RETURN_RETRY; @@ -1964,7 +1976,7 @@ int tls_retry_write_records(OSSL_RECORD_LAYER *rl) * Treat i == 0 as success rather than an error for zero byte * writes to permit this case. */ - if (i >= 0 && tmpwrit == TLS_BUFFER_get_left(thiswb)) { + if (i >= 0 && tmpwrit == left) { TLS_BUFFER_set_left(thiswb, 0); TLS_BUFFER_add_offset(thiswb, tmpwrit); if (++(rl->nextwbuf) < rl->numwpipes) @@ -1982,9 +1994,9 @@ int tls_retry_write_records(OSSL_RECORD_LAYER *rl) */ if (TLS_BUFFER_is_app_buffer(thiswb) && (rl->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER) != 0) { - size_t left = TLS_BUFFER_get_left(thiswb); unsigned char *buf; + left = TLS_BUFFER_get_left(thiswb); buf = OPENSSL_malloc(left); if (buf == NULL) { RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); diff --git a/deps/openssl/openssl/ssl/record/rec_layer_s3.c b/deps/openssl/openssl/ssl/record/rec_layer_s3.c index ba407478b412..3ab50facc93e 100644 --- a/deps/openssl/openssl/ssl/record/rec_layer_s3.c +++ b/deps/openssl/openssl/ssl/record/rec_layer_s3.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -150,7 +150,7 @@ static uint32_t ossl_get_max_early_data(SSL_CONNECTION *s) static int ossl_early_data_count_ok(SSL_CONNECTION *s, size_t length, size_t overhead, int send) { - uint32_t max_early_data; + uint64_t max_early_data; max_early_data = ossl_get_max_early_data(s); diff --git a/deps/openssl/openssl/ssl/rio/poll_builder.c b/deps/openssl/openssl/ssl/rio/poll_builder.c index 28d93ee1947a..f808e9b01e74 100644 --- a/deps/openssl/openssl/ssl/rio/poll_builder.c +++ b/deps/openssl/openssl/ssl/rio/poll_builder.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -120,8 +120,10 @@ int ossl_rio_poll_builder_add_fd(RIO_POLL_BUILDER *rpb, int fd, assert((rpb->pfd_heap != NULL && rpb->pfd_heap == pfds) || (rpb->pfd_heap == NULL && rpb->pfds == pfds)); assert(i <= rpb->pfd_num && rpb->pfd_num <= rpb->pfd_alloc); + /* Check the index first because an appended entry is uninitialised. */ + if (i == rpb->pfd_num || pfds[i].fd == -1) + pfds[i].events = 0; pfds[i].fd = fd; - pfds[i].events = 0; if (want_read) pfds[i].events |= POLLIN; diff --git a/deps/openssl/openssl/ssl/rio/poll_builder.h b/deps/openssl/openssl/ssl/rio/poll_builder.h index 1fe13eacbaba..48605d718223 100644 --- a/deps/openssl/openssl/ssl/rio/poll_builder.h +++ b/deps/openssl/openssl/ssl/rio/poll_builder.h @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -76,4 +76,17 @@ int ossl_rio_poll_builder_poll(RIO_POLL_BUILDER *rpb, OSSL_TIME deadline); * it is currently not needed. */ +#ifndef OPENSSL_NO_QUIC +/* + * Test instrumentation only. If set, poll_translate() (see poll_immediate.c) + * calls this with the index of each item immediately before translating it, + * once all earlier items (if any) have finished translation. This lets + * tests inject a readiness change into the gap between translation of + * consecutive items, in order to deterministically exercise the + * abort-blocking path. Always NULL in production use. + */ +extern void (*ossl_quic_poll_translate_test_step_cb)(size_t idx, void *arg); +extern void *ossl_quic_poll_translate_test_step_cb_arg; +#endif + #endif diff --git a/deps/openssl/openssl/ssl/rio/poll_immediate.c b/deps/openssl/openssl/ssl/rio/poll_immediate.c index 24b82f3a6a43..95410df0d8f4 100644 --- a/deps/openssl/openssl/ssl/rio/poll_immediate.c +++ b/deps/openssl/openssl/ssl/rio/poll_immediate.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -49,6 +49,13 @@ } while (0) #ifndef OPENSSL_NO_QUIC +/* + * Test instrumentation only; see poll_builder.h. Always NULL in production + * use. + */ +void (*ossl_quic_poll_translate_test_step_cb)(size_t idx, void *arg) = NULL; +void *ossl_quic_poll_translate_test_step_cb_arg = NULL; + static int poll_translate_ssl_quic(SSL *ssl, QUIC_REACTOR_WAIT_CTX *wctx, RIO_POLL_BUILDER *rpb, @@ -216,6 +223,10 @@ static int poll_translate(SSL_POLL_ITEM *items, for (i = 0; i < num_items; ++i) { item = &ITEM_N(items, stride, i); + if (ossl_quic_poll_translate_test_step_cb != NULL) + ossl_quic_poll_translate_test_step_cb(i, + ossl_quic_poll_translate_test_step_cb_arg); + switch (item->desc.type) { case BIO_POLL_DESCRIPTOR_TYPE_SSL: ssl = item->desc.value.ssl; @@ -233,7 +244,7 @@ static int poll_translate(SSL_POLL_ITEM *items, FAIL_ITEM(i); if (*abort_blocking) - return 1; + goto out; if (!SSL_get_event_timeout(ssl, &timeout, &is_infinite)) FAIL_ITEM(i++); /* need to clean up this item too */ @@ -271,7 +282,12 @@ static int poll_translate(SSL_POLL_ITEM *items, } out: - if (!ok) + /* + * On abort_blocking, the item which triggered the abort has already + * balanced its own enter/leave of the blocking section (see + * poll_translate_ssl_quic()); only items 0..i-1 still need cleanup here. + */ + if (!ok || *abort_blocking) postpoll_translation_cleanup(items, i, stride, wctx); *p_earliest_wakeup_deadline = earliest_wakeup_deadline; @@ -320,8 +336,15 @@ static int poll_block(SSL_POLL_ITEM *items, p_result_count)) goto out; - if (abort_blocking) + if (abort_blocking) { + /* + * Nothing actually failed; we just shouldn't block because an item + * may have become ready while we were setting up. The caller's + * retry loop will call poll_readout() again to pick this up. + */ + ok = 1; goto out; + } earliest_wakeup_deadline = ossl_time_min(earliest_wakeup_deadline, user_deadline); diff --git a/deps/openssl/openssl/ssl/rio/rio_notifier.c b/deps/openssl/openssl/ssl/rio/rio_notifier.c index ea40790d627b..abc1755dae02 100644 --- a/deps/openssl/openssl/ssl/rio/rio_notifier.c +++ b/deps/openssl/openssl/ssl/rio/rio_notifier.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -10,7 +10,6 @@ #include "internal/sockets.h" #include #include -#include "internal/thread_once.h" #include "internal/rio_notifier.h" /* @@ -28,32 +27,29 @@ static int set_cloexec(int fd) #if defined(OPENSSL_SYS_WINDOWS) -static CRYPTO_ONCE ensure_wsa_startup_once = CRYPTO_ONCE_STATIC_INIT; -static int wsa_started; - static void ossl_wsa_cleanup(void) { - if (wsa_started) { - wsa_started = 0; - WSACleanup(); - } + WSACleanup(); } -DEFINE_RUN_ONCE_STATIC(do_wsa_startup) +static int do_wsa_startup(void) { WORD versionreq = 0x0202; /* Version 2.2 */ WSADATA wsadata; if (WSAStartup(versionreq, &wsadata) != 0) return 0; - wsa_started = 1; - OPENSSL_atexit(ossl_wsa_cleanup); return 1; } static ossl_inline int ensure_wsa_startup(void) { - return RUN_ONCE(&ensure_wsa_startup_once, do_wsa_startup); + return do_wsa_startup(); +} + +static void wsa_done(void) +{ + ossl_wsa_cleanup(); } #endif diff --git a/deps/openssl/openssl/ssl/s3_lib.c b/deps/openssl/openssl/ssl/s3_lib.c index 213ec84b171d..079a308f6ff1 100644 --- a/deps/openssl/openssl/ssl/s3_lib.c +++ b/deps/openssl/openssl/ssl/s3_lib.c @@ -5223,8 +5223,10 @@ int ssl_generate_master_secret(SSL_CONNECTION *s, unsigned char *pms, pskpmslen = 4 + pmslen + psklen; pskpms = OPENSSL_malloc(pskpmslen); - if (pskpms == NULL) + if (pskpms == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_CRYPTO_LIB); goto err; + } t = pskpms; s2n(pmslen, t); if (alg_k & SSL_kPSK) @@ -5248,6 +5250,7 @@ int ssl_generate_master_secret(SSL_CONNECTION *s, unsigned char *pms, OPENSSL_clear_free(pskpms, pskpmslen); #else /* Should never happen */ + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); goto err; #endif } else { diff --git a/deps/openssl/openssl/ssl/ssl_cert.c b/deps/openssl/openssl/ssl/ssl_cert.c index adc5bb3d35c3..43d1191c6e2e 100644 --- a/deps/openssl/openssl/ssl/ssl_cert.c +++ b/deps/openssl/openssl/ssl/ssl_cert.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved * * Licensed under the Apache License 2.0 (the "License"). You may not use @@ -306,7 +306,7 @@ int ssl_cert_set0_chain(SSL_CONNECTION *s, SSL_CTX *ctx, STACK_OF(X509) *chain) for (i = 0; i < sk_X509_num(chain); i++) { X509 *x = sk_X509_value(chain, i); - r = ssl_security_cert(s, ctx, x, 0, 0); + r = ssl_security_cert(s, ctx, x, 0); if (r != 1) { ERR_raise(ERR_LIB_SSL, r); return 0; @@ -340,7 +340,7 @@ int ssl_cert_add0_chain_cert(SSL_CONNECTION *s, SSL_CTX *ctx, X509 *x) if (!cpk) return 0; - r = ssl_security_cert(s, ctx, x, 0, 0); + r = ssl_security_cert(s, ctx, x, 0); if (r != 1) { ERR_raise(ERR_LIB_SSL, r); return 0; @@ -1149,7 +1149,7 @@ int ssl_build_cert_chain(SSL_CONNECTION *s, SSL_CTX *ctx, int flags) */ for (i = 0; i < sk_X509_num(chain); i++) { x = sk_X509_value(chain, i); - rv = ssl_security_cert(s, ctx, x, 0, 0); + rv = ssl_security_cert(s, ctx, x, 0); if (rv != 1) { ERR_raise(ERR_LIB_SSL, rv); OSSL_STACK_OF_X509_free(chain); diff --git a/deps/openssl/openssl/ssl/ssl_lib.c b/deps/openssl/openssl/ssl/ssl_lib.c index 05b0209a76b3..ba494f5fc0d0 100644 --- a/deps/openssl/openssl/ssl/ssl_lib.c +++ b/deps/openssl/openssl/ssl/ssl_lib.c @@ -5226,6 +5226,31 @@ SSL *SSL_dup(SSL *s) || !dup_ca_names(&retsc->client_ca_names, sc->client_ca_names)) goto err; + if (sc->server_cert_type != NULL) { + OPENSSL_free(retsc->server_cert_type); + retsc->server_cert_type = OPENSSL_memdup(sc->server_cert_type, + sc->server_cert_type_len); + if (retsc->server_cert_type == NULL) + goto err; + retsc->server_cert_type_len = sc->server_cert_type_len; + } + + if (sc->client_cert_type != NULL) { + OPENSSL_free(retsc->client_cert_type); + retsc->client_cert_type = OPENSSL_memdup(sc->client_cert_type, + sc->client_cert_type_len); + if (retsc->client_cert_type == NULL) + goto err; + retsc->client_cert_type_len = sc->client_cert_type_len; + } + +#ifndef OPENSSL_NO_CT + retsc->ct_validation_callback = sc->ct_validation_callback; + retsc->ct_validation_callback_arg = sc->ct_validation_callback_arg; +#endif + + retsc->ext.status_type = sc->ext.status_type; + return ret; err: diff --git a/deps/openssl/openssl/ssl/ssl_local.h b/deps/openssl/openssl/ssl/ssl_local.h index 8fc8b6440615..d974ac6ecfe0 100644 --- a/deps/openssl/openssl/ssl/ssl_local.h +++ b/deps/openssl/openssl/ssl/ssl_local.h @@ -1,5 +1,5 @@ /* - * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved * Copyright 2005 Nokia. All rights reserved. * @@ -2901,10 +2901,9 @@ __owur int ssl_validate_ct(SSL_CONNECTION *s); __owur EVP_PKEY *ssl_get_auto_dh(SSL_CONNECTION *s); -__owur int ssl_security_cert(SSL_CONNECTION *s, SSL_CTX *ctx, X509 *x, int vfy, - int is_ee); +__owur int ssl_security_cert(SSL_CONNECTION *s, SSL_CTX *ctx, X509 *x, int is_ee); __owur int ssl_security_cert_chain(SSL_CONNECTION *s, STACK_OF(X509) *sk, - X509 *ex, int vfy); + X509 *ex); int tls_choose_sigalg(SSL_CONNECTION *s, int fatalerrs); diff --git a/deps/openssl/openssl/ssl/ssl_rsa.c b/deps/openssl/openssl/ssl/ssl_rsa.c index 740460f5c2e0..42958d9d0c2d 100644 --- a/deps/openssl/openssl/ssl/ssl_rsa.c +++ b/deps/openssl/openssl/ssl/ssl_rsa.c @@ -42,7 +42,7 @@ int SSL_use_certificate(SSL *ssl, X509 *x) return 0; } - rv = ssl_security_cert(sc, NULL, x, 0, 1); + rv = ssl_security_cert(sc, NULL, x, 1); if (rv != 1) { ERR_raise(ERR_LIB_SSL, rv); return 0; @@ -247,7 +247,7 @@ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) return 0; } - rv = ssl_security_cert(NULL, ctx, x, 0, 1); + rv = ssl_security_cert(NULL, ctx, x, 1); if (rv != 1) { ERR_raise(ERR_LIB_SSL, rv); return 0; @@ -993,13 +993,13 @@ static int ssl_set_cert_and_key(SSL *ssl, SSL_CTX *ctx, X509 *x509, EVP_PKEY *pr c = sc != NULL ? sc->cert : ctx->cert; /* Do all security checks before anything else */ - rv = ssl_security_cert(sc, ctx, x509, 0, 1); + rv = ssl_security_cert(sc, ctx, x509, 1); if (rv != 1) { ERR_raise(ERR_LIB_SSL, rv); goto out; } for (j = 0; j < sk_X509_num(chain); j++) { - rv = ssl_security_cert(sc, ctx, sk_X509_value(chain, j), 0, 0); + rv = ssl_security_cert(sc, ctx, sk_X509_value(chain, j), 0); if (rv != 1) { ERR_raise(ERR_LIB_SSL, rv); goto out; diff --git a/deps/openssl/openssl/ssl/statem/extensions.c b/deps/openssl/openssl/ssl/statem/extensions.c index 2de540f828f0..13846bc11596 100644 --- a/deps/openssl/openssl/ssl/statem/extensions.c +++ b/deps/openssl/openssl/ssl/statem/extensions.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -605,6 +605,11 @@ int tls_collect_extensions(SSL_CONNECTION *s, PACKET *packet, SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_EXTENSION); goto err; } + + /* The server must tolerate the unknown extension and complete. */ + if (thisex == NULL) + continue; + idx = thisex - raw_extensions; /*- * Check that we requested this extension (if appropriate). Requests can @@ -635,17 +640,15 @@ int tls_collect_extensions(SSL_CONNECTION *s, PACKET *packet, SSL_R_UNSOLICITED_EXTENSION); goto err; } - if (thisex != NULL) { - thisex->data = extension; - thisex->present = 1; - thisex->type = type; - thisex->received_order = i++; - if (s->ext.debug_cb) - s->ext.debug_cb(SSL_CONNECTION_GET_USER_SSL(s), !s->server, - thisex->type, PACKET_data(&thisex->data), - PACKET_remaining(&thisex->data), - s->ext.debug_arg); - } + thisex->data = extension; + thisex->present = 1; + thisex->type = type; + thisex->received_order = i++; + if (s->ext.debug_cb) + s->ext.debug_cb(SSL_CONNECTION_GET_USER_SSL(s), !s->server, + thisex->type, PACKET_data(&thisex->data), + (int)PACKET_remaining(&thisex->data), + s->ext.debug_arg); } if (init) { diff --git a/deps/openssl/openssl/ssl/statem/statem_clnt.c b/deps/openssl/openssl/ssl/statem/statem_clnt.c index b317b9392435..0279a62abd2e 100644 --- a/deps/openssl/openssl/ssl/statem/statem_clnt.c +++ b/deps/openssl/openssl/ssl/statem/statem_clnt.c @@ -2814,6 +2814,14 @@ MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL_CONNECTION *s, if (SSL_CONNECTION_IS_TLS13(s)) { PACKET extpkt; + /* + * Fulfilling RFC8446:4.6.1 requirement: Clients MUST NOT cache + * tickets for longer than 7 days. + */ + if (ticket_lifetime_hint > 604800) { + ticket_lifetime_hint = 604800; + } + if (!PACKET_as_length_prefixed_2(pkt, &extpkt) || PACKET_remaining(pkt) != 0) { SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH); diff --git a/deps/openssl/openssl/ssl/statem/statem_lib.c b/deps/openssl/openssl/ssl/statem/statem_lib.c index 7e3be12f7a71..c69008708147 100644 --- a/deps/openssl/openssl/ssl/statem/statem_lib.c +++ b/deps/openssl/openssl/ssl/statem/statem_lib.c @@ -1071,7 +1071,7 @@ static int ssl_add_cert_chain(SSL_CONNECTION *s, WPACKET *pkt, CERT_PKEY *cpk, i /* Don't leave errors in the queue */ ERR_clear_error(); chain = X509_STORE_CTX_get0_chain(xs_ctx); - i = ssl_security_cert_chain(s, chain, NULL, 0); + i = ssl_security_cert_chain(s, chain, NULL); if (i != 1) { #if 0 /* Dummy error calls so mkerr generates them */ @@ -1096,7 +1096,7 @@ static int ssl_add_cert_chain(SSL_CONNECTION *s, WPACKET *pkt, CERT_PKEY *cpk, i } X509_STORE_CTX_free(xs_ctx); } else { - i = ssl_security_cert_chain(s, extra_certs, x, 0); + i = ssl_security_cert_chain(s, extra_certs, x); if (i != 1) { if (!for_comp) SSLfatal(s, SSL_AD_INTERNAL_ERROR, i); diff --git a/deps/openssl/openssl/ssl/statem/statem_srvr.c b/deps/openssl/openssl/ssl/statem/statem_srvr.c index b2f8a0ebc43d..03fcc6eeac79 100644 --- a/deps/openssl/openssl/ssl/statem/statem_srvr.c +++ b/deps/openssl/openssl/ssl/statem/statem_srvr.c @@ -3921,8 +3921,10 @@ CON_FUNC_RETURN tls_construct_server_compressed_certificate(SSL_CONNECTION *sc, || !WPACKET_put_bytes_u24(pkt, cc->orig_len) || !WPACKET_start_sub_packet_u24(pkt) || !WPACKET_memcpy(pkt, cc->data, cc->len) - || !WPACKET_close(pkt)) + || !WPACKET_close(pkt)) { + SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return 0; + } sc->s3.tmp.cert->cert_comp_used++; return 1; @@ -4251,7 +4253,7 @@ CON_FUNC_RETURN tls_construct_new_session_ticket(SSL_CONNECTION *s, WPACKET *pkt SSL_SESSION *new_sess = ssl_session_dup(s->session, 0); if (new_sess == NULL) { - /* SSLfatal already called */ + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_SSL_LIB); goto err; } diff --git a/deps/openssl/openssl/ssl/t1_lib.c b/deps/openssl/openssl/ssl/t1_lib.c index e11fa8bc638e..ef1114172a28 100644 --- a/deps/openssl/openssl/ssl/t1_lib.c +++ b/deps/openssl/openssl/ssl/t1_lib.c @@ -1817,53 +1817,6 @@ void tls1_get_formatlist(SSL_CONNECTION *s, const unsigned char **pformats, } } -/* Check a key is compatible with compression extension */ -static int tls1_check_pkey_comp(SSL_CONNECTION *s, EVP_PKEY *pkey) -{ - unsigned char comp_id; - size_t i; - int point_conv; - - /* If not an EC key nothing to check */ - if (!EVP_PKEY_is_a(pkey, "EC")) - return 1; - - /* Get required compression id */ - point_conv = EVP_PKEY_get_ec_point_conv_form(pkey); - if (point_conv == 0) - return 0; - if (point_conv == POINT_CONVERSION_UNCOMPRESSED) { - comp_id = TLSEXT_ECPOINTFORMAT_uncompressed; - } else if (SSL_CONNECTION_IS_TLS13(s)) { - /* - * ec_point_formats extension is not used in TLSv1.3 so we ignore - * this check. - */ - return 1; - } else { - int field_type = EVP_PKEY_get_field_type(pkey); - - if (field_type == NID_X9_62_prime_field) - comp_id = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime; - else if (field_type == NID_X9_62_characteristic_two_field) - comp_id = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2; - else - return 0; - } - /* - * If point formats extension present check it, otherwise everything is - * supported (see RFC4492). - */ - if (s->ext.peer_ecpointformats == NULL) - return 1; - - for (i = 0; i < s->ext.peer_ecpointformats_len; i++) { - if (s->ext.peer_ecpointformats[i] == comp_id) - return 1; - } - return 0; -} - /* Return group id of a key */ static uint16_t tls1_get_group_id(EVP_PKEY *pkey) { @@ -1888,9 +1841,6 @@ static int tls1_check_cert_param(SSL_CONNECTION *s, X509 *x, int check_ee_md) /* If not EC nothing to do */ if (!EVP_PKEY_is_a(pkey, "EC")) return 1; - /* Check compression */ - if (!tls1_check_pkey_comp(s, pkey)) - return 0; group_id = tls1_get_group_id(pkey); /* * For a server we allow the certificate to not be in our list of supported @@ -2788,13 +2738,6 @@ int tls12_check_peer_sigalg(SSL_CONNECTION *s, uint16_t sig, EVP_PKEY *pkey) if (pkeyid == EVP_PKEY_EC) { - /* Check point compression is permitted */ - if (!tls1_check_pkey_comp(s, pkey)) { - SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, - SSL_R_ILLEGAL_POINT_COMPRESSION); - return 0; - } - /* For TLS 1.3 or Suite B check curve matches signature algorithm */ if (SSL_CONNECTION_IS_TLS13(s) || tls1_suiteb(s)) { int curve = ssl_get_EC_curve_nid(pkey); @@ -4057,8 +4000,6 @@ int tls1_check_chain(SSL_CONNECTION *s, X509 *x, EVP_PKEY *pk, chain = cpk->chain; strict_mode = c->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT; if (tls12_rpk_and_privkey(s, idx)) { - if (EVP_PKEY_is_a(pk, "EC") && !tls1_check_pkey_comp(s, pk)) - return 0; *pvalid = rv = CERT_PKEY_RPK; return rv; } @@ -4401,51 +4342,29 @@ static int ssl_security_cert_key(SSL_CONNECTION *s, SSL_CTX *ctx, X509 *x, return ssl_ctx_security(ctx, op, secbits, 0, x); } -static int ssl_security_cert_sig(SSL_CONNECTION *s, SSL_CTX *ctx, X509 *x, - int op) +int ssl_security_cert(SSL_CONNECTION *s, SSL_CTX *ctx, X509 *x, int is_ee) { - /* Lookup signature algorithm digest */ - int secbits, nid, pknid; - - /* Don't check signature if self signed */ - if ((X509_get_extension_flags(x) & EXFLAG_SS) != 0) - return 1; - if (!X509_get_signature_info(x, &nid, &pknid, &secbits, NULL)) - secbits = -1; - /* If digest NID not defined use signature NID */ - if (nid == NID_undef) - nid = pknid; - if (s != NULL) - return ssl_security(s, op, secbits, nid, x); - else - return ssl_ctx_security(ctx, op, secbits, nid, x); -} - -int ssl_security_cert(SSL_CONNECTION *s, SSL_CTX *ctx, X509 *x, int vfy, - int is_ee) -{ - if (vfy) - vfy = SSL_SECOP_PEER; if (is_ee) { - if (!ssl_security_cert_key(s, ctx, x, SSL_SECOP_EE_KEY | vfy)) + if (!ssl_security_cert_key(s, ctx, x, SSL_SECOP_EE_KEY)) return SSL_R_EE_KEY_TOO_SMALL; } else { - if (!ssl_security_cert_key(s, ctx, x, SSL_SECOP_CA_KEY | vfy)) + if (!ssl_security_cert_key(s, ctx, x, SSL_SECOP_CA_KEY)) return SSL_R_CA_KEY_TOO_SMALL; } - if (!ssl_security_cert_sig(s, ctx, x, SSL_SECOP_CA_MD | vfy)) - return SSL_R_CA_MD_TOO_WEAK; return 1; } /* - * Check security of a chain, if |sk| includes the end entity certificate then - * |x| is NULL. If |vfy| is 1 then we are verifying a peer chain and not sending - * one to the peer. Return values: 1 if ok otherwise error code to use + * Call ssl_security_check() on all certificates in a stack. + * If |x| is non NULL it is checked first, before checking the + * certificates in the stack. + * + * Return values: 1 if ok otherwise the error code from the first + * failing ssl_security_check().; */ int ssl_security_cert_chain(SSL_CONNECTION *s, STACK_OF(X509) *sk, - X509 *x, int vfy) + X509 *x) { int rv, start_idx, i; @@ -4457,13 +4376,13 @@ int ssl_security_cert_chain(SSL_CONNECTION *s, STACK_OF(X509) *sk, } else start_idx = 0; - rv = ssl_security_cert(s, NULL, x, vfy, 1); + rv = ssl_security_cert(s, NULL, x, 1); if (rv != 1) return rv; for (i = start_idx; i < sk_X509_num(sk); i++) { x = sk_X509_value(sk, i); - rv = ssl_security_cert(s, NULL, x, vfy, 0); + rv = ssl_security_cert(s, NULL, x, 0); if (rv != 1) return rv; } @@ -4523,6 +4442,20 @@ static int check_cert_usable(SSL_CONNECTION *s, const SIGALG_LOOKUP *sig, if (supported <= 0) return 0; + /* + * When RPK is negotiated there are no certificate signatures to + * constrain, and there may not even be a certificate configured. + */ + if (TLSEXT_cert_type_rpk == (s->server ? s->ext.server_cert_type : s->ext.client_cert_type)) + return 1; + + /* + * RPK was enabled, adding candidate private-key-only slots, but was not + * negotiated, so the key-only slot is not usable. + */ + if (x == NULL) + return 0; + /* * The TLS 1.3 signature_algorithms_cert extension places restrictions * on the sigalg with which the certificate was signed (by its issuer). diff --git a/deps/openssl/openssl/util/missingcrypto.txt b/deps/openssl/openssl/util/missingcrypto.txt index 16ca0e49dfa0..ad0f165fa6ba 100644 --- a/deps/openssl/openssl/util/missingcrypto.txt +++ b/deps/openssl/openssl/util/missingcrypto.txt @@ -590,8 +590,6 @@ LONG_it(3) MD2_options(3) MD4_Transform(3) MD5_Transform(3) -NAME_CONSTRAINTS_check(3) -NAME_CONSTRAINTS_check_CN(3) NAME_CONSTRAINTS_it(3) NAMING_AUTHORITY_it(3) NCONF_WIN32(3) diff --git a/deps/openssl/openssl/util/other.syms b/deps/openssl/openssl/util/other.syms index ba188d46c796..0bb7b92bd69b 100644 --- a/deps/openssl/openssl/util/other.syms +++ b/deps/openssl/openssl/util/other.syms @@ -2,10 +2,12 @@ # that don't appear in lib*.num -- because they are define's, in # assembly language, etc. # +OPENSSL_armcap environment OPENSSL_ia32cap environment OPENSSL_ppccap environment -OPENSSL_s390xcap environment OPENSSL_riscvcap environment +OPENSSL_s390xcap environment +OPENSSL_sparcv9cap environment OPENSSL_MALLOC_FD environment OPENSSL_MALLOC_FAILURES environment OPENSSL_instrument_bus assembler @@ -783,6 +785,7 @@ SSL_VALUE_CLASS_FEATURE_REQUEST define SSL_VALUE_CLASS_FEATURE_PEER_REQUEST define SSL_VALUE_CLASS_FEATURE_NEGOTIATED define SSL_VALUE_QUIC_IDLE_TIMEOUT define +SSL_VALUE_QUIC_MAX_PENDING_CONNS define SSL_VALUE_QUIC_STREAM_BIDI_LOCAL_AVAIL define SSL_VALUE_QUIC_STREAM_BIDI_REMOTE_AVAIL define SSL_VALUE_QUIC_STREAM_UNI_LOCAL_AVAIL define diff --git a/deps/openssl/openssl/util/perl/TLSProxy/Proxy.pm b/deps/openssl/openssl/util/perl/TLSProxy/Proxy.pm index c3db4e28db0f..729b351b3f0a 100644 --- a/deps/openssl/openssl/util/perl/TLSProxy/Proxy.pm +++ b/deps/openssl/openssl/util/perl/TLSProxy/Proxy.pm @@ -1,4 +1,4 @@ -# Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2016-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -177,6 +177,7 @@ sub init server_port => 0, serverpid => 0, clientpid => 0, + clientexit => 0, execute => $execute, cert => $cert, debug => $debug, @@ -215,6 +216,7 @@ sub clearClient $self->{clientflags} = ""; $self->{sessionfile} = undef; $self->{clientpid} = 0; + $self->{clientexit} = 0; $is_tls13 = 0; $ciphersuite = undef; @@ -585,6 +587,7 @@ sub clientstart $pid = $self->{clientpid}; print "Waiting for s_client process to close: $pid...\n"; waitpid($pid, 0); + $self->{clientexit} = $?; return $success; } @@ -722,6 +725,11 @@ sub clientpid my $self = shift; return $self->{clientpid}; } +sub clientexit +{ + my $self = shift; + return $self->{clientexit}; +} #Read/write accessors sub filter diff --git a/deps/simdjson/simdjson.cpp b/deps/simdjson/simdjson.cpp index 0d19312880fd..7b8b0c44f057 100644 --- a/deps/simdjson/simdjson.cpp +++ b/deps/simdjson/simdjson.cpp @@ -1,4 +1,4 @@ -/* auto-generated on 2026-07-30 16:20:13 -0400. version 4.6.6 Do not edit! */ +/* auto-generated on 2026-08-14 12:14:27 -0400. version 4.6.7 Do not edit! */ /* including simdjson.cpp: */ /* begin file simdjson.cpp */ #define SIMDJSON_SRC_SIMDJSON_CPP @@ -15228,6 +15228,9 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_ const uint8_t *p = value; if (*p == '-') p++; while (numberparsing::is_digit(*p)) p++; + // The digit run must be terminated by a structural or whitespace character; otherwise the + // token is malformed (e.g. "123456789123456789123x"). + if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return NUMBER_ERROR; } size_t len = size_t(p - value); tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT); uint8_t *dst = current_string_buf_loc + sizeof(uint32_t); @@ -21620,6 +21623,9 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_ const uint8_t *p = value; if (*p == '-') p++; while (numberparsing::is_digit(*p)) p++; + // The digit run must be terminated by a structural or whitespace character; otherwise the + // token is malformed (e.g. "123456789123456789123x"). + if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return NUMBER_ERROR; } size_t len = size_t(p - value); tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT); uint8_t *dst = current_string_buf_loc + sizeof(uint32_t); @@ -28007,6 +28013,9 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_ const uint8_t *p = value; if (*p == '-') p++; while (numberparsing::is_digit(*p)) p++; + // The digit run must be terminated by a structural or whitespace character; otherwise the + // token is malformed (e.g. "123456789123456789123x"). + if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return NUMBER_ERROR; } size_t len = size_t(p - value); tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT); uint8_t *dst = current_string_buf_loc + sizeof(uint32_t); @@ -34665,6 +34674,9 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_ const uint8_t *p = value; if (*p == '-') p++; while (numberparsing::is_digit(*p)) p++; + // The digit run must be terminated by a structural or whitespace character; otherwise the + // token is malformed (e.g. "123456789123456789123x"). + if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return NUMBER_ERROR; } size_t len = size_t(p - value); tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT); uint8_t *dst = current_string_buf_loc + sizeof(uint32_t); @@ -41885,6 +41897,9 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_ const uint8_t *p = value; if (*p == '-') p++; while (numberparsing::is_digit(*p)) p++; + // The digit run must be terminated by a structural or whitespace character; otherwise the + // token is malformed (e.g. "123456789123456789123x"). + if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return NUMBER_ERROR; } size_t len = size_t(p - value); tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT); uint8_t *dst = current_string_buf_loc + sizeof(uint32_t); @@ -48136,6 +48151,9 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_ const uint8_t *p = value; if (*p == '-') p++; while (numberparsing::is_digit(*p)) p++; + // The digit run must be terminated by a structural or whitespace character; otherwise the + // token is malformed (e.g. "123456789123456789123x"). + if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return NUMBER_ERROR; } size_t len = size_t(p - value); tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT); uint8_t *dst = current_string_buf_loc + sizeof(uint32_t); @@ -54291,6 +54309,9 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_ const uint8_t *p = value; if (*p == '-') p++; while (numberparsing::is_digit(*p)) p++; + // The digit run must be terminated by a structural or whitespace character; otherwise the + // token is malformed (e.g. "123456789123456789123x"). + if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return NUMBER_ERROR; } size_t len = size_t(p - value); tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT); uint8_t *dst = current_string_buf_loc + sizeof(uint32_t); @@ -60865,6 +60886,9 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_ const uint8_t *p = value; if (*p == '-') p++; while (numberparsing::is_digit(*p)) p++; + // The digit run must be terminated by a structural or whitespace character; otherwise the + // token is malformed (e.g. "123456789123456789123x"). + if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return NUMBER_ERROR; } size_t len = size_t(p - value); tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT); uint8_t *dst = current_string_buf_loc + sizeof(uint32_t); @@ -64733,6 +64757,9 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_ const uint8_t *p = value; if (*p == '-') p++; while (numberparsing::is_digit(*p)) p++; + // The digit run must be terminated by a structural or whitespace character; otherwise the + // token is malformed (e.g. "123456789123456789123x"). + if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return NUMBER_ERROR; } size_t len = size_t(p - value); tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT); uint8_t *dst = current_string_buf_loc + sizeof(uint32_t); diff --git a/deps/simdjson/simdjson.h b/deps/simdjson/simdjson.h index 89175e6d6f70..afcca85ad6bf 100644 --- a/deps/simdjson/simdjson.h +++ b/deps/simdjson/simdjson.h @@ -1,4 +1,4 @@ -/* auto-generated on 2026-07-30 16:20:13 -0400. version 4.6.6 Do not edit! */ +/* auto-generated on 2026-08-14 12:14:27 -0400. version 4.6.7 Do not edit! */ /* including simdjson.h: */ /* begin file simdjson.h */ #ifndef SIMDJSON_H @@ -2538,7 +2538,7 @@ namespace std { #define SIMDJSON_SIMDJSON_VERSION_H /** The version of simdjson being used (major.minor.revision) */ -#define SIMDJSON_VERSION "4.6.6" +#define SIMDJSON_VERSION "4.6.7" namespace simdjson { enum { @@ -2553,7 +2553,7 @@ enum { /** * The revision (major.minor.REVISION) of simdjson being used. */ - SIMDJSON_VERSION_REVISION = 6 + SIMDJSON_VERSION_REVISION = 7 }; } // namespace simdjson diff --git a/deps/undici/src/lib/dispatcher/balanced-pool.js b/deps/undici/src/lib/dispatcher/balanced-pool.js index c21c081c45c4..386023d03dd0 100644 --- a/deps/undici/src/lib/dispatcher/balanced-pool.js +++ b/deps/undici/src/lib/dispatcher/balanced-pool.js @@ -49,14 +49,16 @@ function defaultFactory (origin, opts) { } class BalancedPool extends PoolBase { - constructor (upstreams = [], { factory = defaultFactory, ...opts } = {}) { + constructor (upstreams = [], { factory = defaultFactory, connect, tls, ...opts } = {}) { if (typeof factory !== 'function') { throw new InvalidArgumentError('factory must be a function.') } super(opts) - this[kOptions] = { ...util.deepClone(opts) } + if (connect && typeof connect !== 'function') connect = { ...connect } + if (tls && typeof tls !== 'function') tls = { ...tls } + this[kOptions] = { ...util.deepClone(opts), connect, tls } this[kOptions].interceptors = opts.interceptors ? { ...opts.interceptors } : undefined diff --git a/deps/undici/src/lib/dispatcher/client-h1.js b/deps/undici/src/lib/dispatcher/client-h1.js index 5b2cdd8faf58..ed119b7156bc 100644 --- a/deps/undici/src/lib/dispatcher/client-h1.js +++ b/deps/undici/src/lib/dispatcher/client-h1.js @@ -1012,7 +1012,7 @@ function onSocketClose () { function clearIdleSocketValidation (socket) { if (socket[kIdleSocketValidationTimeout]) { - clearTimeout(socket[kIdleSocketValidationTimeout]) + clearImmediate(socket[kIdleSocketValidationTimeout]) socket[kIdleSocketValidationTimeout] = null } @@ -1021,15 +1021,23 @@ function clearIdleSocketValidation (socket) { function scheduleIdleSocketValidation (client, socket) { socket[kIdleSocketValidation] = 1 - socket[kIdleSocketValidationTimeout] = setTimeout(() => { + // Yield to the check phase (after poll) so unsolicited bytes / FIN / RST + // already pending on this idle keep-alive socket are processed before the + // next request is written (GHSA-35p6-xmwp-9g52). + // + // setTimeout(0) pays Node's ~1ms timer floor on every sequential reuse + // (#5493). setImmediate avoids that, but an *unref'd* Immediate lets poll + // block for ~500ms when the event loop is otherwise idle (#5600 / #5606). + // A ref'd Immediate both keeps the pending request alive and makes poll + // return immediately — the hybrid those issues asked for. + socket[kIdleSocketValidationTimeout] = setImmediate(() => { socket[kIdleSocketValidationTimeout] = null socket[kIdleSocketValidation] = 2 if (client[kSocket] === socket && !socket.destroyed) { client[kResume]() } - }, 0) - socket[kIdleSocketValidationTimeout].unref?.() + }) } /** diff --git a/deps/undici/src/lib/dispatcher/client-h2.js b/deps/undici/src/lib/dispatcher/client-h2.js index 0585e7cd925c..6025768667d1 100644 --- a/deps/undici/src/lib/dispatcher/client-h2.js +++ b/deps/undici/src/lib/dispatcher/client-h2.js @@ -8,7 +8,9 @@ const { RequestAbortedError, SocketError, InformationalError, - InvalidArgumentError + InvalidArgumentError, + HeadersTimeoutError, + BodyTimeoutError } = require('../core/errors.js') const { kUrl, @@ -33,6 +35,7 @@ const { kHTTPContext, kClosed, kBodyTimeout, + kHeadersTimeout, kEnableConnectProtocol, kRemoteSettings, kHTTP2Stream, @@ -219,7 +222,11 @@ function resumeH2 (client) { const socket = client[kSocket] if (socket?.destroyed === false) { - if (client[kSize] === 0 || client[kMaxConcurrentStreams] === 0) { + // Only let the process exit when there is genuinely nothing outstanding. + // Unreffing because the peer advertised MAX_CONCURRENT_STREAMS = 0 left + // queued requests with nothing holding the event loop open, so the process + // could exit with status 0 while an awaited request never settled. + if (client[kSize] === 0) { socket.unref() client[kHTTP2Session].unref() } else { @@ -314,6 +321,36 @@ function onHttp2SessionEnd () { * @this {import('http2').ClientHttp2Session} * @param {number} errorCode */ +// Backport of #5410 and #5569. HTTP/2 multiplexes, so requests complete out of +// order; advancing kRunningIdx blindly retired whichever request happened to +// sit at the head instead of the one that actually finished, which both lost +// requests and left phantom running slots behind. +function completeRequest (client, request, resetPendingIdx = false) { + const queue = client[kQueue] + const runningIdx = client[kRunningIdx] + + // In-order completion: clear the request and advance without splicing. + // The client's resume loop compacts cleared slots once the index grows. + if (runningIdx < client[kPendingIdx] && queue[runningIdx] === request) { + queue[runningIdx] = null + client[kRunningIdx] = runningIdx + 1 + return + } + + const index = queue.indexOf(request, runningIdx) + + if (index === -1 || index >= client[kPendingIdx]) { + return + } + + queue.splice(index, 1) + client[kPendingIdx]-- + + if (resetPendingIdx && client[kPendingIdx] < client[kRunningIdx]) { + client[kPendingIdx] = client[kRunningIdx] + } +} + function onHttp2SessionGoAway (errorCode) { // TODO(mcollina): Verify if GOAWAY implements the spec correctly: // https://datatracker.ietf.org/doc/html/rfc7540#section-6.8 @@ -335,7 +372,9 @@ function onHttp2SessionGoAway (errorCode) { if (client[kRunningIdx] < client[kQueue].length) { const request = client[kQueue][client[kRunningIdx]] client[kQueue][client[kRunningIdx]++] = null - util.errorRequest(client, request, err) + if (request != null) { + util.errorRequest(client, request, err) + } client[kPendingIdx] = client[kRunningIdx] } @@ -368,7 +407,9 @@ function onHttp2SessionClose () { const requests = client[kQueue].splice(client[kRunningIdx]) for (let i = 0; i < requests.length; i++) { const request = requests[i] - util.errorRequest(client, request, err) + if (request != null) { + util.errorRequest(client, request, err) + } } } } @@ -416,7 +457,10 @@ function shouldSendContentLength (method) { } function writeH2 (client, request) { - const requestTimeout = request.bodyTimeout ?? client[kBodyTimeout] + // Time to the response headers, then time between body chunks. Using + // bodyTimeout for both made headersTimeout a no-op over HTTP/2. + const headersTimeout = request.headersTimeout ?? client[kHeadersTimeout] + const bodyTimeout = request.bodyTimeout ?? client[kBodyTimeout] const session = client[kHTTP2Session] const { method, path, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request let { body } = request @@ -483,6 +527,7 @@ function writeH2 (client, request) { // We move the running index to the next request client[kOnError](err) + completeRequest(client, request) client[kResume]() } @@ -537,7 +582,7 @@ function writeH2 (client, request) { request.onUpgrade(statusCode, parseH2Headers(realHeaders), stream) ++session[kOpenStreams] - client[kQueue][client[kRunningIdx]++] = null + completeRequest(client, request) }) stream.on('error', () => { @@ -554,7 +599,7 @@ function writeH2 (client, request) { if (session[kOpenStreams] === 0) session.unref() }) - stream.setTimeout(requestTimeout) + stream.setTimeout(headersTimeout) return true } @@ -570,13 +615,14 @@ function writeH2 (client, request) { request.onUpgrade(statusCode, parseH2Headers(realHeaders), stream) ++session[kOpenStreams] - client[kQueue][client[kRunningIdx]++] = null + completeRequest(client, request) }) + stream.on('error', abort) stream.once('close', () => { session[kOpenStreams] -= 1 if (session[kOpenStreams] === 0) session.unref() }) - stream.setTimeout(requestTimeout) + stream.setTimeout(headersTimeout) return true } @@ -677,7 +723,7 @@ function writeH2 (client, request) { // Increment counter as we have new streams open ++session[kOpenStreams] - stream.setTimeout(requestTimeout) + stream.setTimeout(headersTimeout) // Track whether we received a response (headers) let responseReceived = false @@ -686,6 +732,7 @@ function writeH2 (client, request) { const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers request.onResponseStarted() responseReceived = true + stream.setTimeout(bodyTimeout) // Due to the stream nature, it is possible we face a race condition // where the stream has been assigned, but the request has been aborted @@ -720,14 +767,13 @@ function writeH2 (client, request) { request.onComplete({}) } - client[kQueue][client[kRunningIdx]++] = null + completeRequest(client, request) client[kResume]() } else { // Stream ended without receiving a response - this is an error // (e.g., server destroyed the stream before sending headers) abort(new InformationalError('HTTP/2: stream half-closed (remote)')) - client[kQueue][client[kRunningIdx]++] = null - client[kPendingIdx] = client[kRunningIdx] + completeRequest(client, request, true) client[kResume]() } }) @@ -738,6 +784,14 @@ function writeH2 (client, request) { if (session[kOpenStreams] === 0) { session.unref() } + + // A stream can close without ever emitting 'end' or 'error': a peer's + // RST_STREAM(CANCEL) received before the response is reported by Node as a + // bare 'close', and destroying the stream unenrolls its timeout, so no + // 'timeout' follows either. Nothing else would ever settle this request. + if (!request.aborted && !request.completed) { + abort(new InformationalError('HTTP/2: stream closed before the response was complete')) + } }) stream.once('error', function (err) { @@ -755,7 +809,9 @@ function writeH2 (client, request) { }) stream.on('timeout', () => { - const err = new InformationalError(`HTTP/2: "stream timeout after ${requestTimeout}"`) + const err = responseReceived + ? new BodyTimeoutError(`HTTP/2: "body timeout after ${bodyTimeout}"`) + : new HeadersTimeoutError(`HTTP/2: "headers timeout after ${headersTimeout}"`) stream.removeAllListeners('data') session[kOpenStreams] -= 1 diff --git a/deps/undici/src/lib/dispatcher/client.js b/deps/undici/src/lib/dispatcher/client.js index 6ef97ba0a369..ee67336c97ec 100644 --- a/deps/undici/src/lib/dispatcher/client.js +++ b/deps/undici/src/lib/dispatcher/client.js @@ -374,7 +374,9 @@ class Client extends DispatcherBase { const requests = this[kQueue].splice(this[kPendingIdx]) for (let i = 0; i < requests.length; i++) { const request = requests[i] - util.errorRequest(this, request, err) + if (request != null) { + util.errorRequest(this, request, err) + } } const callback = () => { @@ -413,7 +415,9 @@ function onError (client, err) { for (let i = 0; i < requests.length; i++) { const request = requests[i] - util.errorRequest(client, request, err) + if (request != null) { + util.errorRequest(client, request, err) + } } assert(client[kSize] === 0) } diff --git a/deps/undici/src/lib/handler/cache-handler.js b/deps/undici/src/lib/handler/cache-handler.js index d9ea5479c39e..9b162f65a4b4 100644 --- a/deps/undici/src/lib/handler/cache-handler.js +++ b/deps/undici/src/lib/handler/cache-handler.js @@ -207,6 +207,13 @@ class CacheHandler { } const cacheControlHeader = resHeaders['cache-control'] + const cacheControlDirectives = cacheControlHeader ? parseCacheControlHeader(cacheControlHeader) : {} + + if (revalidationResponseDisallowsCachedReuse(this.#cacheType, resHeaders, cacheControlDirectives)) { + deleteCachedValue(this.#store, this.#cacheKey) + return downstreamOnHeaders() + } + const heuristicallyCacheable = resHeaders['last-modified'] && arrayIncludes(HEURISTICALLY_CACHEABLE_STATUS_CODES, statusCode) if ( !cacheControlHeader && @@ -223,8 +230,7 @@ class CacheHandler { return downstreamOnHeaders() } - const cacheControlDirectives = cacheControlHeader ? parseCacheControlHeader(cacheControlHeader) : {} - if (!canCacheResponse(this.#cacheType, statusCode, resHeaders, cacheControlDirectives, this.#cacheKey.headers)) { + if (!canCacheResponse(this.#cacheType, this.#cacheKey.method, statusCode, resHeaders, cacheControlDirectives, this.#cacheKey.headers)) { if (statusCode === 304 && (cacheControlHeader || revalidationResponseDisallowsCachedReuse(this.#cacheType, resHeaders, cacheControlDirectives))) { deleteCachedValue(this.#store, this.#cacheKey) } @@ -465,7 +471,10 @@ function deleteCachedValueIfNotModified (statusCode, store, cacheKey) { */ function revalidationResponseDisallowsCachedReuse (cacheType, resHeaders, cacheControlDirectives) { return cacheControlDirectives['no-store'] === true || - (cacheType === 'shared' && cacheControlDirectives.private === true) || + (cacheType === 'shared' && ( + cacheControlDirectives.private === true || + Object.hasOwn(resHeaders, 'set-cookie') + )) || (resHeaders.vary ? isInvalidOrWildcardVaryHeader(resHeaders.vary) : false) } @@ -473,12 +482,16 @@ function revalidationResponseDisallowsCachedReuse (cacheType, resHeaders, cacheC * @see https://www.rfc-editor.org/rfc/rfc9111.html#name-storing-responses-to-authen * * @param {import('../../types/cache-interceptor.d.ts').default.CacheOptions['type']} cacheType + * @param {string} method * @param {number} statusCode * @param {import('../../types/header.d.ts').IncomingHttpHeaders} resHeaders * @param {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives} cacheControlDirectives * @param {import('../../types/header.d.ts').IncomingHttpHeaders} [reqHeaders] */ -function canCacheResponse (cacheType, statusCode, resHeaders, cacheControlDirectives, reqHeaders) { +function canCacheResponse (cacheType, method, statusCode, resHeaders, cacheControlDirectives, reqHeaders) { + if (!arrayIncludes(util.safeHTTPMethods, method)) { + return false + } // Status code must be final and understood. if (statusCode < 200 || arrayIncludes(NOT_UNDERSTOOD_STATUS_CODES, statusCode)) { return false @@ -499,7 +512,10 @@ function canCacheResponse (cacheType, statusCode, resHeaders, cacheControlDirect return false } - if (cacheType === 'shared' && cacheControlDirectives.private === true) { + if (cacheType === 'shared' && ( + cacheControlDirectives.private === true || + Object.hasOwn(resHeaders, 'set-cookie') + )) { return false } diff --git a/deps/undici/src/lib/handler/retry-handler.js b/deps/undici/src/lib/handler/retry-handler.js index 8908ce5b4cc6..7cc4c1ca1b64 100644 --- a/deps/undici/src/lib/handler/retry-handler.js +++ b/deps/undici/src/lib/handler/retry-handler.js @@ -95,8 +95,16 @@ class RetryHandler { if (this.retryOpts.throwOnError) { // Preserve old behavior for status codes that are not eligible for retry if (this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true - this.handler.onResponseStart?.(controller, statusCode, headers, statusMessage) + if (this.headersSent) { + // The downstream handler already received the response from an + // earlier attempt. Forwarding this response would replace the + // downstream body and leave the original body pending forever. + this.handler.onResponseError?.(controller, err) + } else { + this.headersSent = true + this.checkpointResponseEnd(headers) + this.handler.onResponseStart?.(controller, statusCode, headers, statusMessage) + } } else { this.error = err } @@ -106,14 +114,23 @@ class RetryHandler { if (isDisturbed(this.opts.body)) { this.headersSent = true + this.checkpointResponseEnd(headers) this.handler.onResponseStart?.(controller, statusCode, headers, statusMessage) return } function shouldRetry (passedErr) { if (passedErr) { - this.headersSent = true - this.handler.onResponseStart?.(controller, statusCode, headers, statusMessage) + if (this.headersSent) { + // The downstream handler already received the response from an + // earlier attempt. Forwarding this response would replace the + // downstream body and leave the original body pending forever. + this.handler.onResponseError?.(controller, passedErr) + } else { + this.headersSent = true + this.checkpointResponseEnd(headers) + this.handler.onResponseStart?.(controller, statusCode, headers, statusMessage) + } controller.resume() return } @@ -133,6 +150,20 @@ class RetryHandler { ) } + checkpointResponseEnd (headers) { + if (this.end == null && this.opts.method !== 'HEAD') { + const contentLength = headers['content-length'] + this.end = contentLength != null ? Number(contentLength) - 1 : null + + assert( + this.end == null || Number.isFinite(this.end), + 'invalid content-length' + ) + + this.resume = this.end != null + } + } + onRequestStart (controller, context) { if (!this.headersSent) { this.handler.onRequestStart?.(controller, context) @@ -253,8 +284,12 @@ class RetryHandler { const { start, size, end = size ? size - 1 : null } = contentRange - assert(this.start === start, 'content-range mismatch') - assert(this.end == null || this.end === end, 'content-range mismatch') + if (this.start !== start || (this.end != null && this.end !== end)) { + throw new RequestRetryError('Content-Range mismatch', statusCode, { + headers, + data: { count: this.retryCount } + }) + } return } @@ -379,7 +414,7 @@ class RetryHandler { } onResponseError (controller, err) { - if (controller?.aborted || isDisturbed(this.opts.body)) { + if (controller?.aborted || isDisturbed(this.opts.body) || (this.headersSent && !this.resume)) { this.handler.onResponseError?.(controller, err) return } diff --git a/deps/undici/src/lib/interceptor/cache.js b/deps/undici/src/lib/interceptor/cache.js index a686cbf4102b..149cf8904da4 100644 --- a/deps/undici/src/lib/interceptor/cache.js +++ b/deps/undici/src/lib/interceptor/cache.js @@ -117,7 +117,10 @@ function staleResponseRequiresRevalidation (result, cacheType) { * @returns {boolean} */ function revalidationResponseDisallowsCachedReuse (cacheType, headers) { - if (headers.vary && isInvalidOrWildcardVaryHeader(headers.vary)) { + if ( + (headers.vary && isInvalidOrWildcardVaryHeader(headers.vary)) || + (cacheType === 'shared' && Object.hasOwn(headers, 'set-cookie')) + ) { return true } @@ -376,6 +379,17 @@ function handleResult ( return handleUncachedResponse(dispatch, globalOpts, cacheKey, handler, opts, reqCacheControl) } + // Shared stores may outlive the Undici version that wrote them. Do not + // re-serve a Set-Cookie header from an existing shared-cache entry. + if (globalOpts.type === 'shared' && Object.hasOwn(result.headers, 'set-cookie')) { + if (util.isStream(result.body)) { + result.body.on('error', nop).destroy() + } + + deleteCachedValue(globalOpts.store, cacheKey) + return handleUncachedResponse(dispatch, globalOpts, cacheKey, handler, opts, reqCacheControl) + } + const now = Date.now() if (now > result.deleteAt) { // Response is expired, cache store shouldn't have given this to us @@ -574,6 +588,11 @@ module.exports = (opts = {}) => { * @type {import('../../types/cache-interceptor.d.ts').default.CacheKey} */ const cacheKey = makeCacheKey(opts) + + if (!arrayIncludes(util.safeHTTPMethods, opts.method)) { + return dispatch(opts, new CacheHandler(globalOpts, cacheKey, handler)) + } + const result = store.get(cacheKey) if (result && typeof result.then === 'function') { diff --git a/deps/undici/src/lib/interceptor/decompress.js b/deps/undici/src/lib/interceptor/decompress.js index ee4202a96f70..6c769aeff160 100644 --- a/deps/undici/src/lib/interceptor/decompress.js +++ b/deps/undici/src/lib/interceptor/decompress.js @@ -1,7 +1,8 @@ 'use strict' const { createInflate, createGunzip, createBrotliDecompress, createZstdDecompress } = require('node:zlib') -const { pipeline } = require('node:stream') +const { pipeline, Transform: TransformStream } = require('node:stream') +const { InvalidArgumentError, ResponseExceededMaxSizeError } = require('../core/errors') const DecoratorHandler = require('../handler/decorator-handler') const { runtimeFeatures } = require('../util/runtime-features') @@ -21,6 +22,31 @@ const supportedEncodings = { } const defaultSkipStatusCodes = /** @type {const} */ ([204, 304]) +const defaultMaxSize = 64 * 1024 * 1024 + +/** + * Limits the output of one stage in a decompression chain. + * @param {number} maxSize - Maximum output size in bytes + * @returns {Transform} + */ +function createMaxSizeLimiter (maxSize) { + let size = 0 + + return new TransformStream({ + transform (chunk, _encoding, callback) { + const decompressedSize = size + chunk.length + if (decompressedSize > maxSize) { + callback(new ResponseExceededMaxSizeError( + `Decompressed response size (${decompressedSize}) exceeded maxSize (${maxSize})` + )) + return + } + + size = decompressedSize + callback(null, chunk) + } + }) +} let warningEmitted = /** @type {boolean} */ (false) @@ -28,20 +54,36 @@ let warningEmitted = /** @type {boolean} */ (false) * @typedef {Object} DecompressHandlerOptions * @property {number[]|Readonly} [skipStatusCodes=[204, 304]] - List of status codes to skip decompression for * @property {boolean} [skipErrorResponses] - Whether to skip decompression for error responses (status codes >= 400) + * @property {number} [maxSize=67108864] - Maximum decompressed response size in bytes */ class DecompressHandler extends DecoratorHandler { /** @type {Transform[]} */ #decompressors = [] + /** @type {Record | undefined} */ + #trailers /** @type {Readonly} */ #skipStatusCodes /** @type {boolean} */ #skipErrorResponses + /** @type {number} */ + #maxSize + /** @type {number} */ + #decompressedSize = 0 + /** @type {boolean} */ + #terminated = false + /** @type {boolean} */ + #inputEnded = false + + constructor (handler, { skipStatusCodes = defaultSkipStatusCodes, skipErrorResponses = true, maxSize = defaultMaxSize } = {}) { + if (!Number.isSafeInteger(maxSize) || maxSize < 1) { + throw new InvalidArgumentError('maxSize must be a positive integer') + } - constructor (handler, { skipStatusCodes = defaultSkipStatusCodes, skipErrorResponses = true } = {}) { super(handler) this.#skipStatusCodes = skipStatusCodes this.#skipErrorResponses = skipErrorResponses + this.#maxSize = maxSize } /** @@ -61,7 +103,7 @@ class DecompressHandler extends DecoratorHandler { * Creates a chain of decompressors for multiple content encodings * * @param {string} encodings - Comma-separated list of content encodings - * @returns {Array} - Array of decompressor streams + * @returns {Array} - Array of decompressor and limiting streams * @throws {Error} - If the number of content-encodings exceeds the maximum allowed */ #createDecompressionChain (encodings) { @@ -89,7 +131,40 @@ class DecompressHandler extends DecoratorHandler { decompressors.push(supportedEncodings[encoding]()) } - return decompressors + if (decompressors.length < 2) { + return decompressors + } + + /** @type {Transform[]} */ + const streams = [] + for (let i = 0; i < decompressors.length; i++) { + streams.push(decompressors[i]) + if (i < decompressors.length - 1) { + streams.push(createMaxSizeLimiter(this.#maxSize)) + } + } + + return streams + } + + /** + * Stops decompression and reports an error. + * @param {Controller} controller - The controller to coordinate with + * @param {Error} error - The decompression error + * @returns {void} + */ + #fail (controller, error) { + if (this.#terminated) { + return + } + + if (this.#inputEnded) { + // The request is already marked complete once the compressed input ends, + // so controller.abort() can no longer propagate decoder flush errors. + this.onResponseError(controller, error) + } else { + controller.abort(error) + } } /** @@ -100,8 +175,21 @@ class DecompressHandler extends DecoratorHandler { */ #setupDecompressorEvents (decompressor, controller) { decompressor.on('readable', () => { + if (this.#terminated) { + return + } + let chunk while ((chunk = decompressor.read()) !== null) { + const decompressedSize = this.#decompressedSize + chunk.length + if (decompressedSize > this.#maxSize) { + this.#fail(controller, new ResponseExceededMaxSizeError( + `Decompressed response size (${decompressedSize}) exceeded maxSize (${this.#maxSize})` + )) + return + } + + this.#decompressedSize = decompressedSize const result = super.onResponseData(controller, chunk) if (result === false) { break @@ -110,7 +198,7 @@ class DecompressHandler extends DecoratorHandler { }) decompressor.on('error', (error) => { - super.onResponseError(controller, error) + this.#fail(controller, error) }) } @@ -124,7 +212,13 @@ class DecompressHandler extends DecoratorHandler { this.#setupDecompressorEvents(decompressor, controller) decompressor.on('end', () => { - super.onResponseEnd(controller, {}) + if (this.#terminated) { + return + } + + this.#terminated = true + this.#cleanupDecompressors() + super.onResponseEnd(controller, this.#trailers) }) } @@ -138,11 +232,18 @@ class DecompressHandler extends DecoratorHandler { this.#setupDecompressorEvents(lastDecompressor, controller) pipeline(this.#decompressors, (err) => { + if (this.#terminated) { + return + } + if (err) { - super.onResponseError(controller, err) + this.#fail(controller, err) return } - super.onResponseEnd(controller, {}) + + this.#terminated = true + this.#cleanupDecompressors() + super.onResponseEnd(controller, this.#trailers) }) } @@ -181,6 +282,33 @@ class DecompressHandler extends DecoratorHandler { // Remove compression headers since we're decompressing const { 'content-encoding': _, 'content-length': __, ...newHeaders } = headers + if (controller?.rawHeaders) { + const rawHeaders = controller.rawHeaders + + if (Array.isArray(rawHeaders)) { + const filteredHeaders = [] + for (let i = 0; i < rawHeaders.length; i += 2) { + const headerName = rawHeaders[i] + const name = Buffer.isBuffer(headerName) ? headerName.toString('latin1') : `${headerName}` + const lowerName = name.toLowerCase() + + if (lowerName === 'content-encoding' || lowerName === 'content-length') { + continue + } + + filteredHeaders.push(rawHeaders[i], rawHeaders[i + 1]) + } + rawHeaders.splice(0, rawHeaders.length, ...filteredHeaders) + } else if (typeof rawHeaders === 'object') { + for (const name of Object.keys(rawHeaders)) { + const lowerName = name.toLowerCase() + if (lowerName === 'content-encoding' || lowerName === 'content-length') { + delete rawHeaders[name] + } + } + } + } + if (this.#decompressors.length === 1) { this.#setupSingleDecompressor(controller) } else { @@ -210,8 +338,9 @@ class DecompressHandler extends DecoratorHandler { */ onResponseEnd (controller, trailers) { if (this.#decompressors.length > 0) { + this.#inputEnded = true + this.#trailers = trailers this.#decompressors[0].end() - this.#cleanupDecompressors() return } super.onResponseEnd(controller, trailers) @@ -223,12 +352,15 @@ class DecompressHandler extends DecoratorHandler { * @returns {void} */ onResponseError (controller, err) { - if (this.#decompressors.length > 0) { - for (const decompressor of this.#decompressors) { - decompressor.destroy(err) - } - this.#cleanupDecompressors() + if (this.#terminated) { + return + } + + this.#terminated = true + for (const decompressor of this.#decompressors) { + decompressor.destroy() } + this.#cleanupDecompressors() super.onResponseError(controller, err) } } diff --git a/deps/undici/src/lib/interceptor/dump.js b/deps/undici/src/lib/interceptor/dump.js index 4810a09f3824..09b57f2163fb 100644 --- a/deps/undici/src/lib/interceptor/dump.js +++ b/deps/undici/src/lib/interceptor/dump.js @@ -7,7 +7,6 @@ class DumpHandler extends DecoratorHandler { #maxSize = 1024 * 1024 #dumped = false #size = 0 - #controller = null aborted = false reason = false @@ -29,7 +28,6 @@ class DumpHandler extends DecoratorHandler { onRequestStart (controller, context) { controller.abort = this.#abort.bind(this) - this.#controller = controller return super.onRequestStart(controller, context) } @@ -53,43 +51,32 @@ class DumpHandler extends DecoratorHandler { } onResponseError (controller, err) { - if (this.#dumped) { - return - } - - // On network errors before connect, controller will be null - err = this.#controller?.reason ?? err - - super.onResponseError(controller, err) + super.onResponseError(controller, this.aborted === true ? this.reason : err) } onResponseData (controller, chunk) { this.#size = this.#size + chunk.length - if (this.#size >= this.#maxSize) { - this.#dumped = true + if (this.#size > this.#maxSize) { + throw new RequestAbortedError( + `Response size (${this.#size}) larger than maxSize (${this.#maxSize})` + ) + } - if (this.aborted === true) { - super.onResponseError(controller, this.reason) - } else { - super.onResponseEnd(controller, {}) - } + if (this.#size === this.#maxSize) { + this.#dumped = true } return true } onResponseEnd (controller, trailers) { - if (this.#dumped) { - return - } - - if (this.#controller.aborted === true) { + if (this.aborted === true) { super.onResponseError(controller, this.reason) return } - super.onResponseEnd(controller, trailers) + super.onResponseEnd(controller, this.#dumped ? {} : trailers) } } diff --git a/deps/undici/src/lib/llhttp/wasm_build_env.txt b/deps/undici/src/lib/llhttp/wasm_build_env.txt index 0b2f32dd902e..1749e700197c 100644 --- a/deps/undici/src/lib/llhttp/wasm_build_env.txt +++ b/deps/undici/src/lib/llhttp/wasm_build_env.txt @@ -1,5 +1,5 @@ -> undici@7.29.0 build:wasm +> undici@7.29.1 build:wasm > node build/wasm.js --docker > docker run --rm --platform=linux/x86_64 --user 1001:1001 --mount type=bind,source=/home/runner/work/node/node/deps/undici/src/lib/llhttp,target=/home/node/build/lib/llhttp --mount type=bind,source=/home/runner/work/node/node/deps/undici/src/build,target=/home/node/build/build --mount type=bind,source=/home/runner/work/node/node/deps/undici/src/deps,target=/home/node/build/deps -t ghcr.io/nodejs/wasm-builder@sha256:975f391d907e42a75b8c72eb77c782181e941608687d4d8694c3e9df415a0970 node build/wasm.js diff --git a/deps/undici/src/lib/web/eventsource/eventsource-stream.js b/deps/undici/src/lib/web/eventsource/eventsource-stream.js index d24e8f6a1b1a..7b9e2f8cbba8 100644 --- a/deps/undici/src/lib/web/eventsource/eventsource-stream.js +++ b/deps/undici/src/lib/web/eventsource/eventsource-stream.js @@ -23,6 +23,49 @@ const COLON = 0x3A */ const SPACE = 0x20 +const DATA = Buffer.from('data') +const EVENT = Buffer.from('event') +const ID = Buffer.from('id') +const RETRY = Buffer.from('retry') + +function isASCIINumberBytes (buffer, start) { + if (start >= buffer.length) { + return false + } + + for (let i = start; i < buffer.length; i++) { + if (buffer[i] < 0x30 || buffer[i] > 0x39) { + return false + } + } + + return true +} + +function isValidLastEventIdBytes (buffer, start) { + for (let i = start; i < buffer.length; i++) { + if (buffer[i] === 0x00) { + return false + } + } + + return true +} + +function isFieldName (line, length, field) { + if (length !== field.length) { + return false + } + + for (let i = 0; i < length; i++) { + if (line[i] !== field[i]) { + return false + } + } + + return true +} + /** * @typedef {object} EventSourceStreamEvent * @type {object} @@ -63,11 +106,14 @@ class EventSourceStream extends Transform { eventEndCheck = false /** - * @type {Buffer|null} + * @type {Buffer[]} */ - buffer = null + chunks = [] + chunkIndex = 0 pos = 0 + lineChunkIndex = 0 + linePos = 0 event = { data: undefined, @@ -107,92 +153,20 @@ class EventSourceStream extends Transform { return } - // Cache the chunk in the buffer, as the data might not be complete while - // processing it - // TODO: Investigate if there is a more performant way to handle - // incoming chunks - // see: https://github.com/nodejs/undici/issues/2630 - if (this.buffer) { - this.buffer = Buffer.concat([this.buffer, chunk]) - } else { - this.buffer = chunk - } + this.chunks.push(chunk) // Strip leading byte-order-mark if we opened the stream and started // the processing of the incoming data if (this.checkBOM) { - switch (this.buffer.length) { - case 1: - // Check if the first byte is the same as the first byte of the BOM - if (this.buffer[0] === BOM[0]) { - // If it is, we need to wait for more data - callback() - return - } - // Set the checkBOM flag to false as we don't need to check for the - // BOM anymore - this.checkBOM = false - - // The buffer only contains one byte so we need to wait for more data - callback() - return - case 2: - // Check if the first two bytes are the same as the first two bytes - // of the BOM - if ( - this.buffer[0] === BOM[0] && - this.buffer[1] === BOM[1] - ) { - // If it is, we need to wait for more data, because the third byte - // is needed to determine if it is the BOM or not - callback() - return - } - - // Set the checkBOM flag to false as we don't need to check for the - // BOM anymore - this.checkBOM = false - break - case 3: - // Check if the first three bytes are the same as the first three - // bytes of the BOM - if ( - this.buffer[0] === BOM[0] && - this.buffer[1] === BOM[1] && - this.buffer[2] === BOM[2] - ) { - // If it is, we can drop the buffered data, as it is only the BOM - this.buffer = Buffer.alloc(0) - // Set the checkBOM flag to false as we don't need to check for the - // BOM anymore - this.checkBOM = false - - // Await more data - callback() - return - } - // If it is not the BOM, we can start processing the data - this.checkBOM = false - break - default: - // The buffer is longer than 3 bytes, so we can drop the BOM if it is - // present - if ( - this.buffer[0] === BOM[0] && - this.buffer[1] === BOM[1] && - this.buffer[2] === BOM[2] - ) { - // Remove the BOM from the buffer - this.buffer = this.buffer.subarray(3) - } - - // Set the checkBOM flag to false as we don't need to check for the - this.checkBOM = false - break + if (this.handleBOM()) { + callback() + return } } - while (this.pos < this.buffer.length) { + while (this.hasCurrentByte()) { + const byte = this.currentByte() + // If the previous line ended with an end-of-line, we need to check // if the next character is also an end-of-line. if (this.eventEndCheck) { @@ -205,10 +179,9 @@ class EventSourceStream extends Transform { if (this.crlfCheck) { // If the current character is a line feed, we can remove it // from the buffer and reset the crlfCheck flag - if (this.buffer[this.pos] === LF) { - this.buffer = this.buffer.subarray(this.pos + 1) - this.pos = 0 + if (byte === LF) { this.crlfCheck = false + this.consumeCurrentByte() // It is possible that the line feed is not the end of the // event. We need to check if the next character is an @@ -224,19 +197,17 @@ class EventSourceStream extends Transform { this.crlfCheck = false } - if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (byte === LF || byte === CR) { // If the current character is a carriage return, we need to // set the crlfCheck flag to true, as we need to check if the // next character is a line feed so we can remove it from the // buffer - if (this.buffer[this.pos] === CR) { + if (byte === CR) { this.crlfCheck = true } - this.buffer = this.buffer.subarray(this.pos + 1) - this.pos = 0 - if ( - this.event.data !== undefined || this.event.event || this.event.id !== undefined || this.event.retry) { + this.consumeCurrentByte() + if (this.hasPendingEvent()) { this.processEvent(this.event) } this.clearEvent() @@ -250,22 +221,18 @@ class EventSourceStream extends Transform { // If the current character is an end-of-line, we can process the // line - if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (byte === LF || byte === CR) { // If the current character is a carriage return, we need to // set the crlfCheck flag to true, as we need to check if the // next character is a line feed - if (this.buffer[this.pos] === CR) { + if (byte === CR) { this.crlfCheck = true } // In any case, we can process the line as we reached an // end-of-line character - this.parseLine(this.buffer.subarray(0, this.pos), this.event) - - // Remove the processed line from the buffer - this.buffer = this.buffer.subarray(this.pos + 1) - // Reset the position as we removed the processed line from the buffer - this.pos = 0 + this.parseLine(this.readLine(), this.event) + this.consumeCurrentByte() // A line was processed and this could be the end of the event. We need // to check if the next line is empty to determine if the event is // finished. @@ -273,7 +240,7 @@ class EventSourceStream extends Transform { continue } - this.pos++ + this.advanceCursor() } callback() @@ -298,64 +265,53 @@ class EventSourceStream extends Transform { return } - let field = '' - let value = '' + let fieldLength = line.length + let valueStart = line.length // If the line contains a U+003A COLON character (:) if (colonPosition !== -1) { - // Collect the characters on the line before the first U+003A COLON - // character (:), and let field be that string. - // TODO: Investigate if there is a more performant way to extract the - // field - // see: https://github.com/nodejs/undici/issues/2630 - field = line.subarray(0, colonPosition).toString('utf8') + fieldLength = colonPosition // Collect the characters on the line after the first U+003A COLON // character (:), and let value be that string. // If value starts with a U+0020 SPACE character, remove it from value. - let valueStart = colonPosition + 1 + valueStart = colonPosition + 1 if (line[valueStart] === SPACE) { ++valueStart } - // TODO: Investigate if there is a more performant way to extract the - // value - // see: https://github.com/nodejs/undici/issues/2630 - value = line.subarray(valueStart).toString('utf8') - - // Otherwise, the string is not empty but does not contain a U+003A COLON - // character (:) - } else { - // Process the field using the steps described below, using the whole - // line as the field name, and the empty string as the field value. - field = line.toString('utf8') - value = '' } - // Modify the event with the field name and value. The value is also - // decoded as UTF-8 - switch (field) { - case 'data': - if (event[field] === undefined) { - event[field] = value - } else { - event[field] += `\n${value}` - } - break - case 'retry': - if (isASCIINumber(value)) { - event[field] = value - } - break - case 'id': - if (isValidLastEventId(value)) { - event[field] = value - } - break - case 'event': - if (value.length > 0) { - event[field] = value - } - break + if (isFieldName(line, fieldLength, DATA)) { + const value = line.toString('utf8', valueStart) + + if (event.data === undefined) { + event.data = value + } else { + event.data += `\n${value}` + } + return + } + + if (isFieldName(line, fieldLength, RETRY)) { + if (isASCIINumberBytes(line, valueStart)) { + event.retry = line.toString('utf8', valueStart) + } + return + } + + if (isFieldName(line, fieldLength, ID)) { + if (isValidLastEventIdBytes(line, valueStart)) { + event.id = line.toString('utf8', valueStart) + } + return + } + + if (isFieldName(line, fieldLength, EVENT)) { + const value = line.toString('utf8', valueStart) + + if (value.length > 0) { + event.event = value + } } } @@ -385,12 +341,151 @@ class EventSourceStream extends Transform { } clearEvent () { - this.event = { - data: undefined, - event: undefined, - id: undefined, - retry: undefined + this.event.data = undefined + this.event.event = undefined + this.event.id = undefined + this.event.retry = undefined + } + + hasPendingEvent () { + return this.event.data !== undefined || + this.event.event !== undefined || + this.event.id !== undefined || + this.event.retry !== undefined + } + + hasCurrentByte () { + return this.chunkIndex < this.chunks.length && + this.pos < this.chunks[this.chunkIndex].length + } + + currentByte () { + return this.chunks[this.chunkIndex][this.pos] + } + + consumeCurrentByte () { + this.advanceCursor() + this.syncLineStartToCursor() + } + + advanceCursor () { + this.pos++ + + while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { + this.chunkIndex++ + this.pos = 0 + } + } + + syncLineStartToCursor () { + this.lineChunkIndex = this.chunkIndex + this.linePos = this.pos + this.dropConsumedChunks() + } + + dropConsumedChunks () { + while (this.lineChunkIndex > 0) { + this.chunks.shift() + this.lineChunkIndex-- + this.chunkIndex-- + } + + if (this.chunkIndex === this.chunks.length) { + this.chunks.length = 0 + this.chunkIndex = 0 + this.pos = 0 + this.lineChunkIndex = 0 + this.linePos = 0 + } + } + + readLine () { + if (this.lineChunkIndex === this.chunkIndex) { + return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos) + } + + const chunks = [] + let length = 0 + + for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { + const chunk = this.chunks[i] + const start = i === this.lineChunkIndex ? this.linePos : 0 + const end = i === this.chunkIndex ? this.pos : chunk.length + const slice = chunk.subarray(start, end) + length += slice.length + chunks.push(slice) + } + + return Buffer.concat(chunks, length) + } + + peekBufferedByte (offset) { + let chunkIndex = this.lineChunkIndex + let pos = this.linePos + + while (chunkIndex < this.chunks.length) { + const chunk = this.chunks[chunkIndex] + const remaining = chunk.length - pos + + if (offset < remaining) { + return chunk[pos + offset] + } + + offset -= remaining + chunkIndex++ + pos = 0 + } + } + + discardLeadingBytes (count) { + while (count > 0 && this.lineChunkIndex < this.chunks.length) { + const chunk = this.chunks[this.lineChunkIndex] + const remaining = chunk.length - this.linePos + + if (count < remaining) { + this.linePos += count + count = 0 + } else { + count -= remaining + this.lineChunkIndex++ + this.linePos = 0 + } + } + + this.chunkIndex = this.lineChunkIndex + this.pos = this.linePos + this.dropConsumedChunks() + } + + handleBOM () { + const first = this.peekBufferedByte(0) + const second = this.peekBufferedByte(1) + const third = this.peekBufferedByte(2) + + if (second === undefined) { + if (first === BOM[0]) { + return true + } + + this.checkBOM = false + return true + } + + if (third === undefined) { + if (first === BOM[0] && second === BOM[1]) { + return true + } + + this.checkBOM = false + return false } + + if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { + this.discardLeadingBytes(3) + } + + this.checkBOM = false + return !this.hasCurrentByte() } } diff --git a/deps/undici/src/lib/web/websocket/connection.js b/deps/undici/src/lib/web/websocket/connection.js index 4ecc8a195fcd..cd95d2ca76ec 100644 --- a/deps/undici/src/lib/web/websocket/connection.js +++ b/deps/undici/src/lib/web/websocket/connection.js @@ -200,7 +200,7 @@ function establishWebSocketConnection (url, protocols, client, handler, options) // is specified, the server needs to include the same field and one of // the selected subprotocol values in its response for the connection to // be established. - if (!requestProtocols.includes(secProtocol)) { + if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { failWebsocketConnection(handler, 1002, 'Protocol was not set in the opening handshake.') return } diff --git a/deps/undici/src/lib/web/websocket/permessage-deflate.js b/deps/undici/src/lib/web/websocket/permessage-deflate.js index 6a6e43899c5a..0b3d493db820 100644 --- a/deps/undici/src/lib/web/websocket/permessage-deflate.js +++ b/deps/undici/src/lib/web/websocket/permessage-deflate.js @@ -63,7 +63,12 @@ class PerMessageDeflate { if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) { callback(new MessageSizeExceededError()) + // The inflater may still hold buffered input that can emit a late + // zlib error. Remove the data listener, then deterministically stop + // the stream so a subsequent 'error' cannot fire without a listener + // (which would terminate the process as an unhandled error event). this.#inflate.removeAllListeners() + this.#inflate.destroy() this.#inflate = null return } diff --git a/deps/undici/src/lib/web/websocket/stream/websocketstream.js b/deps/undici/src/lib/web/websocket/stream/websocketstream.js index 1da0292b4650..32437cb33a75 100644 --- a/deps/undici/src/lib/web/websocket/stream/websocketstream.js +++ b/deps/undici/src/lib/web/websocket/stream/websocketstream.js @@ -34,9 +34,9 @@ class WebSocketStream { /** @type {ReadableStreamDefaultController} */ #readableStreamController - // Each WebSocketStream object has an associated writable stream , which is a WritableStream . - /** @type {WritableStream} */ - #writableStream + // Retain the controller so the writable stream can be errored while locked. + /** @type {WritableStreamDefaultController} */ + #writableStreamController // Each WebSocketStream object has an associated boolean handshake aborted , which is initially false. #handshakeAborted = false @@ -300,6 +300,9 @@ class WebSocketStream { // 12. Let writable be a new WritableStream . // 13. Set up writable with writeAlgorithm , closeAlgorithm , and abortAlgorithm . const writable = new WritableStream({ + start: (controller) => { + this.#writableStreamController = controller + }, write: (chunk) => this.#write(chunk), close: () => closeWebSocketConnection(this.#handler, null, null), abort: (reason) => this.#closeUsingReason(reason) @@ -308,9 +311,6 @@ class WebSocketStream { // Set stream ’s readable stream to readable . this.#readableStream = readable - // Set stream ’s writable stream to writable . - this.#writableStream = writable - // Resolve stream ’s opened promise with WebSocketOpenInfo «[ " extensions " → extensions , " protocol " → protocol , " readable " → readable , " writable " → writable ]». this.#openedPromise.resolve({ extensions, @@ -396,9 +396,7 @@ class WebSocketStream { this.#readableStreamController.close() // 6.2. Error stream ’s writable stream with an " InvalidStateError " DOMException indicating that a closed WebSocketStream cannot be written to. - if (!this.#writableStream.locked) { - this.#writableStream.abort(new DOMException('A closed WebSocketStream cannot be written to', 'InvalidStateError')) - } + this.#writableStreamController.error(new DOMException('A closed WebSocketStream cannot be written to', 'InvalidStateError')) // 6.3. Resolve stream ’s closed promise with WebSocketCloseInfo «[ " closeCode " → code , " reason " → reason ]». this.#closedPromise.resolve({ @@ -415,7 +413,7 @@ class WebSocketStream { this.#readableStreamController?.error(error) // 7.3. Error stream ’s writable stream with error . - this.#writableStream?.abort(error) + this.#writableStreamController?.error(error) // 7.4. Reject stream ’s closed promise with error . this.#closedPromise.reject(error) diff --git a/deps/undici/src/package-lock.json b/deps/undici/src/package-lock.json index 703996c31cf5..9e3612190736 100644 --- a/deps/undici/src/package-lock.json +++ b/deps/undici/src/package-lock.json @@ -1,12 +1,12 @@ { "name": "undici", - "version": "7.29.0", + "version": "7.29.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "undici", - "version": "7.29.0", + "version": "7.29.1", "license": "MIT", "devDependencies": { "@fastify/busboy": "3.2.0", @@ -132,14 +132,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", - "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -262,13 +262,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.29.7" + "@babel/types": "^7.29.8" }, "bin": { "parser": "bin/babel-parser.js" @@ -532,18 +532,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", - "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", + "@babel/generator": "^7.29.8", "@babel/helper-globals": "^7.29.7", - "@babel/parser": "^7.29.7", + "@babel/parser": "^7.29.8", "@babel/template": "^7.29.7", - "@babel/types": "^7.29.7", + "@babel/types": "^7.29.8", "debug": "^4.3.1" }, "engines": { @@ -551,9 +551,9 @@ } }, "node_modules/@babel/types": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", - "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", "dev": true, "license": "MIT", "dependencies": { @@ -1148,9 +1148,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", - "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.7.tgz", + "integrity": "sha512-F42g89Qd5oAWtp0k0nnSrjziAKza7w8SVT4mStc18LZMaRb4J1HQAHLCalEtDCxrTuksx7NU9qsmeLwpOfPqWw==", "dev": true, "license": "MIT", "dependencies": { @@ -1160,7 +1160,7 @@ "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.3.0", + "js-yaml": "^4.3.2", "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" }, @@ -1352,9 +1352,9 @@ } }, "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.0.tgz", - "integrity": "sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==", + "version": "3.15.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.2.tgz", + "integrity": "sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==", "dev": true, "license": "MIT", "dependencies": { @@ -1438,17 +1438,17 @@ } }, "node_modules/@jest/console": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.4.1.tgz", - "integrity": "sha512-v3bhyxUh9Hgmo5p6hAOXe14/R3ZxZDOsvHleh4B07z3m/x4/ngPUXEm9XwK4sF4u+f+P2ORb0Ge+MgpaqRMVDA==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.5.1.tgz", + "integrity": "sha512-u5Ncuc+gXVUwjNMFQOnphHo2Qx2DxyC8Dvpmf4HCx4y0kvSkRRNiQYRixrvOP4V7y52JcSuNxqochCt0PpdHVg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.4.1", + "@jest/types": "30.5.1", "@types/node": "*", "chalk": "^4.1.2", - "jest-message-util": "30.4.1", - "jest-util": "30.4.1", + "jest-message-util": "30.5.1", + "jest-util": "30.5.1", "slash": "^3.0.0" }, "engines": { @@ -1456,18 +1456,18 @@ } }, "node_modules/@jest/core": { - "version": "30.4.2", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.4.2.tgz", - "integrity": "sha512-TZJA6cPJUFxoWhxaLo8t0VX/MZX2wPWr0uIDvLSHIvN4gu9h02vSzqI2kBADG1ExqQlC+cY09xKMSreivvrChQ==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.5.1.tgz", + "integrity": "sha512-BL9g6CJUUhIbdoAflz/Va658erSSXUIvU8XUYiWNTbZljJjZ5yaC9EJ9/dQ19rpbYV3ZOK4sBACqhPaTyhoUIA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/console": "30.4.1", - "@jest/pattern": "30.4.0", - "@jest/reporters": "30.4.1", - "@jest/test-result": "30.4.1", - "@jest/transform": "30.4.1", - "@jest/types": "30.4.1", + "@jest/console": "30.5.1", + "@jest/pattern": "30.5.0", + "@jest/reporters": "30.5.1", + "@jest/test-result": "30.5.1", + "@jest/transform": "30.5.1", + "@jest/types": "30.5.1", "@types/node": "*", "ansi-escapes": "^4.3.2", "chalk": "^4.1.2", @@ -1475,20 +1475,20 @@ "exit-x": "^0.2.2", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.11", - "jest-changed-files": "30.4.1", - "jest-config": "30.4.2", - "jest-haste-map": "30.4.1", - "jest-message-util": "30.4.1", - "jest-regex-util": "30.4.0", - "jest-resolve": "30.4.1", - "jest-resolve-dependencies": "30.4.2", - "jest-runner": "30.4.2", - "jest-runtime": "30.4.2", - "jest-snapshot": "30.4.1", - "jest-util": "30.4.1", - "jest-validate": "30.4.1", - "jest-watcher": "30.4.1", - "pretty-format": "30.4.1", + "jest-changed-files": "30.5.1", + "jest-config": "30.5.1", + "jest-haste-map": "30.5.1", + "jest-message-util": "30.5.1", + "jest-regex-util": "30.5.0", + "jest-resolve": "30.5.1", + "jest-resolve-dependencies": "30.5.1", + "jest-runner": "30.5.1", + "jest-runtime": "30.5.1", + "jest-snapshot": "30.5.1", + "jest-util": "30.5.1", + "jest-validate": "30.5.1", + "jest-watcher": "30.5.1", + "pretty-format": "30.5.1", "slash": "^3.0.0" }, "engines": { @@ -1504,9 +1504,9 @@ } }, "node_modules/@jest/diff-sequences": { - "version": "30.4.0", - "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.4.0.tgz", - "integrity": "sha512-zOpzlfUs45l6u7jm39qr87JCHUDsaeCtvL+kQe/Vn9jSnRB4/5IPXISm0h9I1vZW/o00Kn4UTJ2MOlhnUGwv3g==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.5.0.tgz", + "integrity": "sha512-OsqBjHXCn8cadasoAZBP6nWYvMsRhpMzGXTpxJ5aO04NlbdhIz+FVe3q49l0AwVhsz/cEmIpBes6gAFl1/dWQg==", "dev": true, "license": "MIT", "engines": { @@ -1514,61 +1514,61 @@ } }, "node_modules/@jest/environment": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.4.1.tgz", - "integrity": "sha512-AK9yNRqgKxiabqMoe4oW+3/TSSeV8vkdC7BGaxZdU0AFXfOpofTLqdru2GXKZghP3sdgwE9XXpnVwfZ8JnFV4w==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.5.1.tgz", + "integrity": "sha512-eYJAkOsrpwDXPcoLNEG6lN9Zo3Cy35pxnVQD74vyIfsi/Q8wB/lZFsEjU4wrecOgT4ZviQDZaX/cFIJyMdMxTw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/fake-timers": "30.4.1", - "@jest/types": "30.4.1", + "@jest/fake-timers": "30.5.1", + "@jest/types": "30.5.1", "@types/node": "*", - "jest-mock": "30.4.1" + "jest-mock": "30.5.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/expect": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.4.1.tgz", - "integrity": "sha512-ginrj6TMgh2GshLUGCjO94Ptx9HhdZA/I6A9iUfyeLKFtdAjnKzHDgzgP9HYQgbxM1lbXScQ2eUBz2lGeVDPWA==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.5.1.tgz", + "integrity": "sha512-uOGd40P/COyUp9xHf5jeGiGJC2/ANg+2+Tk9/xN5/LxmlY/r/gxsPrx3DTEtaRZsLAX4wgNSLEDELZ5bmVs2bA==", "dev": true, "license": "MIT", "dependencies": { - "expect": "30.4.1", - "jest-snapshot": "30.4.1" + "expect": "30.5.1", + "jest-snapshot": "30.5.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/expect-utils": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.4.1.tgz", - "integrity": "sha512-ZBn5CglH8fBsQsvs4VWNzD4aWfUYks+IdOOQU3MEK71ol/BcVm+P+rtb1KpiFBpSWSCE27uOahyyf1vfqOVbcQ==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.5.1.tgz", + "integrity": "sha512-WcRWhHQdTMRDpyWKZ/6MINBmovI7zeD+bL8wFjCncRV3NQOwKy1X45IfyblfHR4k/XciIlNEdFL9QjFO+HNKOg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/get-type": "30.1.0" + "@jest/get-type": "30.5.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/fake-timers": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.4.1.tgz", - "integrity": "sha512-iW5umdmfPeWzehrVhugFQZqCchSCud5S1l2YT0O9ZhjRR0ExclANDZkiSBwzqtnlOn0J1JXvO+HZ6rkuyOVOgQ==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.5.1.tgz", + "integrity": "sha512-rEkV6YzpBXo/L9cnj2ibyuYZuyGiNWaPUsyCu3HYJbqCV4jnEiKmf7hId20z8eKjZ0JQ9jtIYKxRSmYB/OYSsA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.4.1", + "@jest/types": "30.5.1", "@sinonjs/fake-timers": "^15.4.0", "@types/node": "*", - "jest-message-util": "30.4.1", - "jest-mock": "30.4.1", - "jest-util": "30.4.1" + "jest-message-util": "30.5.1", + "jest-mock": "30.5.1", + "jest-util": "30.5.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -1585,9 +1585,9 @@ } }, "node_modules/@jest/get-type": { - "version": "30.1.0", - "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", - "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.5.0.tgz", + "integrity": "sha512-9/2VUPitAjmBzbvDvqrxmvB7BzWsBW0WmkkojX1ODuxX1NLGxx9gfaZpHB0z8DtJ9uhGNmZG/VXBhf8uO0OV8Q==", "dev": true, "license": "MIT", "engines": { @@ -1595,62 +1595,78 @@ } }, "node_modules/@jest/globals": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.4.1.tgz", - "integrity": "sha512-ZbuY4cmXC8DkxYjfvT2DbcHWL2T6vmsMhXCDcmTB2T0y0gaezBI77ufq5ZAIdcRkYZ7NEQEDg1xFeKbxUJ5v5Q==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.5.1.tgz", + "integrity": "sha512-VhqvQ251XIC7pk46YymI3HCeBLOdvriDw9zibekodAHEwoVvbVVgpU5H13GvmyOAzxtZCfsm1uvzqkaqJf2I+g==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "30.4.1", - "@jest/expect": "30.4.1", - "@jest/types": "30.4.1", - "jest-mock": "30.4.1" + "@jest/environment": "30.5.1", + "@jest/expect": "30.5.1", + "@jest/types": "30.5.1", + "jest-mock": "30.5.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/pattern": { - "version": "30.4.0", - "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.4.0.tgz", - "integrity": "sha512-RAWn3+f9u8BsHijKJ71uHcFp6vmyEt6VvoWXkl6hKF3qVIuWNmudVjg12DlBPGup/frIl5UcUlH5HfEuvHpEXg==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.5.0.tgz", + "integrity": "sha512-HdNQYSdRTEBNrginaqzQtTjG0HRMfrra/z6Ok7uL3S87vSlarIVohEsJsSj5edu3MiHoHjAkvPROz5ZjoKai+w==", "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", - "jest-regex-util": "30.4.0" + "jest-regex-util": "30.5.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/@jest/react-is-18": { + "name": "react-is", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/react-is-19": { + "name": "react-is", + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.8.tgz", + "integrity": "sha512-s5un28nYxKJw5gvUHyW5PCC28CvBqLu9r3cWgzHT4Vo/5fqqkFcdRYsGcKf50WMPpjjFZS5d76fn3YCo2njKwQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@jest/reporters": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.4.1.tgz", - "integrity": "sha512-/SnkPCzEQpUaBH81kjdEdDdo2WZl5hxw+BmLDGWjRkm8o7XlhjwsU36cqwe5PGBE5WYpBvDzRSdXx9rbGuJtNA==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.5.1.tgz", + "integrity": "sha512-RbUXIfv85KxitJn4l3MpAoMilkvXe2QCO5lXxHWftywo/VdZ5vkEoHRDgphcxP6qmoIkUaN8/UZj6NhdkIFdJg==", "dev": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "30.4.1", - "@jest/test-result": "30.4.1", - "@jest/transform": "30.4.1", - "@jest/types": "30.4.1", - "@jridgewell/trace-mapping": "^0.3.25", + "@jest/console": "30.5.1", + "@jest/test-result": "30.5.1", + "@jest/transform": "30.5.1", + "@jest/types": "30.5.1", + "@jridgewell/trace-mapping": "^0.3.31", "@types/node": "*", "chalk": "^4.1.2", "collect-v8-coverage": "^1.0.2", "exit-x": "^0.2.2", - "glob": "^10.5.0", + "glob": "^13.0.6", "graceful-fs": "^4.2.11", "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-instrument": "^6.0.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^5.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "30.4.1", - "jest-util": "30.4.1", - "jest-worker": "30.4.1", + "jest-message-util": "30.5.1", + "jest-util": "30.5.1", + "jest-worker": "30.5.1", "slash": "^3.0.0", "string-length": "^4.0.2", "v8-to-istanbul": "^9.0.1" @@ -1674,10 +1690,94 @@ "dev": true, "license": "MIT" }, + "node_modules/@jest/reporters/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@jest/reporters/node_modules/brace-expansion": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@jest/reporters/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/reporters/node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@jest/reporters/node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/reporters/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@jest/schemas": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", - "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.5.0.tgz", + "integrity": "sha512-/hunigyNpc4RCjC0VaW3f5RCUZVM2+WQ65qP7z083Gmvac7or2LI50XVNOtE4YPgBpV0yxYiAgorAPGniCoJmg==", "dev": true, "license": "MIT", "dependencies": { @@ -1688,13 +1788,13 @@ } }, "node_modules/@jest/snapshot-utils": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.4.1.tgz", - "integrity": "sha512-ObY4ljvQ95mt6iwKtVLetR/4yXiAgl3H4nJxhztr0MTjrN97TwDYrnCp/kF60Ec9HdhkWTHSu+Hg05aXfngpOA==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.5.1.tgz", + "integrity": "sha512-V3wnxNtiVmw5PPVg433Cn3VdXnsOeu/ofLw3KC04Bn2y1wIlU5kozXQn48rhrgj/02LrCVtntTEF1yBha0XSUw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.4.1", + "@jest/types": "30.5.1", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "natural-compare": "^1.4.0" @@ -1704,14 +1804,15 @@ } }, "node_modules/@jest/source-map": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", - "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.5.0.tgz", + "integrity": "sha512-xWpTJP9D0bDFGbPGT8XuWSwwha/iHADyyKzUnMx4UbdgnHugxrDaQFO4RZ8x4ZsFzRP6pNii8uvlgKCDxCIuDg==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", + "@jridgewell/trace-mapping": "^0.3.31", "callsites": "^3.1.0", + "convert-source-map": "^2.0.0", "graceful-fs": "^4.2.11" }, "engines": { @@ -1719,14 +1820,14 @@ } }, "node_modules/@jest/test-result": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.4.1.tgz", - "integrity": "sha512-/ZG7pgEiOmmWkN9TplKbOu4id2N5lh7FHwRwlkgBVAzGdRH+OkkQ8wX/kIxg4zmd3ZQvAL1RwL2yWsvNYYECTw==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.5.1.tgz", + "integrity": "sha512-A/1S6ZBdpic50E0pxLgvaB9XNPL4k7AksmG69OO2oiotxciWZwHkbOec+qbIi+uUtIIByOVlXJUl97oZUsz+Jw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/console": "30.4.1", - "@jest/types": "30.4.1", + "@jest/console": "30.5.1", + "@jest/types": "30.5.1", "@types/istanbul-lib-coverage": "^2.0.6", "collect-v8-coverage": "^1.0.2" }, @@ -1735,15 +1836,15 @@ } }, "node_modules/@jest/test-sequencer": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.4.1.tgz", - "integrity": "sha512-PeYE+4td5rKjoRPxztObrXU+H8hsjZfxKMXOcmrr34JerSyB/ROOxbbicz8B7A5j9R9VayDnVPvBmedqCsFCdw==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.5.1.tgz", + "integrity": "sha512-SHcPnrjdVRYJv6y6l4JUTy4Jccu7zmO6BmiOfOA34UiVBto22s19WiDC0A/2qfM7MWB/qdcoqfSIRMitpjTT4A==", "dev": true, "license": "MIT", "dependencies": { - "@jest/test-result": "30.4.1", + "@jest/test-result": "30.5.1", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.4.1", + "jest-haste-map": "30.5.1", "slash": "^3.0.0" }, "engines": { @@ -1751,23 +1852,23 @@ } }, "node_modules/@jest/transform": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.4.1.tgz", - "integrity": "sha512-Wz0LyktlTvRefoymh+n64hQ84KNXsRGcwdoZ8CSa0Ea+fgYcHZlnk+hDP7v2MS7il2bQ5uTEIxf4/NNfhMN4KQ==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.5.1.tgz", + "integrity": "sha512-EDnDhn0jleU9ZhpVoA4gvqw+Ev0iw/r5upNT2b79RiwiaTiYAMMhvNJP3lmocjIe5J2ZkoNr0B3K/J6O5GIm4Q==", "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", - "@jest/types": "30.4.1", - "@jridgewell/trace-mapping": "^0.3.25", - "babel-plugin-istanbul": "^7.0.1", + "@jest/types": "30.5.1", + "@jridgewell/trace-mapping": "^0.3.31", + "babel-plugin-istanbul": "^8.0.0", "chalk": "^4.1.2", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.4.1", - "jest-regex-util": "30.4.0", - "jest-util": "30.4.1", + "jest-haste-map": "30.5.1", + "jest-regex-util": "30.5.0", + "jest-util": "30.5.1", "pirates": "^4.0.7", "slash": "^3.0.0", "write-file-atomic": "^5.0.1" @@ -1777,14 +1878,14 @@ } }, "node_modules/@jest/types": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.4.1.tgz", - "integrity": "sha512-f1x/vJXIfjOlEmejYpbkbgw1gOqpPECwMvMEtBqe47j7H2Hg8h8w3o3ikhSXq3MI15kg+oQ0exWO0uCtTNJLoQ==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.5.1.tgz", + "integrity": "sha512-LvVYn83nnXPl+Rg98nvcFgjx6nRMTArhSn6RAX/w3ELn54S8A42TYZvsCMdGUqTM8S0wyXbtlQdU6Hi6dykj9g==", "dev": true, "license": "MIT", "dependencies": { - "@jest/pattern": "30.4.0", - "@jest/schemas": "30.4.1", + "@jest/pattern": "30.5.0", + "@jest/schemas": "30.5.0", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", @@ -1828,9 +1929,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "dev": true, "license": "MIT" }, @@ -1874,22 +1975,25 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", - "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.3.tgz", + "integrity": "sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q==", "dev": true, "license": "MIT", "optional": true, "dependencies": { "@tybys/wasm-util": "^0.10.3" }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + }, "funding": { "type": "github", "url": "https://github.com/sponsors/Brooooooklyn" }, "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" + "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" } }, "node_modules/@nodelib/fs.scandir": { @@ -1940,6 +2044,311 @@ "node": ">=12.4.0" } }, + "node_modules/@parcel/watcher": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.6.0.tgz", + "integrity": "sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.6.0", + "@parcel/watcher-darwin-arm64": "2.6.0", + "@parcel/watcher-darwin-x64": "2.6.0", + "@parcel/watcher-freebsd-x64": "2.6.0", + "@parcel/watcher-linux-arm-glibc": "2.6.0", + "@parcel/watcher-linux-arm-musl": "2.6.0", + "@parcel/watcher-linux-arm64-glibc": "2.6.0", + "@parcel/watcher-linux-arm64-musl": "2.6.0", + "@parcel/watcher-linux-x64-glibc": "2.6.0", + "@parcel/watcher-linux-x64-musl": "2.6.0", + "@parcel/watcher-win32-arm64": "2.6.0", + "@parcel/watcher-win32-x64": "2.6.0" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.6.0.tgz", + "integrity": "sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.6.0.tgz", + "integrity": "sha512-Y3QV0gl7Q1zbfueunkWIERICbEojQFCgpyG7YqOGNFLsckXyI1xu9mAIUpKY9QBYzBtSkN8dBPwd3yiAO9ovMw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.6.0.tgz", + "integrity": "sha512-Ohv6OpzhUfKYD7Beb8kDvG0jbIxORCYY1JRdZnaBtnjjkJxgD7ZVL0nw2sCYd0yTMKTvz3nnTnOF3cDifK+kvw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.6.0.tgz", + "integrity": "sha512-5HmXvDgs8VK+74jF9y9/2FE3/OnlcKmc56tjmSrEuZjpSZOGL+fvAu+HKJBdPs9uwoP2hE6TlSUpXZ/C5jUFmQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.6.0.tgz", + "integrity": "sha512-Ps/hui3A+vMbjdqlqAowK2ZL8+BO8dBjxeWXj6npTBs3jx4wWmbPpaLuqwrQrSqIVMCnpWo238bJ1U37GhQOYg==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.6.0.tgz", + "integrity": "sha512-9c6AUHgHoG+IY88MRIHupztQiQnrbqHYQjkM2btA+Bf/wQnQMuiD0Wfk1EVv3TlNT3x41uU71rn6E4xh/+zvkw==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.6.0.tgz", + "integrity": "sha512-yHRqS2owEXe6Hic9z6Mh1ECsCd+ODVOGvZDyciqRd21+v+o+DnXMOrw50DSpIG2sb8GPEaPPmfeCAWKPJdq46g==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.6.0.tgz", + "integrity": "sha512-WhB2e/V7rqdHHWZusBSPuy5Ei8S6lSz6FE5TKKQz5h3a0O+C+mhY7vxU9b/stqvMb8beLnPY82ZrFTLKs+SrKA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.6.0.tgz", + "integrity": "sha512-ulGE6x6Oz6iAwg75T8YQSoguBWasniIbX+QWpaYPcCnDOpdWX3k+4xbEYPZVLxOuoJI+svJJPD3sEj8G7lrQ3A==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.6.0.tgz", + "integrity": "sha512-tkBYKt7YQrjIJWYDnto2YgO8MRkjlMTSNoRHzsXinBqbLdeOM3L32wPZJvIZxqaLMfSlS/4sUjH/6STVP/XDLw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.6.0.tgz", + "integrity": "sha512-gIZAP23jaHjGWasY/TY6yL7NHFClf0Ga7FN+iINvk+KN94rhm94lYZhFsbYFNcA04/onvGD9kKmiJLJB2HbNwQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.6.0.tgz", + "integrity": "sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -2209,17 +2618,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.65.0.tgz", - "integrity": "sha512-IEgob78X12rHpUmtcwFsXhZdVGJtwTVP8FiCLZkR6GlYVrl2PcuB+KhCE5BlVC/eQpQnu8WXRtkHZuPar+gCRA==", + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.69.0.tgz", + "integrity": "sha512-t5jQTKPIgVW1PE6dR6H6Qz5gm8zjMlX5/2gRaOGd9eO6V7J+tQc6iWKukEe7dY8u9HyYasQ0yfF0/FSSTEO2gA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.65.0", - "@typescript-eslint/type-utils": "8.65.0", - "@typescript-eslint/utils": "8.65.0", - "@typescript-eslint/visitor-keys": "8.65.0", + "@typescript-eslint/scope-manager": "8.69.0", + "@typescript-eslint/type-utils": "8.69.0", + "@typescript-eslint/utils": "8.69.0", + "@typescript-eslint/visitor-keys": "8.69.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -2232,15 +2641,15 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.65.0", + "@typescript-eslint/parser": "^8.69.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", - "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.8.tgz", + "integrity": "sha512-YYNsSlXBjMk92SKnkwvB5LOVSa6OznlFUGcsvrFgNJbJCd0M1XKeFVRc8ZByeCqz32FivYNHJVooLmdqrmvp/Q==", "dev": true, "license": "MIT", "engines": { @@ -2248,16 +2657,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.65.0.tgz", - "integrity": "sha512-CZ4nMxWwgu1HEEFNkeaCptra9QCtkmKdgf3sWh1rl1trIhmxLilgTV4cwcbQ4wemnT4sWQN8CaKOmdYx+g2gMA==", + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.69.0.tgz", + "integrity": "sha512-l4b0DhWioGg6Gt2ebGlvfkFMOjRsauxtsnDRwUSRX1qHq3HdTfQHV8wW9zEXeciai6HfeaKOedQn2Zoofx3WBw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.65.0", - "@typescript-eslint/types": "8.65.0", - "@typescript-eslint/typescript-estree": "8.65.0", - "@typescript-eslint/visitor-keys": "8.65.0", + "@typescript-eslint/scope-manager": "8.69.0", + "@typescript-eslint/types": "8.69.0", + "@typescript-eslint/typescript-estree": "8.69.0", + "@typescript-eslint/visitor-keys": "8.69.0", "debug": "^4.4.3" }, "engines": { @@ -2273,14 +2682,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.65.0.tgz", - "integrity": "sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==", + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.69.0.tgz", + "integrity": "sha512-yi4obFrHMmnsesWehHbkg9zMA7Jt8cXT+mKM08G999pH1yT6nqgsHx7MYm0uY1wAj8CqiBXYRJ7WAT0QdQHQXg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.65.0", - "@typescript-eslint/types": "^8.65.0", + "@typescript-eslint/tsconfig-utils": "^8.69.0", + "@typescript-eslint/types": "^8.69.0", "debug": "^4.4.3" }, "engines": { @@ -2295,14 +2704,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.65.0.tgz", - "integrity": "sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg==", + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.69.0.tgz", + "integrity": "sha512-ewfspqWvSxKSOaplqAUNbaSFO0eB6w1EtQ+esfYFRm3614Ty4uNtExkcbgd6nWsXphbqKyf9ZYdbZdv2xEoWEQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.65.0", - "@typescript-eslint/visitor-keys": "8.65.0" + "@typescript-eslint/types": "8.69.0", + "@typescript-eslint/visitor-keys": "8.69.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2313,9 +2722,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.65.0.tgz", - "integrity": "sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==", + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.69.0.tgz", + "integrity": "sha512-xNqK7YTDZsLniQMV/4rpFR8Z5JlqeRvVjuG1YgF/mdPVH84HSD19L8CczMA0qg2RfwEV231GHH3VnToJDo4MfQ==", "dev": true, "license": "MIT", "engines": { @@ -2330,15 +2739,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.65.0.tgz", - "integrity": "sha512-YjaZ7PRI5qY7ax2L3PbvX0rRyGtipAReCWs0mhhDBHjH/vl0g0BonaGXrKdKpMbIIsMIwDgbk/xzkBTyAltS5g==", + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.69.0.tgz", + "integrity": "sha512-ZfoJAVg3JZndQEpEl9petVlxau3lRuElc4HRMuAlLCf8to04/iHz692RUSNmXKDjEuJmIL+KZ2/BsOcBc16dsA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.65.0", - "@typescript-eslint/typescript-estree": "8.65.0", - "@typescript-eslint/utils": "8.65.0", + "@typescript-eslint/types": "8.69.0", + "@typescript-eslint/typescript-estree": "8.69.0", + "@typescript-eslint/utils": "8.69.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -2355,9 +2764,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.65.0.tgz", - "integrity": "sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==", + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.69.0.tgz", + "integrity": "sha512-K3VrubUPhlo9VDBS6QdI8YB5j7ClpqLRdefcz6PFrhnwicehBweqQ9Evhl4l+FYz0HdDmMqIiSX0aldGRYtDCA==", "dev": true, "license": "MIT", "engines": { @@ -2369,16 +2778,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.65.0.tgz", - "integrity": "sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==", + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.69.0.tgz", + "integrity": "sha512-AdFkgqck3Vudb/kWnxlyafU/4aBhHrbQ9locP2N4psXTy5mOBg0SHJumnLvx7r6g1gV4DKvUFwV2nJZBoqOD8w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.65.0", - "@typescript-eslint/tsconfig-utils": "8.65.0", - "@typescript-eslint/types": "8.65.0", - "@typescript-eslint/visitor-keys": "8.65.0", + "@typescript-eslint/project-service": "8.69.0", + "@typescript-eslint/tsconfig-utils": "8.69.0", + "@typescript-eslint/types": "8.69.0", + "@typescript-eslint/visitor-keys": "8.69.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -2407,9 +2816,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz", - "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", "dev": true, "license": "MIT", "dependencies": { @@ -2420,13 +2829,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.5" + "brace-expansion": "^5.0.8" }, "engines": { "node": "18 || 20 || >=22" @@ -2449,16 +2858,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.65.0.tgz", - "integrity": "sha512-gXiwIHsYreboxeJucHKPvgwl7dXt50mF8s1/c00cP/WoVTyWKFdtfhRWwZiXYFU5H2O8vVoSLNrexFZjYS/SGA==", + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.69.0.tgz", + "integrity": "sha512-tUbx60BBqQa31kXF5MCsOOLL5E/WzUuxIn7YpAvq+eaUlqvk8/NXnXMBNAdLCr0icjkzem7iUA5QqWHe/hJ1aw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.65.0", - "@typescript-eslint/types": "8.65.0", - "@typescript-eslint/typescript-estree": "8.65.0" + "@typescript-eslint/scope-manager": "8.69.0", + "@typescript-eslint/types": "8.69.0", + "@typescript-eslint/typescript-estree": "8.69.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2473,13 +2882,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.65.0.tgz", - "integrity": "sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==", + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.69.0.tgz", + "integrity": "sha512-+rmdgPA+EXkNgKYvHvFfhrs35utXbwaC5PGpDquSXcoXQDKUA5UjV0LmTucG/4JXkM31BTu4TilHtrN8IVBe8w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/types": "8.69.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -2504,9 +2913,9 @@ } }, "node_modules/@ungap/structured-clone": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", - "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz", + "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==", "dev": true, "license": "ISC" }, @@ -2867,9 +3276,9 @@ } }, "node_modules/acorn": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", - "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", "dev": true, "license": "MIT", "bin": { @@ -2923,9 +3332,9 @@ } }, "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", "dev": true, "license": "MIT", "engines": { @@ -3284,16 +3693,16 @@ } }, "node_modules/babel-jest": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.4.1.tgz", - "integrity": "sha512-fATAbM8piYxkiXQp3RBXmZHxZVNJZAVXXfyeyCN2Tida3+qJ8ea9UxhiJ2y4fLO90ZImKt6k9FlcH2+rLkJGhw==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.5.1.tgz", + "integrity": "sha512-ge1xUVZS91ml09YRMgRGgeKJ4YJpcOiuwteAxFBYLugQyp7cRw+hHej6Ho0vPjvLrjq60bb7JPHH9LAMA1/krA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/transform": "30.4.1", + "@jest/transform": "30.5.1", "@types/babel__core": "^7.20.5", - "babel-plugin-istanbul": "^7.0.1", - "babel-preset-jest": "30.4.0", + "babel-plugin-istanbul": "^8.0.0", + "babel-preset-jest": "30.5.0", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "slash": "^3.0.0" @@ -3306,9 +3715,9 @@ } }, "node_modules/babel-plugin-istanbul": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", - "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-8.0.0.tgz", + "integrity": "sha512-18wCskrN3DgbuBmp1gr7LBGT8xdz5xhQQqFvFhVxbkl8VBCrMKQ2YtqBWtUal1Zrc1HTuX0011+Brjw78TCFkg==", "dev": true, "license": "BSD-3-Clause", "workspaces": [ @@ -3319,53 +3728,16 @@ "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/babel-plugin-istanbul/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "test-exclude": "^7.0.1" }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/babel-plugin-istanbul/node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "license": "ISC", - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" + "node": ">=18" } }, "node_modules/babel-plugin-jest-hoist": { - "version": "30.4.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.4.0.tgz", - "integrity": "sha512-9EdtWM/sSfXLOGLwSn+GS6pIXyBnL07/8gyJlwFXjWy4DxMOyItqyUT29d4lQiS380EZwYlX7/At4PgBS+m2aA==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.5.0.tgz", + "integrity": "sha512-gtGo1B+u14jrZQv6TdSWIWkTqclboo7Qn+dFAGUOIuXLFuJKAdg3U5MIWzZnW4vfUb4dX9skmAMiby86e/SF4A==", "dev": true, "license": "MIT", "dependencies": { @@ -3403,20 +3775,20 @@ } }, "node_modules/babel-preset-jest": { - "version": "30.4.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.4.0.tgz", - "integrity": "sha512-lBY4jxsNmCnSiu7kquw8ZC9F4+XLMOKypT3RnNHPvU2Kpd4W0xaPuLr5ZkRyOsvLYAY4yaW1ZwTW4xB7NIiZzg==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.5.0.tgz", + "integrity": "sha512-ZGPn5ClP4lBDpuOK8W1yQIOy359HmbnZv3suucAlIe+SEE9yDsxV4S2PjSbH2Vc97U+WmzYD7vw3kr8NsQ/i6w==", "dev": true, "license": "MIT", "dependencies": { - "babel-plugin-jest-hoist": "30.4.0", + "babel-plugin-jest-hoist": "30.5.0", "babel-preset-current-node-syntax": "^1.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, "peerDependencies": { - "@babel/core": "^7.11.0 || ^8.0.0-beta.1" + "@babel/core": "^7.11.0 || ^8.0.0-beta.1 || ^8.0.0" } }, "node_modules/balanced-match": { @@ -3427,9 +3799,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.1.tgz", - "integrity": "sha512-HYXq73DDpCtNzOmrFsm9eSwCvWCql0RzqjpDzXN9EadiLJ4DNat0nsZ/Bzmy+Ud12mb4/zKDY0cQ805ZzN+i0A==", + "version": "2.11.21", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.21.tgz", + "integrity": "sha512-uh8vpY/1/YyFkunIDFH/12p7/7VdPKA1hejMVEbdkEaWnUz0Hesvx5EbiU6XxjyHZIOju+ZMbQJkRh+es3/spQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -3464,9 +3836,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", "dev": true, "license": "MIT", "dependencies": { @@ -3488,9 +3860,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz", - "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==", + "version": "4.28.9", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.9.tgz", + "integrity": "sha512-EWazOblFYUvlGZcfGhPUPmYh3nikUxBVb+y9MJun5f3hBi812X+8MSQTujLBtgK3cf51fJWbWfOjyeO954d+Eg==", "dev": true, "funding": [ { @@ -3508,11 +3880,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.10.44", - "caniuse-lite": "^1.0.30001806", - "electron-to-chromium": "^1.5.393", - "node-releases": "^2.0.51", - "update-browserslist-db": "^1.2.3" + "baseline-browser-mapping": "^2.11.20", + "caniuse-lite": "^1.0.30001810", + "electron-to-chromium": "^1.5.420", + "node-releases": "^2.0.54", + "update-browserslist-db": "^1.3.2" }, "bin": { "browserslist": "cli.js" @@ -3531,13 +3903,6 @@ "node-int64": "^0.4.0" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "license": "MIT" - }, "node_modules/c8": { "version": "10.1.3", "resolved": "https://registry.npmjs.org/c8/-/c8-10.1.3.tgz", @@ -3720,9 +4085,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001806", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", - "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", "dev": true, "funding": [ { @@ -3784,9 +4149,9 @@ } }, "node_modules/cjs-module-lexer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz", - "integrity": "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.1.tgz", + "integrity": "sha512-Ca8swihM+/4yKecYHY52kgJd300hi2lADU/a1RxNTRe+RJ9jvqQlESpbz9DnG9mowez8qwXHB8qYdIUw9e+F5Q==", "dev": true, "license": "MIT" }, @@ -3907,9 +4272,9 @@ "license": "MIT" }, "node_modules/comment-parser": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.7.tgz", - "integrity": "sha512-0h+uSNtQGW3D98eQt3jJ8L06Fves8hncB4V/PKdw/Qb8Hnk19VaKuTr55UNRYiSoVa7WwrFls+rh3ux9agmkeQ==", + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.8.tgz", + "integrity": "sha512-rKZTGo4fzKYna8UcL0isTg5wkBNla7bxTypLwZQXjIdi++IdP1OJ41rI5Mti3/jltkPujbu4i9LIARYA+zpotQ==", "dev": true, "license": "MIT", "engines": { @@ -4134,10 +4499,20 @@ "object-keys": "^1.1.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" } }, "node_modules/detect-newline": { @@ -4222,9 +4597,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.396", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.396.tgz", - "integrity": "sha512-yHiw2Y3C3H9U6TMbOfoWK/BPreiOPXRfTWPBwQBoZG6/8TB6eOPnsy5oaRYuatR7Fw2SJ4kKforgufeo7fq0EQ==", + "version": "1.5.422", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.422.tgz", + "integrity": "sha512-UvA/32XqrLDdZSn7Jllo1AYNcWji/G0d5M0GTViE7KoGBiMunw3a34Sb2KO4ZZyrSEhqsxFoVhWWJshdyfKqJA==", "dev": true, "license": "ISC" }, @@ -4249,9 +4624,9 @@ "license": "MIT" }, "node_modules/enhanced-resolve": { - "version": "5.24.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.3.tgz", - "integrity": "sha512-PwKooW9JUzh5chmYfHM3IQl5OkK2u2Nm011MgeZrss3JmFraUx/fqrf78kk8GUMYoibx/14MdwTl/1WKkG7TpQ==", + "version": "5.24.5", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz", + "integrity": "sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==", "dev": true, "license": "MIT", "dependencies": { @@ -4408,6 +4783,13 @@ "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", + "dev": true, + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", @@ -4540,6 +4922,7 @@ "version": "9.39.5", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", "dependencies": { @@ -4823,9 +5206,9 @@ } }, "node_modules/eslint-plugin-import-x/node_modules/brace-expansion": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz", - "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", "dev": true, "license": "MIT", "dependencies": { @@ -4836,13 +5219,13 @@ } }, "node_modules/eslint-plugin-import-x/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.5" + "brace-expansion": "^5.0.8" }, "engines": { "node": "18 || 20 || >=22" @@ -5191,18 +5574,18 @@ } }, "node_modules/expect": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-30.4.1.tgz", - "integrity": "sha512-PMARsyh/JtqC20HoGqlFcIlQAyqUtW4PlI1rup1uhYJtKuwAjbvWi3GQMAn+STdHum/dk8xrKfUM1+5SAwpolA==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.5.1.tgz", + "integrity": "sha512-m8YrYgvKe9+9gEnWEuKz+qCGfHqkrff7PPfyDnOFkjsfYRKqiYyOxDFMFieCGAuhtk/VNm63tvNgKZVzVy+Hvg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/expect-utils": "30.4.1", - "@jest/get-type": "30.1.0", - "jest-matcher-utils": "30.4.1", - "jest-message-util": "30.4.1", - "jest-mock": "30.4.1", - "jest-util": "30.4.1" + "@jest/expect-utils": "30.5.1", + "@jest/get-type": "30.5.0", + "jest-matcher-utils": "30.5.1", + "jest-message-util": "30.5.1", + "jest-mock": "30.5.1", + "jest-util": "30.5.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -5283,9 +5666,9 @@ "license": "MIT" }, "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.3.tgz", + "integrity": "sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==", "dev": true, "license": "ISC", "dependencies": { @@ -5395,9 +5778,9 @@ } }, "node_modules/flatted": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.3.tgz", - "integrity": "sha512-/zipXxyO6rGvuNGDiULY9MvEGSkb2gaG4GGH4ygMi0ZZzyMHdUZBmntJmx5x1G2VuPytCwGN4xsJP6cw+sK+vQ==", + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", + "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", "dev": true, "license": "ISC" }, @@ -5434,28 +5817,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -5615,9 +5976,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", - "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.3.tgz", + "integrity": "sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA==", "dev": true, "license": "MIT", "dependencies": { @@ -5663,9 +6024,9 @@ } }, "node_modules/glob/node_modules/brace-expansion": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.2.tgz", - "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", "dev": true, "license": "MIT", "dependencies": { @@ -6003,25 +6364,6 @@ "node": ">=8" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", @@ -6677,16 +7019,16 @@ } }, "node_modules/jest": { - "version": "30.4.2", - "resolved": "https://registry.npmjs.org/jest/-/jest-30.4.2.tgz", - "integrity": "sha512-Yi1jqNC/Oq0N4hBgNH/YvBpP1P57QqundgytzYqy3yqAa7NZPNjSoi4SGbRAXDMdBzNE6xBCi5U7RgfrvMEUVQ==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.5.1.tgz", + "integrity": "sha512-3qrR8+ZXFnn7y0H2yjWQNkGGBLBY4zTRoTMAq9zJcgwLLtlyonfsCLviIXK9xuE2KgIyM+M36AFcoK2DgFR36w==", "dev": true, "license": "MIT", "dependencies": { - "@jest/core": "30.4.2", - "@jest/types": "30.4.1", + "@jest/core": "30.5.1", + "@jest/types": "30.5.1", "import-local": "^3.2.0", - "jest-cli": "30.4.2" + "jest-cli": "30.5.1" }, "bin": { "jest": "bin/jest.js" @@ -6704,14 +7046,14 @@ } }, "node_modules/jest-changed-files": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.4.1.tgz", - "integrity": "sha512-IuctmYrxi21iOSOaIXpJWalHyPAsVv0GeBHKDn8C1CA4W5htHn7INL+wdnL4Bo0+olEndvAFkmb++tIQJG+vvg==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.5.1.tgz", + "integrity": "sha512-0+bvMM/ENhDI29Z8q1r4HxiDIi4G5tnBmSw4esfPQoj9q8Nik7KIyuxHkTVnnniJQf05SxpGaKDQ+4h28ynGPg==", "dev": true, "license": "MIT", "dependencies": { "execa": "^5.1.1", - "jest-util": "30.4.1", + "jest-util": "30.5.1", "p-limit": "^3.1.0" }, "engines": { @@ -6809,29 +7151,29 @@ } }, "node_modules/jest-circus": { - "version": "30.4.2", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.4.2.tgz", - "integrity": "sha512-rvHH7VlY6LgbJXJTQ87GW62g1FntOtbhh0zT+v04kC+pgL6aBKyYINXxWukCpj3dcIBMw5/XUbtDS9dU9JTXeQ==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.5.1.tgz", + "integrity": "sha512-NgliezXQ6yznqR4W5Gqw++0cZSbBZlF0NknNIAE5VmSJKWOtmWJmWnBq3TSkUOVBTPrT7FGGhVdA8DLWnxo2Sw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "30.4.1", - "@jest/expect": "30.4.1", - "@jest/test-result": "30.4.1", - "@jest/types": "30.4.1", + "@jest/environment": "30.5.1", + "@jest/expect": "30.5.1", + "@jest/test-result": "30.5.1", + "@jest/types": "30.5.1", "@types/node": "*", "chalk": "^4.1.2", "co": "^4.6.0", "dedent": "^1.6.0", "is-generator-fn": "^2.1.0", - "jest-each": "30.4.1", - "jest-matcher-utils": "30.4.1", - "jest-message-util": "30.4.1", - "jest-runtime": "30.4.2", - "jest-snapshot": "30.4.1", - "jest-util": "30.4.1", + "jest-each": "30.5.1", + "jest-matcher-utils": "30.5.1", + "jest-message-util": "30.5.1", + "jest-runtime": "30.5.1", + "jest-snapshot": "30.5.1", + "jest-util": "30.5.1", "p-limit": "^3.1.0", - "pretty-format": "30.4.1", + "pretty-format": "30.5.1", "pure-rand": "^7.0.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" @@ -6858,21 +7200,21 @@ "license": "MIT" }, "node_modules/jest-cli": { - "version": "30.4.2", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.4.2.tgz", - "integrity": "sha512-jfA2ocvVHMXS2QijrJ0d31ektP+d/W0T5RpcTX2Pq+3sVqHlsXVCM2+FmwpL+bdY8OfHpIg9xMxLF17Zg0U49Q==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.5.1.tgz", + "integrity": "sha512-uwNYepWgaNBCplm42fCIUZTf/tIEHIy5AYvx7eL1BrwIgyjPt+2poouR23UO2yopIP+kV8oZFHfv+l4pg/8prQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/core": "30.4.2", - "@jest/test-result": "30.4.1", - "@jest/types": "30.4.1", + "@jest/core": "30.5.1", + "@jest/test-result": "30.5.1", + "@jest/types": "30.5.1", "chalk": "^4.1.2", "exit-x": "^0.2.2", "import-local": "^3.2.0", - "jest-config": "30.4.2", - "jest-util": "30.4.1", - "jest-validate": "30.4.1", + "jest-config": "30.5.1", + "jest-util": "30.5.1", + "jest-validate": "30.5.1", "yargs": "^17.7.2" }, "bin": { @@ -6891,33 +7233,33 @@ } }, "node_modules/jest-config": { - "version": "30.4.2", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.4.2.tgz", - "integrity": "sha512-rNHAShJQqQwFNoL0hbf3BphSBOWnpOUAKvidLS/AjNVLPfoj5mSf4jQMfW3cYOs6hXeZC7nF7mDHaBnbxELOzg==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.5.1.tgz", + "integrity": "sha512-L8PKM2X/ngG8PxfLMqglKGZjylPgw84bVPUlMY9W/o76TnLqPWrmQgsaT0HrheGdRtpGE5FbmREA0Kvb+Qx5gQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", - "@jest/get-type": "30.1.0", - "@jest/pattern": "30.4.0", - "@jest/test-sequencer": "30.4.1", - "@jest/types": "30.4.1", - "babel-jest": "30.4.1", + "@jest/get-type": "30.5.0", + "@jest/pattern": "30.5.0", + "@jest/test-sequencer": "30.5.1", + "@jest/types": "30.5.1", + "babel-jest": "30.5.1", "chalk": "^4.1.2", "ci-info": "^4.2.0", "deepmerge": "^4.3.1", - "glob": "^10.5.0", + "glob": "^13.0.6", "graceful-fs": "^4.2.11", - "jest-circus": "30.4.2", - "jest-docblock": "30.4.0", - "jest-environment-node": "30.4.1", - "jest-regex-util": "30.4.0", - "jest-resolve": "30.4.1", - "jest-runner": "30.4.2", - "jest-util": "30.4.1", - "jest-validate": "30.4.1", + "jest-circus": "30.5.1", + "jest-docblock": "30.5.0", + "jest-environment-node": "30.5.1", + "jest-regex-util": "30.5.0", + "jest-resolve": "30.5.1", + "jest-runner": "30.5.1", + "jest-util": "30.5.1", + "jest-validate": "30.5.1", "parse-json": "^5.2.0", - "pretty-format": "30.4.1", + "pretty-format": "30.5.1", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, @@ -6941,26 +7283,110 @@ } } }, + "node_modules/jest-config/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/jest-config/node_modules/brace-expansion": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/jest-config/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-config/node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/jest-config/node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-config/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/jest-diff": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.4.1.tgz", - "integrity": "sha512-CRpFK0RtLriVDGcPPAnR6HMVI8bSR2jnUIgralhauzYQZIb4RH9AtEInTuQr65LmmGggGcRT6HIASxwqsVsmlA==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.5.1.tgz", + "integrity": "sha512-e3cNNMpv8Kh20MjjphTXs+3Vz7DQyLM1nft7KJhnh46atFhjVJRa+0Hq0beywuwsACtMQUBihQkFl8zxb7gt1Q==", "dev": true, "license": "MIT", "dependencies": { - "@jest/diff-sequences": "30.4.0", - "@jest/get-type": "30.1.0", + "@jest/diff-sequences": "30.5.0", + "@jest/get-type": "30.5.0", "chalk": "^4.1.2", - "pretty-format": "30.4.1" + "pretty-format": "30.5.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-docblock": { - "version": "30.4.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.4.0.tgz", - "integrity": "sha512-ZPMabUZCx5MpbZ2eBYSvZ0J8fvo3dR9oM+eeUpb3aKNQFuS2tu3Duw1TNlMoP8k3WQgKGJuhcMFvwcVuq6T7oA==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.5.0.tgz", + "integrity": "sha512-NwDqcxtoZi33RhuW+zJS/RVA3rmheQ8BnwpYZuc/Eruaz6seQb7+aoCeDZu/3X7W2XmD8DbSo9Pn72DbKsBFYw==", "dev": true, "license": "MIT", "dependencies": { @@ -6971,36 +7397,36 @@ } }, "node_modules/jest-each": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.4.1.tgz", - "integrity": "sha512-/8MJbH6fuj48TstjrMf+u/pd06Qezz5xOXvZA6442heNOWr8bdeoGZX2d9fCn028CoMgYmroH9//zky5GfyYmA==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.5.1.tgz", + "integrity": "sha512-S1af0TU4v1EZ/AUlkFs/sxf/5KGsbAT9kRgdyoMX/x72y7C8ZEgETE5o1TPnbKRnrbprc5FR/moYLfdRmqEjsQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/get-type": "30.1.0", - "@jest/types": "30.4.1", + "@jest/get-type": "30.5.0", + "@jest/types": "30.5.1", "chalk": "^4.1.2", - "jest-util": "30.4.1", - "pretty-format": "30.4.1" + "jest-util": "30.5.1", + "pretty-format": "30.5.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-environment-node": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.4.1.tgz", - "integrity": "sha512-4FZYVOk85hz2AyT6BbarKy9u37g6DbrDyCdFhsnDdXqyrueYQvB+0zO4f/kqLCRD0BsPRXPMNJeQwihKZV8naw==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.5.1.tgz", + "integrity": "sha512-LrPj3sPMjsQoOB3jrb8p/sa+XkSFNKo60TTsyc+EB2kxQJHgbwElpXnx1yX25fdFn5958FIObRtcLSHyV8VIAw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "30.4.1", - "@jest/fake-timers": "30.4.1", - "@jest/types": "30.4.1", + "@jest/environment": "30.5.1", + "@jest/fake-timers": "30.5.1", + "@jest/types": "30.5.1", "@types/node": "*", - "jest-mock": "30.4.1", - "jest-util": "30.4.1", - "jest-validate": "30.4.1" + "jest-mock": "30.5.1", + "jest-util": "30.5.1", + "jest-validate": "30.5.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -7017,75 +7443,73 @@ } }, "node_modules/jest-haste-map": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.4.1.tgz", - "integrity": "sha512-rFrcONd8jeFsyw+Z9CrScJgglRf2+NFmNam8dKu7n+SoHqNYT47mn0DdEcVUZJpvh7Iz6/si7f7yUH7GJHVgnw==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.5.1.tgz", + "integrity": "sha512-VIFgt67jW480YDxKfEv9IYQKrFpYt7bOCMn3VsnjK7AK9qo7p6acpnA1DHwsVOULE3dTaYew/6JaTD/d0VDHoQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.4.1", + "@jest/types": "30.5.1", + "@parcel/watcher": "^2.6.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", + "fdir": "^6.5.0", "graceful-fs": "^4.2.11", - "jest-regex-util": "30.4.0", - "jest-util": "30.4.1", - "jest-worker": "30.4.1", - "picomatch": "^4.0.3", - "walker": "^1.0.8" + "jest-regex-util": "30.5.0", + "jest-util": "30.5.1", + "jest-worker": "30.5.1", + "picomatch": "^4.0.3" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.3" } }, "node_modules/jest-leak-detector": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.4.1.tgz", - "integrity": "sha512-IpmyiioeHxiWDhesHnUFmOxcTzwCwKpgACgWajtAP+nYQXiY7DakTxB6Bx9JFiRMljr0AX1PvnQdaU1KFoz6NQ==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.5.1.tgz", + "integrity": "sha512-gt4GT2aWgEoCNTcBe4rqS74xTIUJxi+UD9SNSu9aOk5LmTEd6fS5KSTmAKAfitCCktQHNN+upUuL6EkBfFbMDQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/get-type": "30.1.0", - "pretty-format": "30.4.1" + "@jest/get-type": "30.5.0", + "pretty-format": "30.5.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-matcher-utils": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.4.1.tgz", - "integrity": "sha512-zvYfX5CaeEkFrrLS9suWe9rvJrm9J1Iv3ua8kIBv9GEPzcnsfBf0bob37la7s67fs0nlBC3EuvkOLnXQKxtx4A==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.5.1.tgz", + "integrity": "sha512-aroZVqwOz/wC2y6pC+obgFWKV9viaQWQTTSB6W5H55+egtUczIfXR/rxExTv92xD/ADYwpqaYfVWx1aqwKg7FA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/get-type": "30.1.0", + "@jest/get-type": "30.5.0", "chalk": "^4.1.2", - "jest-diff": "30.4.1", - "pretty-format": "30.4.1" + "jest-diff": "30.5.1", + "pretty-format": "30.5.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-message-util": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.4.1.tgz", - "integrity": "sha512-kwCKIvq0MCW1HzLoGola9Te6JUdzgV0loyKJ3Qghrkz9i5/RRIHsL95BMQc2HBBhlBKC4j22K9p11TGHH8RBpQ==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.5.1.tgz", + "integrity": "sha512-UdQlLdd9wL/Ys7xRErckqwD6wPlSZYueosSWuHc1r2ztGLwlgPvtSJq2+BPEgaEY13WLvfFbmhTj8pba0Sd1jg==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@jest/types": "30.4.1", + "@jest/types": "30.5.1", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", - "jest-util": "30.4.1", + "jest-util": "30.5.1", "picomatch": "^4.0.3", - "pretty-format": "30.4.1", + "pretty-format": "30.5.1", "slash": "^3.0.0", "stack-utils": "^2.0.6" }, @@ -7094,42 +7518,25 @@ } }, "node_modules/jest-mock": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.4.1.tgz", - "integrity": "sha512-/i8SVb8/NSB7RfNi8gfqu8gxLV23KaL5EpAttyb9iz8qWRIqXRLflycz/32wXsYkOnaUlx8NAKnJYtpsmXUmfw==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.5.1.tgz", + "integrity": "sha512-9fVjc3leUpGID2/by/LU4Dvdcp7PFh9LlxS3QRWK3ABm+KtvEVsG/AEGeLY3gKOZsjkBxyfwGltoAVlW7dygHg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.4.1", + "@jest/expect-utils": "30.5.1", + "@jest/types": "30.5.1", "@types/node": "*", - "jest-util": "30.4.1" + "jest-util": "30.5.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, "node_modules/jest-regex-util": { - "version": "30.4.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.4.0.tgz", - "integrity": "sha512-mWlvLviKIgIQ8VCuM1xRdD0TWp3zlzionlmDBjuXVBs+VkmXq6FgW9T4Emr7oGz/Rk6feDCGyiugolcQEyp3mg==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.5.0.tgz", + "integrity": "sha512-Mg0WK7A6xRHLSA1udJ8y9f3lM0uUhFTBnLKzwPmqB9AylvpleJ6BLemR8K9dK27DY+cesDryoA7yLZCAHsPG1A==", "dev": true, "license": "MIT", "engines": { @@ -7137,100 +7544,100 @@ } }, "node_modules/jest-resolve": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.4.1.tgz", - "integrity": "sha512-Zry8Yq/yJcNAZ7dJ5F2heic8AheXvbFZ7XI5V+h28nrYZ7Qoyy4dItq8OodjnYD270mvX+ZudmrNV9cysqhW5Q==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.5.1.tgz", + "integrity": "sha512-wprhLejRtwN6h8ZgaqC0eYjGJ1uMdGPT/+b3eFncbG4NWuuP9QL+vWwRinu9waw7hkOLcpMJGVJAMgBwsPssMQ==", "dev": true, "license": "MIT", "dependencies": { "chalk": "^4.1.2", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.4.1", - "jest-pnp-resolver": "^1.2.3", - "jest-util": "30.4.1", - "jest-validate": "30.4.1", + "jest-haste-map": "30.5.1", + "jest-util": "30.5.1", + "jest-validate": "30.5.1", "slash": "^3.0.0", - "unrs-resolver": "^1.7.11" + "unrs-resolver": "^1.12.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-resolve-dependencies": { - "version": "30.4.2", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.4.2.tgz", - "integrity": "sha512-gDiVh1I+GxYzz9oXlyw+1wv6VOYX1WYxMOfjsA3iGKePV2oxmbHhwxfkALxNxYy1ciw6APWwkW2zZONwP97aEQ==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.5.1.tgz", + "integrity": "sha512-JKpXGONDcTaunrNVn8KCl6qAnwl06jIkvv70lhq0Ze47lsPx9sH5HoeEUiXX6iFGnliHN/qpIbQ0l38wrVmXaw==", "dev": true, "license": "MIT", "dependencies": { - "jest-regex-util": "30.4.0", - "jest-snapshot": "30.4.1" + "jest-regex-util": "30.5.0", + "jest-snapshot": "30.5.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-runner": { - "version": "30.4.2", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.4.2.tgz", - "integrity": "sha512-2dw0PslVYXxffXGpLo+Ejad+KcI1Qkjn7f4X4619gf21oCUmL+SPfjqIa/losUem3yEOvfNZe/F1HWUcNpODcg==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.5.1.tgz", + "integrity": "sha512-FPlQE4+mwnFxXmpPrSi836KV2ZzvK1g6/nPCT8o5BcoDUUNJQeHo1/Qdkoe/QeoL4M7OeJpbnGUhYKhC1VMdaQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/console": "30.4.1", - "@jest/environment": "30.4.1", - "@jest/test-result": "30.4.1", - "@jest/transform": "30.4.1", - "@jest/types": "30.4.1", + "@jest/console": "30.5.1", + "@jest/environment": "30.5.1", + "@jest/source-map": "30.5.0", + "@jest/test-result": "30.5.1", + "@jest/transform": "30.5.1", + "@jest/types": "30.5.1", "@types/node": "*", "chalk": "^4.1.2", "emittery": "^0.13.1", "exit-x": "^0.2.2", "graceful-fs": "^4.2.11", - "jest-docblock": "30.4.0", - "jest-environment-node": "30.4.1", - "jest-haste-map": "30.4.1", - "jest-leak-detector": "30.4.1", - "jest-message-util": "30.4.1", - "jest-resolve": "30.4.1", - "jest-runtime": "30.4.2", - "jest-util": "30.4.1", - "jest-watcher": "30.4.1", - "jest-worker": "30.4.1", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" + "jest-docblock": "30.5.0", + "jest-environment-node": "30.5.1", + "jest-haste-map": "30.5.1", + "jest-leak-detector": "30.5.1", + "jest-message-util": "30.5.1", + "jest-resolve": "30.5.1", + "jest-runtime": "30.5.1", + "jest-util": "30.5.1", + "jest-watcher": "30.5.1", + "jest-worker": "30.5.1", + "p-limit": "^3.1.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-runtime": { - "version": "30.4.2", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.4.2.tgz", - "integrity": "sha512-3/5e8iPz2k/VLqlr8DgTftYyLUv8Su3FkCAO2/Od81UsUTpSxOrS6O5x5KkoQwyUjmpYyDJKeyAvg2T2nvpNkQ==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.5.1.tgz", + "integrity": "sha512-UB88+NRkK2Tw/OqV7dofYcyiUGrVZtD41k/N0xQOs9fG//57XHK7JLWG52HD1UYpUAhjK4xm6DBvFX3yWudsMA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "30.4.1", - "@jest/fake-timers": "30.4.1", - "@jest/globals": "30.4.1", - "@jest/source-map": "30.0.1", - "@jest/test-result": "30.4.1", - "@jest/transform": "30.4.1", - "@jest/types": "30.4.1", + "@jest/environment": "30.5.1", + "@jest/fake-timers": "30.5.1", + "@jest/globals": "30.5.1", + "@jest/source-map": "30.5.0", + "@jest/test-result": "30.5.1", + "@jest/transform": "30.5.1", + "@jest/types": "30.5.1", "@types/node": "*", "chalk": "^4.1.2", - "cjs-module-lexer": "^2.1.0", + "cjs-module-lexer": "^2.2.0", "collect-v8-coverage": "^1.0.2", - "glob": "^10.5.0", + "es-module-lexer": "^2.1.0", + "glob": "^13.0.6", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.4.1", - "jest-message-util": "30.4.1", - "jest-mock": "30.4.1", - "jest-regex-util": "30.4.0", - "jest-resolve": "30.4.1", - "jest-snapshot": "30.4.1", - "jest-util": "30.4.1", + "jest-haste-map": "30.5.1", + "jest-message-util": "30.5.1", + "jest-mock": "30.5.1", + "jest-regex-util": "30.5.0", + "jest-resolve": "30.5.1", + "jest-snapshot": "30.5.1", + "jest-util": "30.5.1", "slash": "^3.0.0", "strip-bom": "^4.0.0" }, @@ -7238,10 +7645,94 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/jest-runtime/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/jest-runtime/node_modules/brace-expansion": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/jest-runtime/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-runtime/node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/jest-runtime/node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-runtime/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/jest-snapshot": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.4.1.tgz", - "integrity": "sha512-tEOkkfOMppUyeiHwjZswOQ3lcnoTnws/q5FnGIaeIh/jmoU0ZlgMYRR8sTlTj+nNGCoJ0RDq6SfxGxCsyMTPmw==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.5.1.tgz", + "integrity": "sha512-cNWFdSb5xuDGl8hKkAZJ3YtI/PzHpAPFV+HUXWIOG8rMhpDTLVbvAc2d2wRicoYw2wGsJGLaurJT6BLC97bLXQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7250,20 +7741,20 @@ "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/types": "^7.27.3", - "@jest/expect-utils": "30.4.1", - "@jest/get-type": "30.1.0", - "@jest/snapshot-utils": "30.4.1", - "@jest/transform": "30.4.1", - "@jest/types": "30.4.1", + "@jest/expect-utils": "30.5.1", + "@jest/get-type": "30.5.0", + "@jest/snapshot-utils": "30.5.1", + "@jest/transform": "30.5.1", + "@jest/types": "30.5.1", "babel-preset-current-node-syntax": "^1.2.0", "chalk": "^4.1.2", - "expect": "30.4.1", + "expect": "30.5.1", "graceful-fs": "^4.2.11", - "jest-diff": "30.4.1", - "jest-matcher-utils": "30.4.1", - "jest-message-util": "30.4.1", - "jest-util": "30.4.1", - "pretty-format": "30.4.1", + "jest-diff": "30.5.1", + "jest-matcher-utils": "30.5.1", + "jest-message-util": "30.5.1", + "jest-util": "30.5.1", + "pretty-format": "30.5.1", "semver": "^7.7.2", "synckit": "^0.11.8" }, @@ -7285,13 +7776,13 @@ } }, "node_modules/jest-util": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.4.1.tgz", - "integrity": "sha512-vjQb1sACEiv13DKJMDToJpzVW0joCsIQrmbg0fi7CyOOt+g9jTuQl2A216pWRBYhOVt53XbL/2LbMKg1BECWOw==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.5.1.tgz", + "integrity": "sha512-yKuxmNy2rSbTXw+3SIPanJo+nV4/BS1p26v44IYBFMsswSQySfMMcPHErnOncda7i9HEz0q605rIhSTBVgrZTg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.4.1", + "@jest/types": "30.5.1", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -7303,18 +7794,18 @@ } }, "node_modules/jest-validate": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.4.1.tgz", - "integrity": "sha512-PDWi4SOwLnwqNDfHZjOcsEFyZ4fc/2W2gVL3DEoyqnB6jCQMLRtfBong8s6omIw3lI0HWOus12xfnFmQtjW3fw==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.5.1.tgz", + "integrity": "sha512-i/buJ56wTpxihE93hQYNMfdOThS87+HGvLZzZJmU4xggPcdTYQq051iwALLCHp3q+SkCGH+EFejQZz5EbBSkkg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/get-type": "30.1.0", - "@jest/types": "30.4.1", + "@jest/get-type": "30.5.0", + "@jest/types": "30.5.1", "camelcase": "^6.3.0", "chalk": "^4.1.2", "leven": "^3.1.0", - "pretty-format": "30.4.1" + "pretty-format": "30.5.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -7334,19 +7825,19 @@ } }, "node_modules/jest-watcher": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.4.1.tgz", - "integrity": "sha512-/l9UonmvCwjHH7d2h3iAwIloLc1H0S8mJZ/LNK3i86hqwPAz8otUJjP9MfYtz9Tt77Su5FD2xGjZn8d31IZHlw==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.5.1.tgz", + "integrity": "sha512-+FHJ7C+S7b3ySfhA1aFmoa6TztsnwZVv84ycPRn0tVN93np2EU4b8C/KadqA3l6igdjgLBTnUotab9ER0HLG8A==", "dev": true, "license": "MIT", "dependencies": { - "@jest/test-result": "30.4.1", - "@jest/types": "30.4.1", + "@jest/test-result": "30.5.1", + "@jest/types": "30.5.1", "@types/node": "*", "ansi-escapes": "^4.3.2", "chalk": "^4.1.2", "emittery": "^0.13.1", - "jest-util": "30.4.1", + "jest-util": "30.5.1", "string-length": "^4.0.2" }, "engines": { @@ -7354,15 +7845,15 @@ } }, "node_modules/jest-worker": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.4.1.tgz", - "integrity": "sha512-SHynN/q/QD++iNyvMdy+WMmbCGk8jIsNcRxycXbWubSOhvo6T+j2afcfUSl+3hYsiBebOTo0cT7c2H7CXugu1g==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.5.1.tgz", + "integrity": "sha512-Cbxh5v7AoLuFRmFJSM4/aHdQ68rjXvUWr716EE0Dh3I7T+T/3FgFKhOERGXHcU2Meftq9+9zxPM3TSNyI9D+HA==", "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", - "jest-util": "30.4.1", + "jest-util": "30.5.1", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" }, @@ -7394,9 +7885,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", - "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", "dev": true, "funding": [ { @@ -7658,16 +8149,6 @@ "node": ">=10" } }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tmpl": "1.0.5" - } - }, "node_modules/map-obj": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", @@ -7994,6 +8475,13 @@ "node": ">=8" } }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT" + }, "node_modules/node-exports-info": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.2.tgz", @@ -8031,9 +8519,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.51", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", - "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", + "version": "2.0.54", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.54.tgz", + "integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==", "dev": true, "license": "MIT", "engines": { @@ -8230,16 +8718,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, "node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -8426,16 +8904,6 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -8506,9 +8974,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "dev": true, "license": "MIT", "engines": { @@ -8644,16 +9112,16 @@ } }, "node_modules/pretty-format": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.4.1.tgz", - "integrity": "sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.5.1.tgz", + "integrity": "sha512-byhRAPguVKMQIj4kjJwJ5lAskVhfuiSdiYl/aLTWpgkGEmic2jYhJh1yE9ih8Ox44Xg9ccCT11/S6QrzSJuNrg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/schemas": "30.4.1", - "ansi-styles": "^5.2.0", - "react-is-18": "npm:react-is@^18.3.1", - "react-is-19": "npm:react-is@^19.2.5" + "@jest/react-is-18": "npm:react-is@^18.3.1", + "@jest/react-is-19": "npm:react-is@^19.2.5", + "@jest/schemas": "30.5.0", + "ansi-styles": "^5.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -8673,9 +9141,9 @@ } }, "node_modules/pretty-ms": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", - "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.1.tgz", + "integrity": "sha512-HzMy3Geq23nVALD/M2LliU+F+M+gVNsvkQWWqeBZ8HDiCgzo6YPJ/Omrmtq24EFrIsk0a3EkQGEd7bDOo+IhGA==", "dev": true, "license": "MIT", "dependencies": { @@ -8783,22 +9251,6 @@ "dev": true, "license": "MIT" }, - "node_modules/react-is-18": { - "name": "react-is", - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/react-is-19": { - "name": "react-is", - "version": "19.2.8", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.8.tgz", - "integrity": "sha512-s5un28nYxKJw5gvUHyW5PCC28CvBqLu9r3cWgzHT4Vo/5fqqkFcdRYsGcKf50WMPpjjFZS5d76fn3YCo2njKwQ==", - "dev": true, - "license": "MIT" - }, "node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -9390,27 +9842,6 @@ "node": ">=8" } }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -9610,25 +10041,25 @@ } }, "node_modules/string.prototype.matchall": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", - "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.1.0.tgz", + "integrity": "sha512-tHNHTxInrYLCga9O9YGxWA3G9/nnzQw8UGAyqGx3Ar1pSTTzIuM4woFSq4SowkXCjJIwq5sIiQvEfRI9tCH1qQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", "define-properties": "^1.2.1", - "es-abstract": "^1.23.6", + "es-abstract": "^1.24.2", "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.6", + "es-object-atoms": "^1.1.2", + "get-intrinsic": "^1.3.0", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", - "regexp.prototype.flags": "^1.5.3", + "regexp.prototype.flags": "^1.5.4", "set-function-name": "^2.0.2", - "side-channel": "^1.1.0" + "side-channel": "^1.1.1" }, "engines": { "node": ">= 0.4" @@ -9893,9 +10324,9 @@ } }, "node_modules/test-exclude/node_modules/brace-expansion": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz", - "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", "dev": true, "license": "MIT", "dependencies": { @@ -9906,13 +10337,13 @@ } }, "node_modules/test-exclude/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.5" + "brace-expansion": "^5.0.8" }, "engines": { "node": "18 || 20 || >=22" @@ -9938,13 +10369,6 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true, - "license": "BSD-3-Clause" - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -10254,16 +10678,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.65.0.tgz", - "integrity": "sha512-/ggrHAwyjENDusvyxbuqxAC2dTnZg/Z8F+fgQtYIz+L6n/9HfSlEZcFGV/NsMNa6CkGk0xUjUAFwC0vHOflvIA==", + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.69.0.tgz", + "integrity": "sha512-B3MltX0VqjUBNEe3b3sSuiRbfa6XrfHFtBiPamjT5AsW/dfq+y+bc0wyuS9DxAS1LyzCxRp2+rxzpLUvqM2BvA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.65.0", - "@typescript-eslint/parser": "8.65.0", - "@typescript-eslint/typescript-estree": "8.65.0", - "@typescript-eslint/utils": "8.65.0" + "@typescript-eslint/eslint-plugin": "8.69.0", + "@typescript-eslint/parser": "8.69.0", + "@typescript-eslint/typescript-estree": "8.69.0", + "@typescript-eslint/utils": "8.69.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -10297,9 +10721,9 @@ } }, "node_modules/undici": { - "version": "6.28.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.28.0.tgz", - "integrity": "sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==", + "version": "6.28.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.28.1.tgz", + "integrity": "sha512-zWpdTVD54H48CIybL0rWQ3ukpb9d23wM7eH5RtfdmeP70cWHNjtfo7P4vZX+5CoDcO53J4Pu5uXp7lNfjc6DRA==", "dev": true, "license": "MIT", "engines": { @@ -10365,9 +10789,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz", + "integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==", "dev": true, "funding": [ { @@ -10431,16 +10855,6 @@ "spdx-expression-parse": "^3.0.0" } }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "makeerror": "1.0.12" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -10651,13 +11065,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, "node_modules/write-file-atomic": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", @@ -10673,9 +11080,9 @@ } }, "node_modules/ws": { - "version": "8.21.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.1.tgz", - "integrity": "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==", + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", "dev": true, "license": "MIT", "engines": { @@ -10815,9 +11222,9 @@ } }, "node_modules/yoctocolors": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", - "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.2.0.tgz", + "integrity": "sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==", "dev": true, "license": "MIT", "engines": { diff --git a/deps/undici/src/package.json b/deps/undici/src/package.json index 6c11dec68399..983f4641bc96 100644 --- a/deps/undici/src/package.json +++ b/deps/undici/src/package.json @@ -1,6 +1,6 @@ { "name": "undici", - "version": "7.29.0", + "version": "7.29.1", "description": "An HTTP/1.1 client, written from scratch for Node.js", "homepage": "https://undici.nodejs.org", "bugs": { diff --git a/deps/undici/src/types/interceptors.d.ts b/deps/undici/src/types/interceptors.d.ts index 71983a768c03..c534575b2a9b 100644 --- a/deps/undici/src/types/interceptors.d.ts +++ b/deps/undici/src/types/interceptors.d.ts @@ -12,6 +12,8 @@ declare namespace Interceptors { export type DecompressInterceptorOpts = { skipErrorResponses?: boolean skipStatusCodes?: number[] + /** Maximum decompressed response size in bytes. @default 67108864 */ + maxSize?: number } export type ResponseErrorInterceptorOpts = { throwOnError: boolean } diff --git a/deps/undici/undici.js b/deps/undici/undici.js index dcdfe509dd3a..9b84552276fb 100644 --- a/deps/undici/undici.js +++ b/deps/undici/undici.js @@ -7871,7 +7871,7 @@ var require_client_h1 = __commonJS({ __name(onSocketClose, "onSocketClose"); function clearIdleSocketValidation(socket) { if (socket[kIdleSocketValidationTimeout]) { - clearTimeout(socket[kIdleSocketValidationTimeout]); + clearImmediate(socket[kIdleSocketValidationTimeout]); socket[kIdleSocketValidationTimeout] = null; } socket[kIdleSocketValidation] = 0; @@ -7879,14 +7879,13 @@ var require_client_h1 = __commonJS({ __name(clearIdleSocketValidation, "clearIdleSocketValidation"); function scheduleIdleSocketValidation(client, socket) { socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setTimeout(() => { + socket[kIdleSocketValidationTimeout] = setImmediate(() => { socket[kIdleSocketValidationTimeout] = null; socket[kIdleSocketValidation] = 2; if (client[kSocket] === socket && !socket.destroyed) { client[kResume](); } - }, 0); - socket[kIdleSocketValidationTimeout].unref?.(); + }); } __name(scheduleIdleSocketValidation, "scheduleIdleSocketValidation"); function resumeH1(client) { @@ -8388,7 +8387,9 @@ var require_client_h2 = __commonJS({ RequestAbortedError, SocketError, InformationalError, - InvalidArgumentError + InvalidArgumentError, + HeadersTimeoutError, + BodyTimeoutError } = require_errors(); var { kUrl, @@ -8413,6 +8414,7 @@ var require_client_h2 = __commonJS({ kHTTPContext, kClosed, kBodyTimeout, + kHeadersTimeout, kEnableConnectProtocol, kRemoteSettings, kHTTP2Stream, @@ -8551,7 +8553,7 @@ var require_client_h2 = __commonJS({ function resumeH2(client) { const socket = client[kSocket]; if (socket?.destroyed === false) { - if (client[kSize] === 0 || client[kMaxConcurrentStreams] === 0) { + if (client[kSize] === 0) { socket.unref(); client[kHTTP2Session].unref(); } else { @@ -8625,6 +8627,25 @@ var require_client_h2 = __commonJS({ util.destroy(this[kSocket], err); } __name(onHttp2SessionEnd, "onHttp2SessionEnd"); + function completeRequest(client, request, resetPendingIdx = false) { + const queue = client[kQueue]; + const runningIdx = client[kRunningIdx]; + if (runningIdx < client[kPendingIdx] && queue[runningIdx] === request) { + queue[runningIdx] = null; + client[kRunningIdx] = runningIdx + 1; + return; + } + const index = queue.indexOf(request, runningIdx); + if (index === -1 || index >= client[kPendingIdx]) { + return; + } + queue.splice(index, 1); + client[kPendingIdx]--; + if (resetPendingIdx && client[kPendingIdx] < client[kRunningIdx]) { + client[kPendingIdx] = client[kRunningIdx]; + } + } + __name(completeRequest, "completeRequest"); function onHttp2SessionGoAway(errorCode) { const err = this[kError] || new SocketError(`HTTP/2: "GOAWAY" frame received with code ${errorCode}`, util.getSocketInfo(this[kSocket])); const client = this[kClient]; @@ -8636,7 +8657,9 @@ var require_client_h2 = __commonJS({ if (client[kRunningIdx] < client[kQueue].length) { const request = client[kQueue][client[kRunningIdx]]; client[kQueue][client[kRunningIdx]++] = null; - util.errorRequest(client, request, err); + if (request != null) { + util.errorRequest(client, request, err); + } client[kPendingIdx] = client[kRunningIdx]; } assert(client[kRunning] === 0); @@ -8660,7 +8683,9 @@ var require_client_h2 = __commonJS({ const requests = client[kQueue].splice(client[kRunningIdx]); for (let i = 0; i < requests.length; i++) { const request = requests[i]; - util.errorRequest(client, request, err); + if (request != null) { + util.errorRequest(client, request, err); + } } } } @@ -8698,7 +8723,8 @@ var require_client_h2 = __commonJS({ } __name(shouldSendContentLength, "shouldSendContentLength"); function writeH2(client, request) { - const requestTimeout = request.bodyTimeout ?? client[kBodyTimeout]; + const headersTimeout = request.headersTimeout ?? client[kHeadersTimeout]; + const bodyTimeout = request.bodyTimeout ?? client[kBodyTimeout]; const session = client[kHTTP2Session]; const { method, path, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request; let { body } = request; @@ -8746,6 +8772,7 @@ var require_client_h2 = __commonJS({ stream.removeAllListeners("data"); stream.close(); client[kOnError](err); + completeRequest(client, request); client[kResume](); } util.destroy(body, err); @@ -8780,7 +8807,7 @@ var require_client_h2 = __commonJS({ const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers2; request.onUpgrade(statusCode, parseH2Headers(realHeaders), stream); ++session[kOpenStreams]; - client[kQueue][client[kRunningIdx]++] = null; + completeRequest(client, request); }); stream.on("error", () => { if (stream.rstCode === NGHTTP2_REFUSED_STREAM || stream.rstCode === NGHTTP2_CANCEL) { @@ -8791,7 +8818,7 @@ var require_client_h2 = __commonJS({ session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); - stream.setTimeout(requestTimeout); + stream.setTimeout(headersTimeout); return true; } stream = session.request(headers, { endStream: false, signal }); @@ -8800,13 +8827,14 @@ var require_client_h2 = __commonJS({ const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers2; request.onUpgrade(statusCode, parseH2Headers(realHeaders), stream); ++session[kOpenStreams]; - client[kQueue][client[kRunningIdx]++] = null; + completeRequest(client, request); }); + stream.on("error", abort); stream.once("close", () => { session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); - stream.setTimeout(requestTimeout); + stream.setTimeout(headersTimeout); return true; } headers[HTTP2_HEADER_PATH] = path; @@ -8864,12 +8892,13 @@ var require_client_h2 = __commonJS({ writeBodyH2(); } ++session[kOpenStreams]; - stream.setTimeout(requestTimeout); + stream.setTimeout(headersTimeout); let responseReceived = false; stream.once("response", (headers2) => { const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers2; request.onResponseStarted(); responseReceived = true; + stream.setTimeout(bodyTimeout); if (request.aborted) { stream.removeAllListeners("data"); return; @@ -8892,12 +8921,11 @@ var require_client_h2 = __commonJS({ if (!request.aborted && !request.completed) { request.onComplete({}); } - client[kQueue][client[kRunningIdx]++] = null; + completeRequest(client, request); client[kResume](); } else { abort(new InformationalError("HTTP/2: stream half-closed (remote)")); - client[kQueue][client[kRunningIdx]++] = null; - client[kPendingIdx] = client[kRunningIdx]; + completeRequest(client, request, true); client[kResume](); } }); @@ -8907,6 +8935,9 @@ var require_client_h2 = __commonJS({ if (session[kOpenStreams] === 0) { session.unref(); } + if (!request.aborted && !request.completed) { + abort(new InformationalError("HTTP/2: stream closed before the response was complete")); + } }); stream.once("error", function(err) { stream.removeAllListeners("data"); @@ -8920,7 +8951,7 @@ var require_client_h2 = __commonJS({ stream.removeAllListeners("data"); }); stream.on("timeout", () => { - const err = new InformationalError(`HTTP/2: "stream timeout after ${requestTimeout}"`); + const err = responseReceived ? new BodyTimeoutError(`HTTP/2: "body timeout after ${bodyTimeout}"`) : new HeadersTimeoutError(`HTTP/2: "headers timeout after ${headersTimeout}"`); stream.removeAllListeners("data"); session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) { @@ -9430,7 +9461,9 @@ var require_client = __commonJS({ const requests = this[kQueue].splice(this[kPendingIdx]); for (let i = 0; i < requests.length; i++) { const request = requests[i]; - util.errorRequest(this, request, err); + if (request != null) { + util.errorRequest(this, request, err); + } } const callback = /* @__PURE__ */ __name(() => { if (this[kClosedResolve]) { @@ -9455,7 +9488,9 @@ var require_client = __commonJS({ const requests = client[kQueue].splice(client[kRunningIdx]); for (let i = 0; i < requests.length; i++) { const request = requests[i]; - util.errorRequest(client, request, err); + if (request != null) { + util.errorRequest(client, request, err); + } } assert(client[kSize] === 0); } @@ -14767,7 +14802,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request.headersList); - if (!requestProtocols.includes(secProtocol)) { + if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { failWebsocketConnection(handler, 1002, "Protocol was not set in the opening handshake."); return; } @@ -14891,6 +14926,7 @@ var require_permessage_deflate = __commonJS({ if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) { callback(new MessageSizeExceededError()); this.#inflate.removeAllListeners(); + this.#inflate.destroy(); this.#inflate = null; return; } @@ -15902,6 +15938,43 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; + var DATA = Buffer.from("data"); + var EVENT = Buffer.from("event"); + var ID = Buffer.from("id"); + var RETRY = Buffer.from("retry"); + function isASCIINumberBytes(buffer, start) { + if (start >= buffer.length) { + return false; + } + for (let i = start; i < buffer.length; i++) { + if (buffer[i] < 48 || buffer[i] > 57) { + return false; + } + } + return true; + } + __name(isASCIINumberBytes, "isASCIINumberBytes"); + function isValidLastEventIdBytes(buffer, start) { + for (let i = start; i < buffer.length; i++) { + if (buffer[i] === 0) { + return false; + } + } + return true; + } + __name(isValidLastEventIdBytes, "isValidLastEventIdBytes"); + function isFieldName(line, length, field) { + if (length !== field.length) { + return false; + } + for (let i = 0; i < length; i++) { + if (line[i] !== field[i]) { + return false; + } + } + return true; + } + __name(isFieldName, "isFieldName"); var EventSourceStream = class extends Transform { static { __name(this, "EventSourceStream"); @@ -15924,10 +15997,13 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer|null} + * @type {Buffer[]} */ - buffer = null; + chunks = []; + chunkIndex = 0; pos = 0; + lineChunkIndex = 0; + linePos = 0; event = { data: void 0, event: void 0, @@ -15959,63 +16035,30 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - if (this.buffer) { - this.buffer = Buffer.concat([this.buffer, chunk]); - } else { - this.buffer = chunk; - } + this.chunks.push(chunk); if (this.checkBOM) { - switch (this.buffer.length) { - case 1: - if (this.buffer[0] === BOM[0]) { - callback(); - return; - } - this.checkBOM = false; - callback(); - return; - case 2: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { - callback(); - return; - } - this.checkBOM = false; - break; - case 3: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { - this.buffer = Buffer.alloc(0); - this.checkBOM = false; - callback(); - return; - } - this.checkBOM = false; - break; - default: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { - this.buffer = this.buffer.subarray(3); - } - this.checkBOM = false; - break; + if (this.handleBOM()) { + callback(); + return; } } - while (this.pos < this.buffer.length) { + while (this.hasCurrentByte()) { + const byte = this.currentByte(); if (this.eventEndCheck) { if (this.crlfCheck) { - if (this.buffer[this.pos] === LF) { - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; + if (byte === LF) { this.crlfCheck = false; + this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { - if (this.buffer[this.pos] === CR) { + if (byte === LF || byte === CR) { + if (byte === CR) { this.crlfCheck = true; } - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; - if (this.event.data !== void 0 || this.event.event || this.event.id !== void 0 || this.event.retry) { + this.consumeCurrentByte(); + if (this.hasPendingEvent()) { this.processEvent(this.event); } this.clearEvent(); @@ -16024,17 +16067,16 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { - if (this.buffer[this.pos] === CR) { + if (byte === LF || byte === CR) { + if (byte === CR) { this.crlfCheck = true; } - this.parseLine(this.buffer.subarray(0, this.pos), this.event); - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; + this.parseLine(this.readLine(), this.event); + this.consumeCurrentByte(); this.eventEndCheck = true; continue; } - this.pos++; + this.advanceCursor(); } callback(); } @@ -16050,43 +16092,42 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let field = ""; - let value = ""; + let fieldLength = line.length; + let valueStart = line.length; if (colonPosition !== -1) { - field = line.subarray(0, colonPosition).toString("utf8"); - let valueStart = colonPosition + 1; + fieldLength = colonPosition; + valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } - value = line.subarray(valueStart).toString("utf8"); - } else { - field = line.toString("utf8"); - value = ""; } - switch (field) { - case "data": - if (event[field] === void 0) { - event[field] = value; - } else { - event[field] += ` + if (isFieldName(line, fieldLength, DATA)) { + const value = line.toString("utf8", valueStart); + if (event.data === void 0) { + event.data = value; + } else { + event.data += ` ${value}`; - } - break; - case "retry": - if (isASCIINumber(value)) { - event[field] = value; - } - break; - case "id": - if (isValidLastEventId(value)) { - event[field] = value; - } - break; - case "event": - if (value.length > 0) { - event[field] = value; - } - break; + } + return; + } + if (isFieldName(line, fieldLength, RETRY)) { + if (isASCIINumberBytes(line, valueStart)) { + event.retry = line.toString("utf8", valueStart); + } + return; + } + if (isFieldName(line, fieldLength, ID)) { + if (isValidLastEventIdBytes(line, valueStart)) { + event.id = line.toString("utf8", valueStart); + } + return; + } + if (isFieldName(line, fieldLength, EVENT)) { + const value = line.toString("utf8", valueStart); + if (value.length > 0) { + event.event = value; + } } } /** @@ -16111,12 +16152,120 @@ ${value}`; } } clearEvent() { - this.event = { - data: void 0, - event: void 0, - id: void 0, - retry: void 0 - }; + this.event.data = void 0; + this.event.event = void 0; + this.event.id = void 0; + this.event.retry = void 0; + } + hasPendingEvent() { + return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; + } + hasCurrentByte() { + return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; + } + currentByte() { + return this.chunks[this.chunkIndex][this.pos]; + } + consumeCurrentByte() { + this.advanceCursor(); + this.syncLineStartToCursor(); + } + advanceCursor() { + this.pos++; + while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { + this.chunkIndex++; + this.pos = 0; + } + } + syncLineStartToCursor() { + this.lineChunkIndex = this.chunkIndex; + this.linePos = this.pos; + this.dropConsumedChunks(); + } + dropConsumedChunks() { + while (this.lineChunkIndex > 0) { + this.chunks.shift(); + this.lineChunkIndex--; + this.chunkIndex--; + } + if (this.chunkIndex === this.chunks.length) { + this.chunks.length = 0; + this.chunkIndex = 0; + this.pos = 0; + this.lineChunkIndex = 0; + this.linePos = 0; + } + } + readLine() { + if (this.lineChunkIndex === this.chunkIndex) { + return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); + } + const chunks = []; + let length = 0; + for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { + const chunk = this.chunks[i]; + const start = i === this.lineChunkIndex ? this.linePos : 0; + const end = i === this.chunkIndex ? this.pos : chunk.length; + const slice = chunk.subarray(start, end); + length += slice.length; + chunks.push(slice); + } + return Buffer.concat(chunks, length); + } + peekBufferedByte(offset) { + let chunkIndex = this.lineChunkIndex; + let pos = this.linePos; + while (chunkIndex < this.chunks.length) { + const chunk = this.chunks[chunkIndex]; + const remaining = chunk.length - pos; + if (offset < remaining) { + return chunk[pos + offset]; + } + offset -= remaining; + chunkIndex++; + pos = 0; + } + } + discardLeadingBytes(count) { + while (count > 0 && this.lineChunkIndex < this.chunks.length) { + const chunk = this.chunks[this.lineChunkIndex]; + const remaining = chunk.length - this.linePos; + if (count < remaining) { + this.linePos += count; + count = 0; + } else { + count -= remaining; + this.lineChunkIndex++; + this.linePos = 0; + } + } + this.chunkIndex = this.lineChunkIndex; + this.pos = this.linePos; + this.dropConsumedChunks(); + } + handleBOM() { + const first = this.peekBufferedByte(0); + const second = this.peekBufferedByte(1); + const third = this.peekBufferedByte(2); + if (second === void 0) { + if (first === BOM[0]) { + return true; + } + this.checkBOM = false; + return true; + } + if (third === void 0) { + if (first === BOM[0] && second === BOM[1]) { + return true; + } + this.checkBOM = false; + return false; + } + if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { + this.discardLeadingBytes(3); + } + this.checkBOM = false; + return !this.hasCurrentByte(); } }; module2.exports = { diff --git a/deps/uv/src/win/fs-event.c b/deps/uv/src/win/fs-event.c index fd77f2a49784..5cb7caea9ac8 100644 --- a/deps/uv/src/win/fs-event.c +++ b/deps/uv/src/win/fs-event.c @@ -63,13 +63,17 @@ static void uv__fs_event_queue_readdirchanges(uv_loop_t* loop, handle->req_pending = 1; } -static void uv__relative_path(const WCHAR* filename, - const WCHAR* dir, - WCHAR** relpath) { +/* Compute the path of `filename` relative to the watched directory `dir`. + * Returns 0 on success, -1 if `filename` is not actually prefixed by `dir`, + * which can happen if the directory is a short path. */ +static int uv__relative_path(const WCHAR* filename, + const WCHAR* dir, + WCHAR** relpath) { size_t relpathlen; size_t filenamelen = wcslen(filename); size_t dirlen = wcslen(dir); - assert(!_wcsnicmp(filename, dir, dirlen)); + if (filenamelen <= dirlen || _wcsnicmp(filename, dir, dirlen) != 0) + return -1; if (dirlen > 0 && dir[dirlen - 1] == '\\') dirlen--; relpathlen = filenamelen - dirlen - 1; @@ -78,6 +82,7 @@ static void uv__relative_path(const WCHAR* filename, uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); wcsncpy(*relpath, filename + dirlen + 1, relpathlen); (*relpath)[relpathlen] = L'\0'; + return 0; } static int uv__split_path(const WCHAR* filename, WCHAR** dir, @@ -517,12 +522,21 @@ void uv__process_fs_event_req(uv_loop_t* loop, uv_req_t* req, if (long_filenamew) { /* Get the file name out of the long path. */ - uv__relative_path(long_filenamew, - handle->dirw, - &filenamew); - uv__free(long_filenamew); - long_filenamew = filenamew; - sizew = -1; + if (uv__relative_path(long_filenamew, + handle->dirw, + &filenamew) == 0) { + uv__free(long_filenamew); + long_filenamew = filenamew; + sizew = -1; + } else { + /* The resolved long path was not prefixed by the watched + * directory (e.g. short name vs long name mismatch), + * fall back to the name given by ReadDirectoryChangesW. */ + uv__free(long_filenamew); + long_filenamew = NULL; + filenamew = file_info->FileName; + sizew = file_info->FileNameLength / sizeof(WCHAR); + } } else { /* We couldn't get the long filename, use the one reported. */ filenamew = file_info->FileName; diff --git a/deps/uv/test/test-fs-event.c b/deps/uv/test/test-fs-event.c index f224181fc368..103e74aed967 100644 --- a/deps/uv/test/test-fs-event.c +++ b/deps/uv/test/test-fs-event.c @@ -587,32 +587,107 @@ TEST_IMPL(fs_event_watch_dir_recursive) { } #ifdef _WIN32 +static char short_path_file[MAX_PATH]; + +static void short_path_timer_cb(uv_timer_t* handle) { + ++timer_cb_called; + touch_file(short_path_file); +} + +/* Try to create a unique watch directory that has a 8.3 short component + under `parent` ("" means the cwd). If it's successful, fills `watch_dir` + and `short_dir` with the long and short forms of the created directory + respectively, and returns 1. Otherwise removes the directory created + and returns 0. */ +static int short_path_make(const char* parent, + char* watch_dir, size_t watch_n, + char* short_dir, size_t short_n) { + uv_fs_t req; + char tmpl[MAX_PATH]; + WCHAR watch_dirw[MAX_PATH]; + WCHAR short_dirw[MAX_PATH]; + WCHAR long_dirw[MAX_PATH]; + size_t pathlen; + int r; + + if (parent[0] != '\0') + r = snprintf(tmpl, sizeof(tmpl), "%s\\watch_dirXXXXXX", parent); + else + r = snprintf(tmpl, sizeof(tmpl), "watch_dirXXXXXX"); + if (r < 0 || (size_t) r >= sizeof(tmpl)) + return 0; + + r = uv_fs_mkdtemp(NULL, &req, tmpl, NULL); + if (r != 0) { + uv_fs_req_cleanup(&req); + return 0; + } + + /* Copy the created path out before cleaning up the request that owns it. */ + pathlen = strlen(req.path); + memcpy(watch_dir, req.path, pathlen + 1); + uv_fs_req_cleanup(&req); + + /* The caller appends "\\file1" to both watch_dir and short_dir. If there is + no room for that suffix, skip this location. */ + if (pathlen + sizeof("\\file1") <= watch_n && + MultiByteToWideChar(CP_UTF8, 0, watch_dir, -1, + watch_dirw, ARRAY_SIZE(watch_dirw)) != 0 && + GetShortPathNameW(watch_dirw, short_dirw, ARRAY_SIZE(short_dirw)) != 0 && + GetLongPathNameW(watch_dirw, long_dirw, ARRAY_SIZE(long_dirw)) != 0 && + _wcsicmp(short_dirw, long_dirw) != 0 && + WideCharToMultiByte(CP_UTF8, 0, short_dirw, -1, + short_dir, (int) short_n, NULL, NULL) != 0) + return 1; + + uv_fs_rmdir(NULL, &req, watch_dir, NULL); + uv_fs_req_cleanup(&req); + return 0; +} + TEST_IMPL(fs_event_watch_dir_short_path) { uv_loop_t* loop; - uv_fs_t req; + char temp_path[MAX_PATH]; + char watch_dir[MAX_PATH]; + char watch_file[MAX_PATH]; + char short_dir[MAX_PATH]; + size_t temp_len; int has_shortnames; int r; - /* Setup */ loop = uv_default_loop(); - delete_file("watch_dir/file1"); - delete_dir("watch_dir/"); - create_dir("watch_dir"); - create_file("watch_dir/file1"); - /* Newer version of Windows ship with - HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\NtfsDisable8dot3NameCreation - not equal to 0. So we verify the files we created are addressable by a 8.3 - short name */ - has_shortnames = uv_fs_stat(NULL, &req, "watch_~1", NULL) != UV_ENOENT; + /* This test needs the watched directory to have an 8.3 short component. The + generated "watch_dirXXXXXX" name is > 8 chars, so it gets a short alias on + volumes where 8.3 name creation is enabled. For non-system volumes on + newer Windows it's disabled by default (NtfsDisable8dot3NameCreation=3). + The temp dir and the cwd may be on different volumes, so try each and use + whichever has a short alias, and skip if neither does. */ + has_shortnames = 0; + temp_len = sizeof(temp_path); + if (uv_os_tmpdir(temp_path, &temp_len) == 0) + has_shortnames = short_path_make(temp_path, + watch_dir, sizeof(watch_dir), + short_dir, sizeof(short_dir)); + if (!has_shortnames) + has_shortnames = short_path_make("", + watch_dir, sizeof(watch_dir), + short_dir, sizeof(short_dir)); + if (has_shortnames) { + snprintf(watch_file, sizeof(watch_file), "%s\\file1", watch_dir); + /* short_path_file is used in the timer callback to touch the file. */ + snprintf(short_path_file, sizeof(short_path_file), "%s\\file1", short_dir); + /* The directory was just created, so file1 cannot exist yet. */ + create_file(watch_file); + r = uv_fs_event_init(loop, &fs_event); ASSERT_OK(r); - r = uv_fs_event_start(&fs_event, fs_event_cb_dir, "watch_~1", 0); + r = uv_fs_event_start(&fs_event, fs_event_cb_dir, short_dir, 0); ASSERT_OK(r); r = uv_timer_init(loop, &timer); ASSERT_OK(r); - r = uv_timer_start(&timer, timer_cb_file, 100, 0); + r = uv_timer_start(&timer, short_path_timer_cb, 100, 0); ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); @@ -620,12 +695,11 @@ TEST_IMPL(fs_event_watch_dir_short_path) { ASSERT_EQ(1, fs_event_cb_called); ASSERT_EQ(1, timer_cb_called); ASSERT_EQ(1, close_cb_called); + /* Cleanup */ + delete_file(watch_file); + delete_dir(watch_dir); } - /* Cleanup */ - delete_file("watch_dir/file1"); - delete_dir("watch_dir/"); - MAKE_VALGRIND_HAPPY(loop); if (!has_shortnames) diff --git a/deps/zlib/google/OWNERS b/deps/zlib/google/OWNERS index 1bd83ac482ee..901c226205f8 100644 --- a/deps/zlib/google/OWNERS +++ b/deps/zlib/google/OWNERS @@ -1,4 +1,4 @@ -satorux@chromium.org +satorux@google.com # compression_utils* asvitkine@chromium.org diff --git a/deps/zlib/google/zip_reader_unittest.cc b/deps/zlib/google/zip_reader_unittest.cc index 578539ffbf76..6e58f7f72ee8 100644 --- a/deps/zlib/google/zip_reader_unittest.cc +++ b/deps/zlib/google/zip_reader_unittest.cc @@ -35,7 +35,6 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" -#include "third_party/icu/source/i18n/unicode/timezone.h" #include "third_party/zlib/google/zip_internal.h" using ::testing::_; @@ -367,10 +366,8 @@ TEST_F(ZipReaderTest, RegularFile) { EXPECT_EQ(target_path, entry->path); EXPECT_EQ(13527, entry->original_size); - EXPECT_EQ("2009-05-29 06:22:20.000", - base::UnlocalizedTimeFormatWithPattern(entry->last_modified, - "y-MM-dd HH:mm:ss.SSS", - icu::TimeZone::getGMT())); + EXPECT_EQ("2009-05-29T06:22:20.000Z", + base::TimeFormatAsIso8601(entry->last_modified)); EXPECT_FALSE(entry->is_unsafe); EXPECT_FALSE(entry->is_directory); } @@ -467,10 +464,8 @@ TEST_F(ZipReaderTest, Directory) { EXPECT_EQ(target_path, entry->path); // The directory size should be zero. EXPECT_EQ(0, entry->original_size); - EXPECT_EQ("2009-05-31 15:49:52.000", - base::UnlocalizedTimeFormatWithPattern(entry->last_modified, - "y-MM-dd HH:mm:ss.SSS", - icu::TimeZone::getGMT())); + EXPECT_EQ("2009-05-31T15:49:52.000Z", + base::TimeFormatAsIso8601(entry->last_modified)); EXPECT_FALSE(entry->is_unsafe); EXPECT_TRUE(entry->is_directory); } diff --git a/doc/api/assert.md b/doc/api/assert.md index a641522b7689..4c70c895e394 100644 --- a/doc/api/assert.md +++ b/doc/api/assert.md @@ -294,7 +294,7 @@ const assert2 = new Assert({ skipPrototype: true }); assert2.deepStrictEqual(foo, bar); // OK ``` -When destructured, methods lose access to the instance's `this` context and revert to default assertion behavior +When destructured, methods lose access to the instance's `this` context and revert to the default assertion behavior (diff: 'simple', non-strict mode). To maintain custom options when using destructured methods, avoid destructuring and call methods directly on the instance. @@ -710,8 +710,8 @@ are also recursively evaluated by the following rules. ### Comparison details * Primitive values are compared with the [`==` operator][], - with the exception of {NaN}. It is treated as being identical in case - both sides are {NaN}. + except for {NaN}, which is treated as identical when both + sides are {NaN}. * [Type tags][Object.prototype.toString()] of objects should be the same. * Only [enumerable "own" properties][] are considered. * Object constructors are compared when available. @@ -1210,7 +1210,7 @@ error messages as expressive as possible. If specified, `error` can be a [`Class`][], {RegExp} or a validation function. See [`assert.throws()`][] for more details. -Besides the async nature to await the completion behaves identically to +Aside from asynchronously awaiting completion, it behaves identically to [`assert.doesNotThrow()`][]. ```mjs diff --git a/doc/api/buffer.md b/doc/api/buffer.md index e34d614f7957..6a6c136353f2 100644 --- a/doc/api/buffer.md +++ b/doc/api/buffer.md @@ -536,6 +536,8 @@ added: - v20.16.0 --> +* Returns: {Promise} + The `blob.bytes()` method returns the byte of the `Blob` object as a `Promise`. ```js @@ -566,6 +568,7 @@ added: * `start` {number} The starting index. * `end` {number} The ending index. * `type` {string} The content-type for the new `Blob` +* Returns: {Blob} Creates and returns a new `Blob` containing a subset of this `Blob` objects data. The original `Blob` is not altered. @@ -5248,6 +5251,7 @@ added: > Stability: 3 - Legacy. Use `Buffer.from(data, 'base64')` instead. * `data` {any} The Base64-encoded input string. +* Returns: {string} Decodes a string of Base64-encoded data into bytes, and encodes those bytes into a string using Latin-1 (ISO-8859-1). @@ -5278,6 +5282,7 @@ added: > Stability: 3 - Legacy. Use `buf.toString('base64')` instead. * `data` {any} An ASCII (Latin1) string. +* Returns: {string} Decodes a string into bytes using Latin-1 (ISO-8859), and encodes those bytes into a string using Base64. @@ -5303,6 +5308,11 @@ npx codemod@latest @nodejs/buffer-atob-btoa added: - v19.6.0 - v18.15.0 +changes: + - version: v24.21.0 + pr-url: https://github.com/nodejs/node/pull/64504 + description: Detached `ArrayBuffer`s and views backed by them are treated + as empty. --> * `input` {Buffer | ArrayBuffer | TypedArray} The input to validate. @@ -5311,7 +5321,7 @@ added: This function returns `true` if `input` contains only valid ASCII-encoded data, including the case in which `input` is empty. -Throws if the `input` is a detached array buffer. +A detached `ArrayBuffer`, or a `TypedArray` backed by one, is treated as empty. ### `buffer.isUtf8(input)` @@ -5319,6 +5329,11 @@ Throws if the `input` is a detached array buffer. added: - v19.4.0 - v18.14.0 +changes: + - version: v24.21.0 + pr-url: https://github.com/nodejs/node/pull/64504 + description: Detached `ArrayBuffer`s and views backed by them are treated + as empty. --> * `input` {Buffer | ArrayBuffer | TypedArray} The input to validate. @@ -5327,7 +5342,7 @@ added: This function returns `true` if `input` contains only valid UTF-8-encoded data, including the case in which `input` is empty. -Throws if the `input` is a detached array buffer. +A detached `ArrayBuffer`, or a `TypedArray` backed by one, is treated as empty. ### `buffer.INSPECT_MAX_BYTES` diff --git a/doc/api/child_process.md b/doc/api/child_process.md index 4cb444dbd7d9..77db426c668b 100644 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -1714,10 +1714,14 @@ may not actually terminate the process. See kill(2) for reference. -On Windows, where POSIX signals do not exist, the `signal` argument will be -ignored except for `'SIGKILL'`, `'SIGTERM'`, `'SIGINT'` and `'SIGQUIT'`, and the -process will always be killed forcefully and abruptly (similar to `'SIGKILL'`). -See [Signal Events][] for more details. +On Windows, where POSIX signals do not exist, signals are handled as follows. +`'SIGKILL'`, `'SIGTERM'`, `'SIGINT'` and `'SIGQUIT'` terminate the process +forcefully and abruptly (similar to `'SIGKILL'`); any other signal whose name is +known on Windows (such as `'SIGHUP'`) does the same. `'SIGWINCH'` is not +terminal and is not coerced: `subprocess.kill()` throws an `ENOSYS` error and +the child keeps running. A signal name that does not exist on Windows (such as +`'SIGSTOP'`) throws an `ERR_UNKNOWN_SIGNAL` error. See [Signal Events][] for more +details. On Linux, child processes of child processes will not be terminated when attempting to kill their parent. This is likely to happen when running a diff --git a/doc/api/cli.md b/doc/api/cli.md index 86a644418033..801b017bc5a9 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -293,6 +293,25 @@ Error: connect ERR_ACCESS_DENIED Access to this API has been restricted. Use --a } ``` +### `--allow-openssl-store` + + + +> Stability: 1.1 - Active development + +When using the [Permission Model][], the process will not be able to use +OpenSSL STORE loaders by default, for example to load a private key from a +{URL} passed to [`crypto.createPrivateKey()`][]. Attempts to do so will throw +an `ERR_ACCESS_DENIED` unless the user explicitly passes the +`--allow-openssl-store` flag. This permission can be dropped at runtime via +[`permission.drop()`][]. + +This flag grants broad authority to configured OpenSSL STORE loaders. A loader +may access files, devices, tokens, or the network. Access performed by a loader +is not constrained by the `fs.read` or `fs.write` permission scopes. + ### `--allow-wasi` -Enable FIPS-compliant crypto at startup. (Requires Node.js to be built -against FIPS-compatible OpenSSL.) +Enable [FIPS mode][] at startup. With OpenSSL 3, a configured provider named +`fips` must be available and initialize successfully. With OpenSSL 1.1.1, +Node.js must be built against a FIPS-capable OpenSSL. ### `--enable-network-family-autoselection` @@ -1358,25 +1378,6 @@ added: Enable experimental support for the worker inspection with Chrome DevTools. -### `--expose-gc` - - - -> Stability: 1 - Experimental. This flag is inherited from V8 and is subject to -> change upstream. - -This flag will expose the gc extension from V8. - -```js -if (globalThis.gc) { - globalThis.gc(); -} -``` - ### `--force-context-aware` -Force FIPS-compliant crypto on startup. (Cannot be disabled from script code.) -(Same requirements as `--enable-fips`.) +Enable [FIPS mode][] at startup and prevent it from being disabled from script +code. The same OpenSSL requirements as [`--enable-fips`][] apply. ### `--force-node-api-uncaught-exceptions-policy` @@ -2067,9 +2068,11 @@ usually only useful for developers debugging Node.js itself. added: v6.9.0 --> -Load an OpenSSL configuration file on startup. Among other uses, this can be -used to enable FIPS-compliant crypto if Node.js is built -against FIPS-enabled OpenSSL. +Load an OpenSSL configuration file on startup. The file can activate an +OpenSSL 3 FIPS provider or configure a FIPS-capable OpenSSL 1.1.1 build. See +[FIPS mode][]. + +This option takes precedence over the `OPENSSL_CONF` environment variable. ### `--openssl-legacy-provider` @@ -2139,6 +2142,7 @@ following permissions are restricted: * Worker Threads - manageable through [`--allow-worker`][] flag * WASI - manageable through [`--allow-wasi`][] flag * Addons - manageable through [`--allow-addons`][] flag +* OpenSSL STORE loaders - manageable through [`--allow-openssl-store`][] flag ### `--permission-audit` @@ -3605,6 +3609,7 @@ one is included in the list below. * `--allow-fs-read` * `--allow-fs-write` * `--allow-inspector` +* `--allow-openssl-store` * `--allow-wasi` * `--allow-worker` * `--conditions`, `-C` @@ -4014,12 +4019,18 @@ environment variable is arbitrary. added: v6.11.0 --> -Load an OpenSSL configuration file on startup. Among other uses, this can be -used to enable FIPS-compliant crypto if Node.js is built with -`./configure --openssl-fips`. +Load an OpenSSL configuration file on startup. The file can be used as part of +a [FIPS mode][] configuration. + +If the variable is set to an empty value, Node.js starts without loading any +OpenSSL configuration file. This is a way past a default configuration file +that exists but cannot be read, for example when `/etc/ssl` is not accessible +to the user Node.js runs as, which is otherwise fatal at startup. No +configuration is applied in that case, including any [FIPS mode][] setup the +file would have performed. If the [`--openssl-config`][] command-line option is used, the environment -variable is ignored. +variable is ignored, and an empty value has no effect. ### `SSL_CERT_DIR=dir` @@ -4223,6 +4234,7 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12 [ECMAScript module]: esm.md#modules-ecmascript-modules [EventSource Web API]: https://html.spec.whatwg.org/multipage/server-sent-events.html#server-sent-events [ExperimentalWarning: `vm.measureMemory` is an experimental feature]: vm.md#vmmeasurememoryoptions +[FIPS mode]: crypto.md#fips-mode [File System Permissions]: permissions.md#file-system-permissions [Loading ECMAScript modules using `require()`]: modules.md#loading-ecmascript-modules-using-require [Module resolution and loading]: packages.md#module-resolution-and-loading @@ -4244,12 +4256,14 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12 [`--allow-child-process`]: #--allow-child-process [`--allow-fs-read`]: #--allow-fs-read [`--allow-fs-write`]: #--allow-fs-write +[`--allow-openssl-store`]: #--allow-openssl-store [`--allow-wasi`]: #--allow-wasi [`--allow-worker`]: #--allow-worker [`--build-snapshot`]: #--build-snapshot [`--cpu-prof-dir`]: #--cpu-prof-dir [`--diagnostic-dir`]: #--diagnostic-dirdirectory [`--disable-sigusr1`]: #--disable-sigusr1 +[`--enable-fips`]: #--enable-fips [`--env-file-if-exists`]: #--env-file-if-existsfile [`--env-file`]: #--env-filefile [`--experimental-sea-config`]: single-executable-applications.md#generating-single-executable-preparation-blobs @@ -4276,6 +4290,7 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12 [`SlowBuffer`]: buffer.md#class-slowbuffer [`Web Storage`]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API [`YoungGenerationSizeFromSemiSpaceSize`]: https://chromium.googlesource.com/v8/v8.git/+/refs/tags/10.3.129/src/heap/heap.cc#328 +[`crypto.createPrivateKey()`]: crypto.md#cryptocreateprivatekeykey [`dns.lookup()`]: dns.md#dnslookuphostname-options-callback [`dns.setDefaultResultOrder()`]: dns.md#dnssetdefaultresultorderorder [`dnsPromises.lookup()`]: dns.md#dnspromiseslookuphostname-options @@ -4284,6 +4299,7 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12 [`net.getDefaultAutoSelectFamilyAttemptTimeout()`]: net.md#netgetdefaultautoselectfamilyattempttimeout [`node:sqlite`]: sqlite.md [`node:stream/iter`]: stream_iter.md +[`permission.drop()`]: permissions.md#permissiondropscope-reference [`process.setUncaughtExceptionCaptureCallback()`]: process.md#processsetuncaughtexceptioncapturecallbackfn [`tls.DEFAULT_MAX_VERSION`]: tls.md#tlsdefault_max_version [`tls.DEFAULT_MIN_VERSION`]: tls.md#tlsdefault_min_version @@ -4297,7 +4313,7 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12 [conditional exports]: packages.md#conditional-exports [context-aware]: addons.md#context-aware-addons [debugger]: debugger.md -[debugging security implications]: https://nodejs.org/en/docs/guides/debugging-getting-started/#security-implications +[debugging security implications]: https://nodejs.org/learn/getting-started/debugging#security-implications [deprecation warnings]: deprecations.md#list-of-deprecated-apis [emit_warning]: process.md#processemitwarningwarning-options [environment_variables]: #environment-variables_1 @@ -4312,7 +4328,7 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12 [running tests from the command line]: test.md#running-tests-from-the-command-line [scavenge garbage collector]: https://v8.dev/blog/orinoco-parallel-scavenger [security warning]: #warning-binding-inspector-to-a-public-ipport-combination-is-insecure -[semi-space]: https://www.memorymanagement.org/glossary/s.html#semi.space +[semi-space]: https://v8.dev/blog/trash-talk#minor-gc [single executable application]: single-executable-applications.md [snapshot testing]: test.md#snapshot-testing [syntax detection]: packages.md#syntax-detection diff --git a/doc/api/crypto.md b/doc/api/crypto.md index ca7ca7fef459..24de83cfb25f 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -2654,7 +2654,7 @@ changes: -* `privateKey` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView|KeyObject|CryptoKey} +* `privateKey` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView|KeyObject|CryptoKey|URL} * `dsaEncoding` {string} * `padding` {integer} * `saltLength` {integer} @@ -3939,6 +3939,10 @@ input.on('readable', () => { -* `key` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView} - * `key` {string|ArrayBuffer|Buffer|TypedArray|DataView|Object} The key - material, either in PEM, DER, JWK, or raw format. +* `key` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView|URL} + * `key` {string|ArrayBuffer|Buffer|TypedArray|DataView|Object|URL} The key + material, either in PEM, DER, JWK, or raw format, or a {URL} referencing an + object for an OpenSSL STORE loader. * `format` {string} Must be `'pem'`, `'der'`, `'jwk'`, `'raw-private'`, or `'raw-seed'`. **Default:** `'pem'`. * `type` {string} Must be `'pkcs1'`, `'pkcs8'` or `'sec1'`. This option is required only if the `format` is `'der'` and ignored otherwise. - * `passphrase` {string | Buffer} The passphrase to use for decryption. + * `passphrase` {string | Buffer} The passphrase to use for decryption. When + `key` is a {URL}, this is the optional PIN/passphrase forwarded to the + STORE loader. + * `properties` {string} The optional OpenSSL property query used when + fetching the STORE loader for a {URL} key. * `encoding` {string} The string encoding to use when `key` is a string. * `asymmetricKeyType` {string} Required when `format` is `'raw-private'` or `'raw-seed'` and ignored otherwise. @@ -3986,6 +3995,46 @@ must be an object with the properties described above. If the private key is encrypted, a `passphrase` must be specified. The length of the passphrase is limited to 1024 bytes. +#### Private keys from OpenSSL STORE loaders + +> Stability: 1.1 - Active development + +If `key` is a {URL} (or an object whose `key` is a {URL}), the private key is +loaded through an OpenSSL STORE loader. The URL is passed to OpenSSL as a URI, +for example a `file:` URI or a provider-backed scheme such as `pkcs11:`. When +the [Permission Model][] is enabled, [`--allow-openssl-store`][] is required. + +> **Warning**: A URI scheme does not pin an OpenSSL STORE loader or prove where +> the returned key came from. Node.js forwards the URI to OpenSSL, which chooses +> loaders according to its version and configuration. For example, OpenSSL may +> offer an opaque URI such as `pkcs11:object=...` (one without `//` after the +> scheme) to its `file` loader before trying the `pkcs11` loader. If the complete +> URI is a valid local path and that file exists, it may be loaded instead. +> Node.js does not verify which loader supplied the key. Do not rely on a +> provider-specific URI scheme as proof that a key came from that provider or +> from a hardware device. + +Configured OpenSSL STORE loaders have broad authority and may access files, +devices, tokens, or the network. Access performed by a loader is not constrained +by the `fs.read` or `fs.write` permission scopes. + +When a {URL} is used, `format`, `type`, `asymmetricKeyType`, and `namedCurve` +are ignored even when those options would otherwise depend on each other, such +as `type` with `format: 'der'` or `namedCurve` with +`asymmetricKeyType: 'ec'`. The input is passed to the STORE loader as a URI, +not handled as PEM, DER, JWK, or raw key material. `passphrase` is still used as +the optional PIN/passphrase passed to the loader, and `encoding` applies if that +`passphrase` is a string. + +Use `passphrase` instead of embedding credentials in the URI passed to the +STORE loader. Node.js redacts the URI from its own permission-denial resource +and diagnostics. Errors reported by OpenSSL or a provider after loading begins +may include the URI. + +When `properties` is specified with a {URL} key, it is passed to OpenSSL as the +property query for selecting the STORE loader. It is not appended to the URL and +is distinct from provider-specific URI parameters. + ### `crypto.createPublicKey(key)` -* `key` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView|KeyObject} Private Key +* `key` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView|KeyObject|URL} Private Key * `ciphertext` {ArrayBuffer|Buffer|TypedArray|DataView} * `callback` {Function} * `err` {Error} @@ -4164,7 +4217,7 @@ changes: --> * `options` {Object} - * `privateKey` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView|KeyObject} + * `privateKey` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView|KeyObject|URL} * `publicKey` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView|KeyObject} * `callback` {Function} * `err` {Error} @@ -4227,11 +4280,8 @@ deprecated: v10.0.0 > Stability: 0 - Deprecated -Property for checking and controlling whether a FIPS compliant crypto provider -is currently in use. Setting to true requires a FIPS build of Node.js. - -This property is deprecated. Please use `crypto.setFips()` and -`crypto.getFips()` instead. +Deprecated property for checking and controlling [FIPS mode][]. Use +[`crypto.getFips()`][] and [`crypto.setFips()`][] instead. ### `crypto.generateKey(type, options, callback)` @@ -4822,9 +4872,14 @@ console.log(aliceSecret === bobSecret); added: v10.0.0 --> -* Returns: {number} `1` if and only if a FIPS compliant crypto provider is - currently in use, `0` otherwise. A future semver-major release may change - the return type of this API to a {boolean}. +* Returns: {number} `1` if FIPS mode is enabled, `0` otherwise. A future + semver-major release may change the return type of this API to a {boolean}. + +With OpenSSL 3, this reports whether the default property query includes +`fips=yes`. It does not establish that a FIPS provider is loaded or validated. +It can return `1` even when a requested cryptographic implementation cannot be +fetched because no loaded provider supplies a match for `fips=yes`. See [FIPS +mode][]. ### `crypto.getHashes()` @@ -5152,6 +5207,10 @@ negative performance implications for some applications; see the -* `password` {string|Buffer|TypedArray|DataView} -* `salt` {string|Buffer|TypedArray|DataView} +* `password` {string|ArrayBuffer|Buffer|TypedArray|DataView} +* `salt` {string|ArrayBuffer|Buffer|TypedArray|DataView} * `iterations` {number} * `keylen` {number} * `digest` {string} @@ -5243,7 +5302,7 @@ changes: -* `privateKey` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView|KeyObject|CryptoKey} +* `privateKey` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView|KeyObject|CryptoKey|URL} * `oaepHash` {string} The hash function to use for OAEP padding and MGF1. **Default:** `'sha1'` * `oaepLabel` {string|ArrayBuffer|Buffer|TypedArray|DataView} The label to @@ -5288,9 +5347,10 @@ changes: -* `privateKey` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView|KeyObject|CryptoKey} - * `key` {string|ArrayBuffer|Buffer|TypedArray|DataView|KeyObject|CryptoKey} - A PEM encoded private key. +* `privateKey` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView|KeyObject|CryptoKey|URL} + * `key` {string|ArrayBuffer|Buffer|TypedArray|DataView|KeyObject|CryptoKey|URL} + The private key material, a {KeyObject}, {CryptoKey}, or a {URL} + referencing an object for an OpenSSL STORE loader. * `passphrase` {string|ArrayBuffer|Buffer|TypedArray|DataView} An optional passphrase for the private key. * `padding` {crypto.constants} An optional padding value defined in @@ -5524,9 +5584,12 @@ changes: * `buffer` {ArrayBuffer|Buffer|TypedArray|DataView} Must be supplied. The size of the provided `buffer` must not be larger than `2**31 - 1`. -* `offset` {number} **Default:** `0` -* `size` {number} **Default:** `buffer.length - offset`. The `size` must - not be larger than `2**31 - 1`. +* `offset` {number} The start position, in elements for a `TypedArray` and in + bytes for an `ArrayBuffer` or `DataView`. **Default:** `0` +* `size` {number} The amount to fill, in the same units as `offset`. + **Default:** `buffer.length - offset` for a `TypedArray`, or + `buffer.byteLength - offset` for an `ArrayBuffer` or `DataView`. The `size` + must not be larger than `2**31 - 1`. * `callback` {Function} `function(err, buf) {}`. This function is similar to [`crypto.randomBytes()`][] but requires the first @@ -5661,9 +5724,12 @@ changes: * `buffer` {ArrayBuffer|Buffer|TypedArray|DataView} Must be supplied. The size of the provided `buffer` must not be larger than `2**31 - 1`. -* `offset` {number} **Default:** `0` -* `size` {number} **Default:** `buffer.length - offset`. The `size` must - not be larger than `2**31 - 1`. +* `offset` {number} The start position, in elements for a `TypedArray` and in + bytes for an `ArrayBuffer` or `DataView`. **Default:** `0` +* `size` {number} The amount to fill, in the same units as `offset`. + **Default:** `buffer.length - offset` for a `TypedArray`, or + `buffer.byteLength - offset` for an `ArrayBuffer` or `DataView`. The `size` + must not be larger than `2**31 - 1`. * Returns: {ArrayBuffer|Buffer|TypedArray|DataView} The object passed as `buffer` argument. @@ -6089,10 +6155,33 @@ is a bit field taking one of or a mix of the following flags (defined in added: v10.0.0 --> -* `bool` {boolean} `true` to enable FIPS mode. +* `bool` {boolean} `true` to enable FIPS mode, `false` to disable it. -Enables the FIPS compliant crypto provider in a FIPS-enabled Node.js build. -Throws an error if FIPS mode is not available. +Changes [FIPS mode][]. With OpenSSL 3, this only adds or removes `fips=yes` in +the default property query. It does not install, load, initialize, or validate +a FIPS provider. For a usable FIPS configuration, install the provider and +configure OpenSSL to load it when Node.js starts, as described in [FIPS +mode][]. + +If no loaded provider supplies a requested cryptographic implementation +matching `fips=yes`, the call can still succeed and `crypto.getFips()` can still +return `1`, but fetching that implementation fails. Affected `node:crypto` +operations typically fail with `ERR_OSSL_EVP_UNSUPPORTED`. Operations that do +not require a new fetch, including those using previously fetched +implementations or initialized operation contexts, may still succeed. Call this +method during application initialization, before application code uses other +OpenSSL-backed APIs. + +This method only affects subsequent algorithm fetches. Node.js initializes some +OpenSSL state before application code runs. When the property query must be +active from process startup, set `default_properties = fips=yes` in the OpenSSL +configuration or use [`--enable-fips`][] or [`--force-fips`][]. The command-line +flags additionally require a configured provider named `fips` to initialize and +pass its self-test; Node.js fails to start otherwise. + +Throws an error if OpenSSL cannot change the state. FIPS mode cannot be +disabled when Node.js was started with `--force-fips`. With OpenSSL 1.1.1, +enabling FIPS mode requires a FIPS-capable OpenSSL build. ### `crypto.sign(algorithm, data, key[, callback])` @@ -6130,7 +6219,7 @@ changes: * `algorithm` {string | null | undefined} * `data` {ArrayBuffer|Buffer|SharedArrayBuffer|TypedArray|DataView|string} -* `key` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView|KeyObject|CryptoKey} +* `key` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView|KeyObject|CryptoKey|URL} * `callback` {Function} * `err` {Error} * `signature` {Buffer} @@ -6527,83 +6616,120 @@ console.log(receivedPlaintext); ### FIPS mode -When using OpenSSL 3, Node.js supports FIPS 140-2 when used with an appropriate -OpenSSL 3 provider, such as the [FIPS provider from OpenSSL 3][] which can be -installed by following the instructions in [OpenSSL's FIPS README file][]. +Node.js exposes the FIPS support provided by the linked OpenSSL library. Node.js +is not itself FIPS validated. Validation belongs to a specific OpenSSL module or +provider and only applies when it is deployed according to its security policy. +Vendor-provided Node.js or OpenSSL builds can require a different configuration; +follow the vendor's documentation for those builds. + +With OpenSSL 1.1.1, Node.js must be built against a FIPS-capable OpenSSL library. -For FIPS support in Node.js you will need: +With OpenSSL 3, FIPS support uses the provider model described in the +[OpenSSL FIPS module guide][]. Using FIPS-approved implementations requires: * A correctly installed OpenSSL 3 FIPS provider. * An OpenSSL 3 [FIPS module configuration file][]. -* An OpenSSL 3 configuration file that references the FIPS module - configuration file. +* The FIPS provider to be loaded into the OpenSSL library context used by + Node.js, normally by activating it in an OpenSSL configuration file when + Node.js starts. +* The default property query to include `fips=yes` when cryptographic + implementations are fetched. This can be set from process startup by the + OpenSSL configuration, [`--enable-fips`][], or [`--force-fips`][], or for + subsequent fetches by `crypto.setFips(true)`. -Node.js will need to be configured with an OpenSSL configuration file that -points to the FIPS provider. An example configuration file looks like this: +An example OpenSSL 3 configuration file looks like this: ```text nodejs_conf = nodejs_init +config_diagnostics = 1 .include //fipsmodule.cnf [nodejs_init] providers = provider_sect +alg_section = algorithm_sect [provider_sect] -default = default_sect # The fips section name should match the section name inside the # included fipsmodule.cnf. fips = fips_sect +base = base_sect -[default_sect] +[base_sect] activate = 1 -``` - -where `fipsmodule.cnf` is the FIPS module configuration file generated from the -FIPS provider installation step: -```bash -openssl fipsinstall +[algorithm_sect] +default_properties = fips=yes ``` -Set the `OPENSSL_CONF` environment variable to point to -your configuration file and `OPENSSL_MODULES` to the location of the FIPS -provider dynamic library. e.g. +The `fipsmodule.cnf` file is generated as part of the FIPS provider installation +and contains module integrity and self-test information. The exact command and +arguments are installation-specific; see [OpenSSL FIPS configuration][] and the +[OpenSSL FIPS module guide][]. The installation uses `openssl fipsinstall`. + +The example activates the provider and enables the `fips=yes` property query +when Node.js starts. To activate the provider at startup but enable the property +query later with `crypto.setFips(true)`, omit `alg_section = algorithm_sect` and +the `[algorithm_sect]` block. The provider must still be loaded; when using this +startup configuration, keep its activation enabled. `crypto.setFips(true)` +should be called before application code uses other OpenSSL-backed APIs. It is +not equivalent to enabling the property query from process startup because +Node.js initializes some OpenSSL state before application code runs. Use the +example as written, [`--enable-fips`][], or [`--force-fips`][] when the property +query must be active from process startup. + +`config_diagnostics` causes configuration errors to prevent startup instead of +being ignored. The `base` provider supplies non-cryptographic supporting +algorithms, such as encoders and decoders, that are commonly needed alongside +the FIPS provider. `default_properties = fips=yes` restricts OpenSSL's default +algorithm selection to implementations that match `fips=yes`. + +Set `OPENSSL_CONF` to the OpenSSL configuration file. For a dynamically loaded +provider, `OPENSSL_MODULES` can set the directory containing the provider module. +For example: ```bash export OPENSSL_CONF=//nodejs.cnf export OPENSSL_MODULES=//ossl-modules ``` -FIPS mode can then be enabled in Node.js either by: - -* Starting Node.js with `--enable-fips` or `--force-fips` command line flags. -* Programmatically calling `crypto.setFips(true)`. - -Optionally FIPS mode can be enabled in Node.js via the OpenSSL configuration -file. e.g. - -```text -nodejs_conf = nodejs_init - -.include //fipsmodule.cnf - -[nodejs_init] -providers = provider_sect -alg_section = algorithm_sect - -[provider_sect] -default = default_sect -# The fips section name should match the section name inside the -# included fipsmodule.cnf. -fips = fips_sect - -[default_sect] -activate = 1 - -[algorithm_sect] -default_properties = fips=yes -``` +The [`--openssl-config`][] command-line option selects the configuration file and +takes precedence over `OPENSSL_CONF`. If neither is set, OpenSSL's default +configuration file is used. + +By default, Node.js reads the `nodejs_conf` section instead of OpenSSL's usual +`openssl_conf` section. Use [`--openssl-shared-config`][] to read `openssl_conf`, +or build Node.js with `./configure --openssl-conf-name=` to change the +default section name. + +On OpenSSL 3, the configuration above enables the `fips=yes` property query at +startup. The following controls are also available: + +* [`--enable-fips`][] and [`--force-fips`][] enable the property query and + additionally require the configured provider named `fips` to initialize and + pass its self-test. Node.js exits if that check fails. `--force-fips` also + prevents FIPS mode from being disabled from script code. +* [`crypto.setFips()`][] changes the FIPS/property-query state. On OpenSSL 3, it + does not install, load, initialize, or validate a provider. Implementations + fetched before the call are not changed. +* [`crypto.getFips()`][] reports the FIPS/property-query state. On OpenSSL 3, a + return value of `1` does not prove that a FIPS provider is loaded or validated. + +With OpenSSL 1.1.1, these controls use the library's FIPS mode support and +require a FIPS-capable OpenSSL build. + +Only algorithms available under the active FIPS settings can be used. With +OpenSSL 3, if no loaded provider supplies a requested cryptographic +implementation matching `fips=yes`, fetching it fails, typically with +`ERR_OSSL_EVP_UNSUPPORTED`. The same error can occur for algorithms that +Node.js supports when FIPS mode is disabled but that are unavailable under the +active FIPS settings. + +OpenSSL documents that the same FIPS provider cannot be used by multiple copies +of `libcrypto` in one process. This can affect native addons that load another +copy of `libcrypto`; OpenSSL's documented workaround is to use a separate copy +of the provider for each `libcrypto` instance. See [OpenSSL FIPS provider +limitations][]. ## Crypto constants @@ -6887,16 +7013,19 @@ See the [list of SSL OP Flags][] for details. [Caveats]: #support-for-weak-or-compromised-algorithms [Crypto constants]: #crypto-constants [DEP0182]: deprecations.md#dep0182-short-gcm-authentication-tags-without-explicit-authtaglength -[FIPS module configuration file]: https://www.openssl.org/docs/man3.0/man5/fips_config.html -[FIPS provider from OpenSSL 3]: https://www.openssl.org/docs/man3.0/man7/crypto.html#FIPS-provider +[FIPS mode]: #fips-mode +[FIPS module configuration file]: https://docs.openssl.org/3.0/man5/fips_config/ [HTML 5.2]: https://www.w3.org/TR/html52/changes.html#features-removed [JWK]: https://tools.ietf.org/html/rfc7517 [Key usages]: webcrypto.md#cryptokeyusages [NIST SP 800-131A]: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf [NIST SP 800-132]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf [NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf -[OpenSSL's FIPS README file]: https://github.com/openssl/openssl/blob/openssl-3.0/README-FIPS.md +[OpenSSL FIPS configuration]: https://docs.openssl.org/3.0/man5/fips_config/ +[OpenSSL FIPS module guide]: https://docs.openssl.org/master/man7/fips_module/ +[OpenSSL FIPS provider limitations]: https://docs.openssl.org/3.6/man7/OSSL_PROVIDER-FIPS/ [OpenSSL's SPKAC implementation]: https://www.openssl.org/docs/man3.0/man1/openssl-spkac.html +[Permission Model]: permissions.md#permission-model [RFC 1421]: https://www.rfc-editor.org/rfc/rfc1421.txt [RFC 2409]: https://www.rfc-editor.org/rfc/rfc2409.txt [RFC 2818]: https://www.rfc-editor.org/rfc/rfc2818.txt @@ -6910,6 +7039,11 @@ See the [list of SSL OP Flags][] for details. [RFC 8032]: https://www.rfc-editor.org/rfc/rfc8032.txt [RFC 9562]: https://www.rfc-editor.org/rfc/rfc9562.txt [Web Crypto API documentation]: webcrypto.md +[`--allow-openssl-store`]: cli.md#--allow-openssl-store +[`--enable-fips`]: cli.md#--enable-fips +[`--force-fips`]: cli.md#--force-fips +[`--openssl-config`]: cli.md#--openssl-configfile +[`--openssl-shared-config`]: cli.md#--openssl-shared-config [`BN_is_prime_ex`]: https://www.openssl.org/docs/man1.1.1/man3/BN_is_prime_ex.html [`Buffer`]: buffer.md [`DH_generate_key()`]: https://www.openssl.org/docs/man3.0/man3/DH_generate_key.html @@ -6936,6 +7070,7 @@ See the [list of SSL OP Flags][] for details. [`crypto.generateKeyPair()`]: #cryptogeneratekeypairtype-options-callback [`crypto.getCurves()`]: #cryptogetcurves [`crypto.getDiffieHellman()`]: #cryptogetdiffiehellmangroupname +[`crypto.getFips()`]: #cryptogetfips [`crypto.getHashes()`]: #cryptogethashes [`crypto.hash()`]: #cryptohashalgorithm-data-options [`crypto.privateDecrypt()`]: #cryptoprivatedecryptprivatekey-buffer @@ -6944,6 +7079,7 @@ See the [list of SSL OP Flags][] for details. [`crypto.publicEncrypt()`]: #cryptopublicencryptkey-buffer [`crypto.randomBytes()`]: #cryptorandombytessize-callback [`crypto.randomFill()`]: #cryptorandomfillbuffer-offset-size-callback +[`crypto.setFips()`]: #cryptosetfipsbool [`crypto.sign()`]: #cryptosignalgorithm-data-key-callback [`crypto.verify()`]: #cryptoverifyalgorithm-data-key-signature-callback [`crypto.webcrypto.getRandomValues()`]: webcrypto.md#cryptogetrandomvaluestypedarray diff --git a/doc/api/fs.md b/doc/api/fs.md index 467fd6a8400e..4003651052d0 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -323,6 +323,9 @@ fd.createReadStream({ start: 90, end: 99 }); +* Returns: {Promise} + Calls `filehandle.close()` and returns a promise that fulfills when the filehandle is closed. @@ -1321,6 +1327,10 @@ changes: Asynchronously copies `src` to `dest`. By default, `dest` is overwritten if it already exists. +Symbolic links are followed. If `src` is a symbolic link, the target file is +copied. If `dest` is a symbolic link, the target file is overwritten unless +`mode` contains `fs.constants.COPYFILE_EXCL`. + No guarantees are made about the atomicity of the copy operation. If an error occurs after the destination file has been opened for writing, an attempt will be made to remove the destination. @@ -1461,6 +1471,7 @@ const { glob } = require('node:fs/promises'); ### `fsPromises.lchmod(path, mode)` @@ -2831,6 +2842,10 @@ callback function. Node.js makes no guarantees about the atomicity of the copy operation. If an error occurs after the destination file has been opened for writing, Node.js will attempt to remove the destination. +Symbolic links are followed. If `src` is a symbolic link, the target file is +copied. If `dest` is a symbolic link, the target file is overwritten unless +`mode` contains `fs.constants.COPYFILE_EXCL`. + `mode` is an optional integer that specifies the behavior of the copy operation. It is possible to create a mask consisting of the bitwise OR of two or more values (e.g. @@ -2926,6 +2941,9 @@ behavior is similar to `cp dir1/ dir2/`. > Stability: 0 - Deprecated @@ -7284,6 +7331,8 @@ changes: description: No longer experimental. --> +* Returns: {Promise} + Calls `dir.close()` if the directory handle is open, and returns a promise that fulfills when disposal is complete. @@ -7322,6 +7371,13 @@ Additionally, when [`fs.readdir()`][] or [`fs.readdirSync()`][] is called with the `withFileTypes` option set to `true`, the resulting array is filled with {fs.Dirent} objects, rather than strings or {Buffer}s. +When a directory is read, such as with [`fs.readdir()`][] or +[`fs.opendir()`][], the file type of each entry is the type reported by the +operating system and may depend on the file system; for example, some file +systems may report a type that differs from what [`fs.lstat()`][] returns. +Node.js calls [`fs.lstat()`][] on such an entry only when the reported type +is unknown. Use [`fs.lstat()`][] when an accurate file type is required. + #### `dirent.isBlockDevice()` +#### Header name constants + +The `HTTP2_HEADER_*` constants provide names for HTTP/2 pseudo-headers and +known HTTP header names. Using these string constants is optional. For example, +`http2.constants.HTTP2_HEADER_CONTENT_TYPE` is equal to `'content-type'`. +For APIs that accept regular header names, +`http2.constants.HTTP2_HEADER_CONTENT_TYPE`, `'content-type'`, and +`'Content-Type'` have the same effect; Node.js serializes the name in +lower-case. + +Regular header constants can be used with the compatibility API wherever the +corresponding literal header name is accepted. In compatibility API request +handlers, prefer `request.method`, `request.authority`, `request.scheme`, and +`request.url` for the corresponding pseudo-headers. Other incoming +pseudo-headers remain available through `request.headers`. Set response status +through `response.statusCode` or the `statusCode` argument to +`response.writeHead()`. Passing `HTTP2_HEADER_STATUS` (`':status'`) to +`response.setHeader()` or in `response.writeHead()`'s headers object throws +`ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED`. `HTTP2_HEADER_PROTOCOL` is a request +pseudo-header and cannot be sent in a response. + +Incoming header object keys are lower-case, so use a constant or a lower-case +literal when accessing them as object properties. Using a constant does not +change header validation, and the availability of a constant does not imply +that the header is valid in every HTTP/2 context. See [HTTP/2 Headers Object][] +and [Invalid character handling in header names and values][] for details about +header casing and validation. + +##### Pseudo-header constants + +`HTTP2_HEADER_METHOD`, `HTTP2_HEADER_AUTHORITY`, `HTTP2_HEADER_SCHEME`, and +`HTTP2_HEADER_PATH` identify request pseudo-headers. `HTTP2_HEADER_STATUS` +identifies the response pseudo-header. `HTTP2_HEADER_PROTOCOL` identifies the +extended `CONNECT` request pseudo-header. Pseudo-headers are not permitted in +trailers. + +| Constant | Value | +| ---------------------------------------- | -------------- | +| `http2.constants.HTTP2_HEADER_STATUS` | `':status'` | +| `http2.constants.HTTP2_HEADER_METHOD` | `':method'` | +| `http2.constants.HTTP2_HEADER_AUTHORITY` | `':authority'` | +| `http2.constants.HTTP2_HEADER_SCHEME` | `':scheme'` | +| `http2.constants.HTTP2_HEADER_PATH` | `':path'` | +| `http2.constants.HTTP2_HEADER_PROTOCOL` | `':protocol'` | + +##### Regular header constants + +The `HTTP2_HEADER_CONNECTION`, `HTTP2_HEADER_UPGRADE`, +`HTTP2_HEADER_HTTP2_SETTINGS`, `HTTP2_HEADER_KEEP_ALIVE`, +`HTTP2_HEADER_PROXY_CONNECTION`, and `HTTP2_HEADER_TRANSFER_ENCODING` +constants identify connection-specific headers that HTTP/2 does not permit. +`HTTP2_HEADER_TE` is permitted only when its value is `'trailers'`. + +| Constant | Value | +| --------------------------------------------------------------- | ------------------------------------ | +| `http2.constants.HTTP2_HEADER_ACCEPT_ENCODING` | `'accept-encoding'` | +| `http2.constants.HTTP2_HEADER_ACCEPT_LANGUAGE` | `'accept-language'` | +| `http2.constants.HTTP2_HEADER_ACCEPT_RANGES` | `'accept-ranges'` | +| `http2.constants.HTTP2_HEADER_ACCEPT` | `'accept'` | +| `http2.constants.HTTP2_HEADER_ACCESS_CONTROL_ALLOW_CREDENTIALS` | `'access-control-allow-credentials'` | +| `http2.constants.HTTP2_HEADER_ACCESS_CONTROL_ALLOW_HEADERS` | `'access-control-allow-headers'` | +| `http2.constants.HTTP2_HEADER_ACCESS_CONTROL_ALLOW_METHODS` | `'access-control-allow-methods'` | +| `http2.constants.HTTP2_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN` | `'access-control-allow-origin'` | +| `http2.constants.HTTP2_HEADER_ACCESS_CONTROL_EXPOSE_HEADERS` | `'access-control-expose-headers'` | +| `http2.constants.HTTP2_HEADER_ACCESS_CONTROL_REQUEST_HEADERS` | `'access-control-request-headers'` | +| `http2.constants.HTTP2_HEADER_ACCESS_CONTROL_REQUEST_METHOD` | `'access-control-request-method'` | +| `http2.constants.HTTP2_HEADER_AGE` | `'age'` | +| `http2.constants.HTTP2_HEADER_AUTHORIZATION` | `'authorization'` | +| `http2.constants.HTTP2_HEADER_CACHE_CONTROL` | `'cache-control'` | +| `http2.constants.HTTP2_HEADER_CONNECTION` | `'connection'` | +| `http2.constants.HTTP2_HEADER_CONTENT_DISPOSITION` | `'content-disposition'` | +| `http2.constants.HTTP2_HEADER_CONTENT_ENCODING` | `'content-encoding'` | +| `http2.constants.HTTP2_HEADER_CONTENT_LENGTH` | `'content-length'` | +| `http2.constants.HTTP2_HEADER_CONTENT_TYPE` | `'content-type'` | +| `http2.constants.HTTP2_HEADER_COOKIE` | `'cookie'` | +| `http2.constants.HTTP2_HEADER_DATE` | `'date'` | +| `http2.constants.HTTP2_HEADER_ETAG` | `'etag'` | +| `http2.constants.HTTP2_HEADER_FORWARDED` | `'forwarded'` | +| `http2.constants.HTTP2_HEADER_HOST` | `'host'` | +| `http2.constants.HTTP2_HEADER_IF_MODIFIED_SINCE` | `'if-modified-since'` | +| `http2.constants.HTTP2_HEADER_IF_NONE_MATCH` | `'if-none-match'` | +| `http2.constants.HTTP2_HEADER_IF_RANGE` | `'if-range'` | +| `http2.constants.HTTP2_HEADER_LAST_MODIFIED` | `'last-modified'` | +| `http2.constants.HTTP2_HEADER_LINK` | `'link'` | +| `http2.constants.HTTP2_HEADER_LOCATION` | `'location'` | +| `http2.constants.HTTP2_HEADER_RANGE` | `'range'` | +| `http2.constants.HTTP2_HEADER_REFERER` | `'referer'` | +| `http2.constants.HTTP2_HEADER_SERVER` | `'server'` | +| `http2.constants.HTTP2_HEADER_SET_COOKIE` | `'set-cookie'` | +| `http2.constants.HTTP2_HEADER_STRICT_TRANSPORT_SECURITY` | `'strict-transport-security'` | +| `http2.constants.HTTP2_HEADER_TRANSFER_ENCODING` | `'transfer-encoding'` | +| `http2.constants.HTTP2_HEADER_TE` | `'te'` | +| `http2.constants.HTTP2_HEADER_UPGRADE_INSECURE_REQUESTS` | `'upgrade-insecure-requests'` | +| `http2.constants.HTTP2_HEADER_UPGRADE` | `'upgrade'` | +| `http2.constants.HTTP2_HEADER_USER_AGENT` | `'user-agent'` | +| `http2.constants.HTTP2_HEADER_VARY` | `'vary'` | +| `http2.constants.HTTP2_HEADER_X_CONTENT_TYPE_OPTIONS` | `'x-content-type-options'` | +| `http2.constants.HTTP2_HEADER_X_FRAME_OPTIONS` | `'x-frame-options'` | +| `http2.constants.HTTP2_HEADER_KEEP_ALIVE` | `'keep-alive'` | +| `http2.constants.HTTP2_HEADER_PROXY_CONNECTION` | `'proxy-connection'` | +| `http2.constants.HTTP2_HEADER_X_XSS_PROTECTION` | `'x-xss-protection'` | +| `http2.constants.HTTP2_HEADER_ALT_SVC` | `'alt-svc'` | +| `http2.constants.HTTP2_HEADER_CONTENT_SECURITY_POLICY` | `'content-security-policy'` | +| `http2.constants.HTTP2_HEADER_EARLY_DATA` | `'early-data'` | +| `http2.constants.HTTP2_HEADER_EXPECT_CT` | `'expect-ct'` | +| `http2.constants.HTTP2_HEADER_ORIGIN` | `'origin'` | +| `http2.constants.HTTP2_HEADER_PURPOSE` | `'purpose'` | +| `http2.constants.HTTP2_HEADER_TIMING_ALLOW_ORIGIN` | `'timing-allow-origin'` | +| `http2.constants.HTTP2_HEADER_X_FORWARDED_FOR` | `'x-forwarded-for'` | +| `http2.constants.HTTP2_HEADER_PRIORITY` | `'priority'` | +| `http2.constants.HTTP2_HEADER_ACCEPT_CHARSET` | `'accept-charset'` | +| `http2.constants.HTTP2_HEADER_ACCESS_CONTROL_MAX_AGE` | `'access-control-max-age'` | +| `http2.constants.HTTP2_HEADER_ALLOW` | `'allow'` | +| `http2.constants.HTTP2_HEADER_CONTENT_LANGUAGE` | `'content-language'` | +| `http2.constants.HTTP2_HEADER_CONTENT_LOCATION` | `'content-location'` | +| `http2.constants.HTTP2_HEADER_CONTENT_MD5` | `'content-md5'` | +| `http2.constants.HTTP2_HEADER_CONTENT_RANGE` | `'content-range'` | +| `http2.constants.HTTP2_HEADER_DNT` | `'dnt'` | +| `http2.constants.HTTP2_HEADER_EXPECT` | `'expect'` | +| `http2.constants.HTTP2_HEADER_EXPIRES` | `'expires'` | +| `http2.constants.HTTP2_HEADER_FROM` | `'from'` | +| `http2.constants.HTTP2_HEADER_IF_MATCH` | `'if-match'` | +| `http2.constants.HTTP2_HEADER_IF_UNMODIFIED_SINCE` | `'if-unmodified-since'` | +| `http2.constants.HTTP2_HEADER_MAX_FORWARDS` | `'max-forwards'` | +| `http2.constants.HTTP2_HEADER_PREFER` | `'prefer'` | +| `http2.constants.HTTP2_HEADER_PROXY_AUTHENTICATE` | `'proxy-authenticate'` | +| `http2.constants.HTTP2_HEADER_PROXY_AUTHORIZATION` | `'proxy-authorization'` | +| `http2.constants.HTTP2_HEADER_REFRESH` | `'refresh'` | +| `http2.constants.HTTP2_HEADER_RETRY_AFTER` | `'retry-after'` | +| `http2.constants.HTTP2_HEADER_TRAILER` | `'trailer'` | +| `http2.constants.HTTP2_HEADER_TK` | `'tk'` | +| `http2.constants.HTTP2_HEADER_VIA` | `'via'` | +| `http2.constants.HTTP2_HEADER_WARNING` | `'warning'` | +| `http2.constants.HTTP2_HEADER_WWW_AUTHENTICATE` | `'www-authenticate'` | +| `http2.constants.HTTP2_HEADER_HTTP2_SETTINGS` | `'http2-settings'` | + #### Error codes for `RST_STREAM` and `GOAWAY` | Value | Name | Constant | @@ -3920,9 +4056,10 @@ API: ```mjs import { createServer } from 'node:http2'; const server = createServer((req, res) => { - res.setHeader('Content-Type', 'text/html'); - res.setHeader('X-Foo', 'bar'); - res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' }); + res.writeHead(200, { + 'Content-Type': 'text/plain; charset=utf-8', + 'X-Foo': 'bar', + }); res.end('ok'); }); ``` @@ -3930,9 +4067,10 @@ const server = createServer((req, res) => { ```cjs const http2 = require('node:http2'); const server = http2.createServer((req, res) => { - res.setHeader('Content-Type', 'text/html'); - res.setHeader('X-Foo', 'bar'); - res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' }); + res.writeHead(200, { + 'Content-Type': 'text/plain; charset=utf-8', + 'X-Foo': 'bar', + }); res.end('ok'); }); ``` @@ -5023,6 +5161,7 @@ you need to implement any fall-back behavior yourself. [HTTP/2 Settings Object]: #settings-object [HTTP/2 Unencrypted]: https://http2.github.io/faq/#does-http2-require-encryption [HTTPS]: https.md +[Invalid character handling in header names and values]: #invalid-character-handling-in-header-names-and-values [Performance Observer]: perf_hooks.md [RFC 7838]: https://tools.ietf.org/html/rfc7838 [RFC 8336]: https://tools.ietf.org/html/rfc8336 diff --git a/doc/api/n-api.md b/doc/api/n-api.md index f51a5ad9427e..648d17a0f2d9 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -194,9 +194,8 @@ the native addon. #### node-gyp -[node-gyp][] is a build system based on the [gyp-next][] fork of -Google's [GYP][] tool and comes bundled with npm. GYP, and therefore node-gyp, -requires that Python be installed. +[node-gyp][] is a build system based on the [gyp-next][] tool and comes bundled with npm. +node-gyp requires that Python be installed. Historically, node-gyp has been the tool of choice for building native addons. It has widespread adoption and documentation. However, some @@ -6944,7 +6943,7 @@ node_api_get_module_file_name(node_api_basic_env env, const char** result); `result` may be an empty string if the add-on loading process fails to establish the add-on's file name during loading. -[ABI Stability]: https://nodejs.org/en/docs/guides/abi-stability/ +[ABI Stability]: https://nodejs.org/learn/modules/abi-stability [AppVeyor]: https://www.appveyor.com [C++ Addons]: addons.md [CMake]: https://cmake.org @@ -6952,7 +6951,6 @@ the add-on's file name during loading. [ECMAScript Language Specification]: https://tc39.es/ecma262/ [Error handling]: #error-handling [GCC]: https://gcc.gnu.org -[GYP]: https://gyp.gsrc.io [GitHub releases]: https://help.github.com/en/github/administering-a-repository/about-releases [LLVM]: https://llvm.org [Native Abstractions for Node.js]: https://github.com/nodejs/nan diff --git a/doc/api/net.md b/doc/api/net.md index cffab3df9671..d148c2844b44 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -96,6 +96,47 @@ added: Adds a rule to block the given IP address. +### `blockList.addAddresses(addresses[, type])` + + + +* `addresses` {string\[]|net.SocketAddress\[]} An array of IPv4 or IPv6 + addresses. +* `type` {string} Either `'ipv4'` or `'ipv6'`. **Default:** `'ipv4'`. + +Adds multiple address rules to the block list in a single operation. +This is more efficient than calling `blockList.addAddress()` repeatedly +when adding a large number of individual addresses, as the addresses +are inserted under a single internal lock acquisition. + +### `blockList.addCIDR(cidr)` + + + +* `cidr` {string} An IPv4 or IPv6 subnet in CIDR notation (e.g. + `'10.0.0.0/8'` or `'2001:db8::/32'`). + +Adds a subnet rule using CIDR notation. The address family is automatically +detected from the address (IPv6 if the address contains `':'`, IPv4 +otherwise). This is equivalent to calling `blockList.addSubnet()` with +the parsed network address, prefix length, and family. + +### `blockList.addCIDRs(cidrs)` + + + +* `cidrs` {string\[]} An array of IPv4 or IPv6 subnets in CIDR notation. + +Adds multiple subnet rules using CIDR notation in a single call. The address +family for each entry is automatically detected. This is equivalent to +calling `blockList.addCIDR()` for each element of the array. + ### `blockList.addRange(start, end[, type])` -* Type: {string\[]} - -The list of rules added to the blocklist. - -### `BlockList.isBlockList(value)` - - - -* `value` {any} Any JS value -* Returns `true` if the `value` is a `net.BlockList`. +Clears all rules from the `BlockList`. ### `blockList.fromJSON(value)` @@ -203,6 +229,130 @@ blockList.fromJSON(JSON.stringify(data)); * `value` Blocklist.rules +### `BlockList.isBlockList(value)` + + + +* `value` {any} Any JS value +* Returns `true` if the `value` is a `net.BlockList`. + +### `BlockList.PRIVATE_RANGES` + + + +* Type: {string\[]} + +A frozen array of CIDR strings representing private, loopback, and link-local +IP address ranges. This can be passed to `blockList.addCIDRs()` to quickly +populate a blocklist with all non-routable address ranges. + +The included ranges are: + +* `10.0.0.0/8` — RFC 1918 private IPv4 +* `172.16.0.0/12` — RFC 1918 private IPv4 +* `192.168.0.0/16` — RFC 1918 private IPv4 +* `127.0.0.0/8` — IPv4 loopback +* `::1/128` — IPv6 loopback +* `169.254.0.0/16` — IPv4 link-local +* `fe80::/10` — IPv6 link-local +* `fc00::/7` — IPv6 unique local (ULA) + +```js +const blockList = new net.BlockList(); +blockList.addCIDRs(net.BlockList.PRIVATE_RANGES); + +console.log(blockList.check('10.0.0.1')); // Prints: true +console.log(blockList.check('127.0.0.1')); // Prints: true +console.log(blockList.check('8.8.8.8')); // Prints: false +``` + +### `blockList.removeAddress(address[, type])` + + + +* `address` {string|net.SocketAddress} An IPv4 or IPv6 address. +* `type` {string} Either `'ipv4'` or `'ipv6'`. **Default:** `'ipv4'`. + +Removes a rule that was previously added with `blockList.addAddress()`. The +address must match exactly the value used when the rule was added. If the +specified address does not exist, this is a no-op. + +### `blockList.removeCIDR(cidr)` + + + +* `cidr` {string} An IPv4 or IPv6 subnet in CIDR notation (e.g. + `'10.0.0.0/8'` or `'2001:db8::/32'`). + +Removes a subnet rule using CIDR notation. The address family is automatically +detected from the address. This is equivalent to calling +`blockList.removeSubnet()` with the parsed network address, prefix length, +and family. If the specified subnet does not exist, this is a no-op. + +### `blockList.removeRange(start, end[, type])` + + + +* `start` {string|net.SocketAddress} The starting IPv4 or IPv6 address in the + range. +* `end` {string|net.SocketAddress} The ending IPv4 or IPv6 address in the range. +* `type` {string} Either `'ipv4'` or `'ipv6'`. **Default:** `'ipv4'`. + +Removes a rule that was previously added with `blockList.addRange()`. The `start` +and `end` addresses must match exactly the values used when the rule was added. +If the specified range does not exist, this is a no-op. + +### `blockList.removeSubnet(net, prefix[, type])` + + + +* `net` {string|net.SocketAddress} The network IPv4 or IPv6 address. +* `prefix` {number} The number of CIDR prefix bits. For IPv4, this + must be a value between `0` and `32`. For IPv6, this must be between + `0` and `128`. +* `type` {string} Either `'ipv4'` or `'ipv6'`. **Default:** `'ipv4'`. + +Removes a rule that was previously added with `blockList.addSubnet()`. The +network address and prefix must match exactly the values used when the rule was +added. If the specified subnet does not exist, this is a no-op. + +### `blockList.rules` + + + +* Type: {string\[]} + +The list of rules added to the blocklist. + +### `blockList.size` + + + +* Type: {number} + +The number of rules in the blocklist. This is equivalent to +`blockList.rules.length` but does not allocate the rules array. + ### `blockList.toJSON()` > Stability: 1.2 - Release candidate @@ -1254,15 +1404,15 @@ added: v0.1.90 * `error` {Object} * Returns: {net.Socket} -Ensures that no more I/O activity happens on this socket. +Ensures that no more I/O activity happens on the current connection. Destroys the stream and closes the connection. See [`writable.destroy()`][] for further details. ### `socket.destroyed` -* Type: {boolean} Indicates if the connection is destroyed or not. Once a - connection is destroyed no further data can be transferred using it. +* Type: {boolean} Indicates if the connection is destroyed or not. No further + data can be transferred using a destroyed connection. See [`writable.destroyed`][] for further details. @@ -2225,12 +2375,13 @@ added: v0.3.0 * `input` {string} * Returns: {integer} -Returns `6` if `input` is an IPv6 address. Returns `4` if `input` is an IPv4 -address in [dot-decimal notation][] with no leading zeroes. Otherwise, returns -`0`. +Returns `6` if `input` is an IPv6 address, including an IPv4-mapped IPv6 address. +Returns `4` if `input` is an IPv4 address in [dot-decimal notation][] with no +leading zeroes. Otherwise, returns `0`. ```js net.isIP('::1'); // returns 6 +net.isIP('::ffff:127.0.0.1'); // returns 6 net.isIP('127.0.0.1'); // returns 4 net.isIP('127.000.000.001'); // returns 0 net.isIP('127.0.0.1/24'); // returns 0 @@ -2265,10 +2416,12 @@ added: v0.3.0 * `input` {string} * Returns: {boolean} -Returns `true` if `input` is an IPv6 address. Otherwise, returns `false`. +Returns `true` if `input` is an IPv6 address, including an IPv4-mapped IPv6 address. +Otherwise, returns `false`. ```js net.isIPv6('::1'); // returns true +net.isIPv6('::ffff:127.0.0.1'); // returns true net.isIPv6('fhqwhgads'); // returns false ``` diff --git a/doc/api/os.md b/doc/api/os.md index 6b3bb1ddfa55..a2592a2f20cc 100644 --- a/doc/api/os.md +++ b/doc/api/os.md @@ -298,42 +298,42 @@ The properties available on the assigned network address object include: ```json { - "lo:": [ + "lo": [ { - "address:": "127.0.0.1", - "netmask:": "255.0.0.0", - "family:": "IPv4", - "mac:": "00:00:00:00:00:00", - "internal:": true, - "cidr:": "127.0.0.1/8" + "address": "127.0.0.1", + "netmask": "255.0.0.0", + "family": "IPv4", + "mac": "00:00:00:00:00:00", + "internal": true, + "cidr": "127.0.0.1/8" }, { - "address:": "::1", - "netmask:": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", - "family:": "IPv6", - "mac:": "00:00:00:00:00:00", - "scopeid:": 0, - "internal:": true, - "cidr:": "::1/128" + "address": "::1", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "family": "IPv6", + "mac": "00:00:00:00:00:00", + "scopeid": 0, + "internal": true, + "cidr": "::1/128" } ], - "eth0:": [ + "eth0": [ { - "address:": "192.168.1.108", - "netmask:": "255.255.255.0", - "family:": "IPv4", - "mac:": "01:02:03:0a:0b:0c", - "internal:": false, - "cidr:": "192.168.1.108/24" + "address": "192.168.1.108", + "netmask": "255.255.255.0", + "family": "IPv4", + "mac": "01:02:03:0a:0b:0c", + "internal": false, + "cidr": "192.168.1.108/24" }, { - "address:": "fe80::a00:27ff:fe4e:66a1", - "netmask:": "ffff:ffff:ffff:ffff::", - "family:": "IPv6", - "mac:": "01:02:03:0a:0b:0c", - "scopeid:": 1, - "internal:": false, - "cidr:": "fe80::a00:27ff:fe4e:66a1/64" + "address": "fe80::a00:27ff:fe4e:66a1", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "mac": "01:02:03:0a:0b:0c", + "scopeid": 1, + "internal": false, + "cidr": "fe80::a00:27ff:fe4e:66a1/64" } ] } diff --git a/doc/api/perf_hooks.md b/doc/api/perf_hooks.md index b71505441087..1a91a5724362 100644 --- a/doc/api/perf_hooks.md +++ b/doc/api/perf_hooks.md @@ -1621,6 +1621,16 @@ added: **Default:** `Number.MAX_SAFE_INTEGER`. * `figures` {number} The number of accuracy digits. Must be a number between `1` and `5`. **Default:** `3`. + * `halfLife` {number} The EWMA half-life in number of samples. When set to + a value greater than 0, the histogram tracks an exponentially weighted + moving average and standard deviation, accessible via + `histogram.ewmaMean` and `histogram.ewmaStddev`. After `halfLife` + recordings, a value's influence has decayed to 50%. **Default:** `0` + (disabled). + * `threshold` {number} An SLO threshold value. When set together with + `halfLife`, the histogram tracks a smoothed error rate for values + exceeding this threshold, accessible via `histogram.ewmaErrorRate` and + `histogram.burnRate()`. **Default:** `0` (disabled). * Returns: {RecordableHistogram} Returns a {RecordableHistogram}. @@ -1858,6 +1868,75 @@ added: The number of samples recorded by the histogram. +### `histogram.ccdf(value)` + + + +* `value` {number} The value to query. +* Returns: {number} A probability between 0.0 and 1.0. + +Returns the complementary cumulative distribution function (CCDF) value +for the given value, representing the probability that a recorded value +will exceed `value`. Equivalent to `1 - histogram.cdf(value)`. + +### `histogram.cdf(value)` + + + +* `value` {number} The value to query. +* Returns: {number} A probability between 0.0 and 1.0. + +Returns the cumulative distribution function (CDF) value for the given +value, representing the probability that a recorded value will be less +than or equal to `value`. This is the inverse operation of +`histogram.percentile()`. + +### `histogram.cliffsD(other)` + + + +* `other` {Histogram} The histogram to compare against. +* Returns: {number} A value between -1.0 and 1.0. + +Computes [Cliff's delta][], a non-parametric effect size measure. Returns +the probability that a random value from this histogram exceeds a random +value from `other`, minus the reverse probability. A value of 1 means every +value in this histogram exceeds every value in `other`; -1 means the +opposite; 0 means no tendency in either direction. + +### `histogram.cohensD(other)` + + + +* `other` {Histogram} The histogram to compare against. +* Returns: {number} The effect size. + +Computes [Cohen's d][] effect size, the standardized difference between the +means of this histogram and `other`, using the pooled standard deviation. +Positive values indicate this histogram has a higher mean. By convention, +|d| < 0.2 is a small effect, 0.5 is medium, and 0.8 or greater is large. +Both histograms must have at least 2 recorded values; otherwise returns 0. + +### `histogram.countAt(value)` + + + +* `value` {number} The value to query. +* Returns: {number} + +Returns the number of recorded values that fall within the equivalent +value range of the given value. + ### `histogram.exceeds` + +* Type: {number} + +The exponentially weighted moving average of recorded values. Only active +when the histogram was created with a `halfLife` option greater than 0. +Returns `0` when EWMA is disabled or no values have been recorded. + +### `histogram.ewmaStddev` + + + +* Type: {number} + +The exponentially weighted moving standard deviation. Only active when the +histogram was created with a `halfLife` option greater than 0. Returns `0` +when EWMA is disabled or no values have been recorded. + +### `histogram.ewmaErrorRate` + + + +* Type: {number} + +The EWMA-smoothed probability of a recorded value exceeding the configured +`threshold`. Only active when the histogram was created with both `halfLife` +and `threshold` options. Returns `0` when not enabled or no values have been +recorded. + +### `histogram.burnRate(sloTarget)` + + + +* `sloTarget` {number} The SLO target as a fraction between 0 and 1 + (exclusive). For example, `0.999` for a 99.9% SLO. +* Returns: {number} + +Returns the SLO burn rate: `ewmaErrorRate / (1 - sloTarget)`. A burn rate +of 1 means the error budget will be exactly exhausted over the SLO window. +A burn rate greater than 1 means it is being consumed faster than allowed. +Requires the histogram to have been created with both `halfLife` and +`threshold` options. + +```js +const { createHistogram } = require('node:perf_hooks'); + +// Track latency with a 200ms SLO threshold, half-life of 100 samples +const h = createHistogram({ halfLife: 100, threshold: 200_000_000 }); + +// ... record latency values ... + +// Check burn rate against a 99.9% SLO +const rate = h.burnRate(0.999); +if (rate > 1) { + console.log(`SLO burn rate: ${rate.toFixed(2)}x — error budget depleting`); +} +``` + +### `histogram.ksTest(other)` + + + +* `other` {Histogram} The histogram to compare against. +* Returns: {number} The KS D-statistic, between 0.0 and 1.0. + +Computes the Kolmogorov-Smirnov test statistic comparing this histogram's +distribution to `other`. A value of 0 indicates identical distributions; +values close to 1 indicate completely disjoint distributions. Useful for +detecting performance regressions by comparing before/after histograms. + +### `histogram.kurtosis` + + + +* Type: {number} + +The excess kurtosis of the recorded values. Measures the heaviness of the +distribution's tails relative to a normal distribution. Positive values +indicate heavier tails (more extreme outliers); negative values indicate +lighter tails. + +### `histogram.linearBuckets(stepSize)` + + + +* `stepSize` {number} The width of each linear bucket. +* Returns: {Map} A map of bucket boundary values to counts. + +Returns the histogram data rebucketed into linearly-spaced intervals +of `stepSize`. Useful for visualization and export. + +### `histogram.logBuckets(firstBucket, base)` + + + +* `firstBucket` {number} The value of the first bucket boundary. +* `base` {number} The logarithmic base for bucket width growth. Must be > 1. +* Returns: {Map} A map of bucket boundary values to counts. + +Returns the histogram data rebucketed into logarithmically-spaced +intervals, where each bucket's width is multiplied by `base`. +Useful for visualization and export. + +### `histogram.mannWhitneyTest(other)` + + + +* `other` {Histogram} The histogram to compare against. +* Returns: {Object} + * `uStatistic` {number} The Mann-Whitney U statistic. + * `zScore` {number} The z-score (normal approximation). + * `pValue` {number} Two-tailed p-value. + +Performs a [Mann-Whitney U test][] comparing whether this histogram tends to +produce larger or smaller values than `other`. Unlike `welchTest()`, this is a +non-parametric test that makes no assumptions about the shape of the +distributions. Uses the normal approximation with tie correction for the +p-value. + ### `histogram.max` + +* `percentile` {number} A percentile value in the range (0, 100]. +* `options` {Object} + * `confidence` {number} The confidence level for the interval, between + 0 and 1 (exclusive). **Default:** `0.95`. +* Returns: {Object} + * `value` {number} The point estimate (same as `histogram.percentile()`). + * `lower` {number} The lower bound of the confidence interval. + * `upper` {number} The upper bound of the confidence interval. + +Returns a confidence interval for the given percentile using the exact +binomial method. With fewer samples, the interval will be wider, reflecting +the greater uncertainty in the percentile estimate. Requires at least 2 +recorded values; with fewer than 2, `lower` and `upper` will equal `value`. + +```js +const { createHistogram } = require('node:perf_hooks'); + +const h = createHistogram(); +for (let i = 0; i < 1000; i++) { + h.record(Math.floor(Math.random() * 100)); +} + +const ci = h.percentileCI(99); +console.log(ci.value); // The p99 point estimate +console.log(ci.lower); // The lower bound (95% confidence) +console.log(ci.upper); // The upper bound (95% confidence) +``` + ### `histogram.percentiles` + +* `percentiles` {number\[]} An array of percentile values in the range (0, 100]. +* Returns: {Map} A map of percentile values to their corresponding histogram + values. + +Returns the values at the specified percentiles, computed in a single +efficient pass over the histogram data. More efficient than calling +`histogram.percentile()` multiple times. + ### `histogram.reset()` + +* Type: {number} + +The skewness of the recorded values. Measures the asymmetry of the +distribution. A positive value indicates a right-skewed distribution +(longer right tail, common for latency data); a negative value +indicates a left-skewed distribution. + ### `histogram.stddev` + +* `other` {Histogram} The histogram to compare against. +* `options` {Object} + * `confidence` {number} Confidence level for the interval, between 0 and 1. + **Default:** `0.95`. +* Returns: {Object} + * `tStatistic` {number} The Welch t-statistic. + * `degreesOfFreedom` {number} Welch-Satterthwaite degrees of freedom. + * `pValue` {number} Two-tailed p-value. + * `confidenceInterval` {Object} + * `lower` {number} Lower bound of the confidence interval on the + difference of means. + * `upper` {number} Upper bound. + +Performs [Welch's t-test][] comparing the means of this histogram and `other`. +The p-value indicates the probability of observing a difference at least this +extreme under the null hypothesis that the two distributions have the same +mean. Both histograms must have at least 2 recorded values; otherwise the +result has `pValue` 1 and `tStatistic` 0. + ## Class: `ELDHistogram extends Histogram` A `Histogram` that records event loop delay, returned by @@ -2091,6 +2395,193 @@ added: Calculates the amount of time (in nanoseconds) that has passed since the previous call to `recordDelta()` and records that amount in the histogram. +### `histogram.recordCorrected(val, expectedInterval)` + + + +* `val` {number|bigint} The value to record. +* `expectedInterval` {number|bigint} The expected recording interval. + +Records a value with coordinated omission correction. When a system stall +prevents timely recording, this method backfills intermediate values at +`expectedInterval` steps between the previously recorded value and `val`. +This compensates for measurement gaps that would otherwise underrepresent +latency. + +### `histogram.subtract(other)` + + + +* `other` {RecordableHistogram} + +Subtracts the values of `other` from this histogram. Both histograms should +have compatible configurations. Bucket counts that would become negative +are clamped to zero. + +## Histogram analysis examples + +The `Histogram` class provides statistical analysis methods useful for +performance monitoring, SLO enforcement, and regression detection. + +### Distribution shape analysis + +```js +const { createHistogram } = require('node:perf_hooks'); + +const h = createHistogram(); + +// Simulate a right-skewed latency distribution +for (let i = 0; i < 1000; i++) { + h.record(Math.ceil(Math.random() * 100)); +} +// Add some outliers +for (let i = 0; i < 10; i++) { + h.record(500 + Math.ceil(Math.random() * 500)); +} + +console.log('Skewness:', h.skewness.toFixed(4)); // Positive = right-skewed +console.log('Kurtosis:', h.kurtosis.toFixed(4)); // Positive = heavy tails +``` + +### SLO monitoring with CDF + +```js +const { createHistogram } = require('node:perf_hooks'); + +const latency = createHistogram(); + +// Record request latencies (in nanoseconds)... + +// "What fraction of requests complete within 100ms?" +const withinSLO = latency.cdf(100_000_000); +console.log(`${(withinSLO * 100).toFixed(1)}% of requests within SLO`); + +// "What fraction of requests exceed 500ms?" +const violating = latency.ccdf(500_000_000); +console.log(`${(violating * 100).toFixed(1)}% of requests violating SLO`); +``` + +### SLO burn rate monitoring + +```js +const { createHistogram } = require('node:perf_hooks'); + +// Track latency with EWMA (half-life 100 samples) and a 200ms SLO threshold +const latency = createHistogram({ + halfLife: 100, + threshold: 200_000_000, // 200ms in nanoseconds +}); + +// Record request latencies... + +// Smoothed error rate: probability of exceeding the threshold +console.log(`Error rate: ${(latency.ewmaErrorRate * 100).toFixed(2)}%`); + +// Burn rate against a 99.9% SLO +// >1 means the error budget is depleting faster than allowed +const rate = latency.burnRate(0.999); +console.log(`Burn rate: ${rate.toFixed(2)}x`); + +// EWMA mean and stddev track the smoothed latency +console.log(`EWMA latency: ${latency.ewmaMean.toFixed(0)}ns`); +console.log(`EWMA stddev: ${latency.ewmaStddev.toFixed(0)}ns`); +``` + +### Regression detection with KS test + +```js +const { createHistogram } = require('node:perf_hooks'); + +const baseline = createHistogram(); +const current = createHistogram(); + +// Record baseline and current latencies... + +// D-statistic: 0 = identical, 1 = completely different +const d = baseline.ksTest(current); +if (d > 0.1) { + console.log(`Possible regression detected (D=${d.toFixed(4)})`); +} +``` + +### Batch percentile queries + +```js +const { createHistogram } = require('node:perf_hooks'); + +const h = createHistogram(); +// Record values... + +// Efficiently query common monitoring percentiles in one pass +const p = h.percentilesAt([50, 75, 90, 95, 99, 99.9]); +console.log('p50:', p.get(50)); +console.log('p99:', p.get(99)); +``` + +### Snapshot diffing with subtract + +```js +const { createHistogram } = require('node:perf_hooks'); + +const total = createHistogram(); +const snapshot = createHistogram(); + +// Record values into total... +// Periodically snapshot for "last interval" analysis: +snapshot.add(total); + +// Later, take a new snapshot and diff: +const newSnapshot = createHistogram(); +newSnapshot.add(total); +newSnapshot.subtract(snapshot); +// newSnapshot now contains only the values recorded since the last snapshot +console.log('Recent p99:', newSnapshot.percentile(99)); +``` + +### Benchmark comparison with Welch's t-test + +```js +const { createHistogram } = require('node:perf_hooks'); + +const baseline = createHistogram(); +const candidate = createHistogram(); + +// Record operation rates from the old and new builds... + +const result = baseline.welchTest(candidate); +const improvement = ((candidate.mean - baseline.mean) / baseline.mean * 100); + +console.log(`Improvement: ${improvement.toFixed(2)}%`); +console.log(`p-value: ${result.pValue.toFixed(6)}`); +console.log(`95% CI: [${result.confidenceInterval.lower.toFixed(2)}, ` + + `${result.confidenceInterval.upper.toFixed(2)}]`); + +if (result.pValue < 0.05) { + const d = baseline.cohensD(candidate); + console.log(`Statistically significant (Cohen's d = ${d.toFixed(4)})`); +} +``` + +### Effect size with Cliff's delta + +```js +const { createHistogram } = require('node:perf_hooks'); + +const before = createHistogram(); +const after = createHistogram(); + +// Record latencies before and after a change... + +const delta = before.cliffsD(after); +// A delta > 0: before tends to produce larger values (improvement) +// A delta < 0: after tends to produce larger values (regression) +console.log(`Cliff's delta: ${delta.toFixed(4)}`); +``` + ## Examples ### Measuring the duration of async operations @@ -2345,13 +2836,17 @@ dns.promises.resolve('localhost'); ``` [Async Hooks]: async_hooks.md +[Cliff's delta]: https://en.wikipedia.org/wiki/Effect_size#Cliff's_delta +[Cohen's d]: https://en.wikipedia.org/wiki/Effect_size#Cohen's_d [Fetch Response Body Info]: https://fetch.spec.whatwg.org/#response-body-info [Fetch Timing Info]: https://fetch.spec.whatwg.org/#fetch-timing-info [High Resolution Time]: https://www.w3.org/TR/hr-time-2 +[Mann-Whitney U test]: https://en.wikipedia.org/wiki/Mann%E2%80%93Whitney_U_test [Performance Timeline]: https://w3c.github.io/performance-timeline/ [Resource Timing]: https://www.w3.org/TR/resource-timing-2/ [User Timing]: https://www.w3.org/TR/user-timing/ [Web Performance APIs]: https://w3c.github.io/perf-timing-primer/ +[Welch's t-test]: https://en.wikipedia.org/wiki/Welch%27s_t-test [Worker threads]: worker_threads.md#worker-threads [`'exit'`]: process.md#event-exit [`child_process.spawnSync()`]: child_process.md#child_processspawnsynccommand-args-options diff --git a/doc/api/permissions.md b/doc/api/permissions.md index 673d38541dd1..3d8f9fe81038 100644 --- a/doc/api/permissions.md +++ b/doc/api/permissions.md @@ -81,6 +81,13 @@ using the [`--allow-child-process`][] and [`--allow-worker`][] respectively. To allow native addons when using permission model, use the [`--allow-addons`][] flag. For WASI, use the [`--allow-wasi`][] flag. +To allow use of OpenSSL STORE loaders, for example to load a private key +from a {URL} passed to [`crypto.createPrivateKey()`][], use the +[`--allow-openssl-store`][] flag. +This flag grants broad authority to configured OpenSSL STORE loaders, which may +access files, devices, tokens, or the network. Access performed by a loader is +not constrained by the `fs.read` or `fs.write` permission scopes. + #### Runtime API When enabling the Permission Model through the [`--permission`][] @@ -126,7 +133,7 @@ const config = fs.readFileSync('/etc/myapp/config.json', 'utf8'); // Drop read access to /etc/myapp after initialization process.permission.drop('fs.read', '/etc/myapp'); -// This will now throw ERR_ACCESS_DENIED +// This will now return false process.permission.has('fs.read', '/etc/myapp/config.json'); // false // Drop child process permission entirely @@ -204,7 +211,7 @@ $ node --permission index.js * `index.js` will be included in the allowed file system read list ```console -$ node -r /path/to/custom-require.js --permission index.js. +$ node -r /path/to/custom-require.js --permission index.js ``` * `/path/to/custom-require.js` will be included in the allowed file system read @@ -259,7 +266,8 @@ Example `node.config.json`: "allow-fs-write": ["./bar"], "allow-child-process": true, "allow-worker": true, - "allow-addons": false + "allow-addons": false, + "allow-openssl-store": false } } ``` @@ -319,6 +327,7 @@ There are constraints you need to know before using this system: * Inspector protocol * File system access * WASI + * OpenSSL STORE loaders * The Permission Model is initialized after the Node.js environment is set up. However, certain flags such as `--env-file` or `--openssl-config` are designed to read files before environment initialization. As a result, such flags are @@ -368,9 +377,11 @@ Developers relying on --permission to sandbox untrusted code should be aware tha [`--allow-child-process`]: cli.md#--allow-child-process [`--allow-fs-read`]: cli.md#--allow-fs-read [`--allow-fs-write`]: cli.md#--allow-fs-write +[`--allow-openssl-store`]: cli.md#--allow-openssl-store [`--allow-wasi`]: cli.md#--allow-wasi [`--allow-worker`]: cli.md#--allow-worker [`--permission-audit`]: cli.md#--permission-audit [`--permission`]: cli.md#--permission +[`crypto.createPrivateKey()`]: crypto.md#cryptocreateprivatekeykey [`npx`]: https://docs.npmjs.com/cli/commands/npx [`permission.has()`]: process.md#processpermissionhasscope-reference diff --git a/doc/api/process.md b/doc/api/process.md index ffa8046ace63..4d2add1373cb 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -3184,6 +3184,7 @@ The available scopes are: * `fs.read` - File System read operations * `fs.write` - File System write operations * `child` - Child process spawning operations +* `openssl.store` - Loading keys through OpenSSL STORE loaders * `worker` - Worker thread spawning operation ```js @@ -3237,6 +3238,7 @@ The available scopes are the same as [`process.permission.has()`][]: * `fs.read` - File System read operations * `fs.write` - File System write operations * `child` - Child process spawning operations +* `openssl.store` - Loading keys through OpenSSL STORE loaders * `worker` - Worker thread spawning operation * `inspector` - Inspector operations * `wasi` - WASI operations diff --git a/doc/api/quic.md b/doc/api/quic.md index 17251d959202..75dba5028425 100644 --- a/doc/api/quic.md +++ b/doc/api/quic.md @@ -305,7 +305,11 @@ unidirectional (data flows in only one direction). The `quic` module provides separate APIs for creating each kind: [`session.createBidirectionalStream()`][] and [`session.createUnidirectionalStream()`][]. Streams initiated by a remote -peer are delivered via the [`session.onstream`][] callback. +peer are delivered via the [`session.onstream`][] callback. When the +negotiated application protocol supports the stream-level callbacks (e.g. +HTTP/3) and an `onheaders` callback is configured, incoming streams can +instead be consumed entirely through it and registering `onstream` is +optional. There are two ways to write data to a stream: @@ -409,7 +413,9 @@ A typical client session progresses through these stages: On the server side, call [`quic.listen()`][] with a callback. The callback fires for each incoming session after the TLS handshake begins. Incoming -streams arrive via the [`session.onstream`][] callback. +streams arrive via the [`session.onstream`][] callback, or, for HTTP/3 +sessions with an `onheaders` callback configured, directly through that +callback (see the [minimal HTTP/3 server][] example). [`session.destroy()`][] is available for immediate teardown — all open streams are destroyed and the session is closed without waiting for them to finish. @@ -1090,6 +1096,15 @@ added: v23.8.0 The callback to invoke when a new stream is initiated by a remote peer. Read/write. +If no `onstream` callback is set and the stream has no other consumer, an +incoming stream is destroyed on arrival and a warning is emitted. An +`onheaders` callback counts as a consumer when the negotiated application +protocol supports it (e.g. HTTP/3), because it is invoked for every incoming +request stream. Other stream-level callbacks (`ontrailers`, `oninfo`, +`onwanttrailers`) do not, since they are conditional or outbound-only and +would leave the stream unobservable. An HTTP/3 server that handles requests +entirely through `onheaders` does not need to set `onstream`. + ### `session.ondatagram` + +* `code` {number|bigint} The application error code to send to the peer. + **Default:** `0n`. + +Tells the peer that this end will not send any more data on this stream, +sending a `RESET_STREAM` frame carrying `code`. The readable side is left +open, so data already sent by the peer remains available to read. + +Any data still queued for sending is discarded. A reset stream is never +acknowledged by the peer, so the outbound queue can no longer drain. + +No acknowledgement of this action is provided. The call does nothing if the +stream has been destroyed, if it has already been reset, or if it is a +remote-initiated unidirectional stream, which has no writable side to abort. + +### `stream.stopSending([code])` + + + +* `code` {number|bigint} The application error code to send to the peer. + **Default:** `0n`. + +Asks the peer to stop sending data on this stream, sending a `STOP_SENDING` +frame carrying `code`. The writable side is left open, so this end can +still send data. + +No acknowledgement of this action is provided. The call does nothing if the +stream has been destroyed, or if it is a locally-initiated unidirectional +stream, which has no readable side to abort. + ### `stream.early` * `sql` {string} A SQL string to compile to a prepared statement. @@ -677,7 +699,8 @@ sqlTagStore.get`SELECT ${value}`; is equivalent to: ```js -db.prepare('SELECT ?').get(value); +using statement = db.prepare('SELECT ?'); +statement.get(value); ``` However, in the first example, the tag store will cache the underlying prepared @@ -797,6 +820,7 @@ added: --> * `changeset` {Uint8Array} A binary changeset or patchset. + * `options` {Object} The configuration options for how the changes will be applied. * `filter` {Function} for each table affected by at least one change in the changeset, the `filter` callback is invoked with the @@ -825,6 +849,7 @@ added: applying the changeset is aborted and the database is rolled back. **Default**: A function that returns `SQLITE_CHANGESET_ABORT`. + * Returns: {boolean} Whether the changeset was applied successfully without being aborted. An exception is thrown if the database is not @@ -841,7 +866,7 @@ targetDb.exec('CREATE TABLE data(key INTEGER PRIMARY KEY, value TEXT)'); const session = sourceDb.createSession(); -const insert = sourceDb.prepare('INSERT INTO data (key, value) VALUES (?, ?)'); +using insert = sourceDb.prepare('INSERT INTO data (key, value) VALUES (?, ?)'); insert.run(1, 'hello'); insert.run(2, 'world'); @@ -861,7 +886,7 @@ targetDb.exec('CREATE TABLE data(key INTEGER PRIMARY KEY, value TEXT)'); const session = sourceDb.createSession(); -const insert = sourceDb.prepare('INSERT INTO data (key, value) VALUES (?, ?)'); +using insert = sourceDb.prepare('INSERT INTO data (key, value) VALUES (?, ?)'); insert.run(1, 'hello'); insert.run(2, 'world'); @@ -922,7 +947,8 @@ wrapper around [`sqlite3session_patchset()`][]. ### `session.close()` -Closes the session. An exception is thrown if the database or the session is not open. This method is a +Closes the session. An exception is thrown if the database or the session is not open, +or if the session is currently generating a changeset or patchset. This method is a wrapper around [`sqlite3session_delete()`][]. ### `session[Symbol.dispose]()` @@ -950,11 +976,61 @@ times with different bound values. Parameters also offer protection against [SQL injection][] attacks. For these reasons, prepared statements are preferred over hand-crafted SQL strings when handling user input. +### Binding parameters + +The `all()`, `get()`, `iterate()`, and `run()` methods bind their arguments to +the parameters of the prepared statement before executing it. Parameters are +either anonymous or named. + +Anonymous parameters are written as `?` in SQL and are bound in order from the +arguments passed to the method. The `?NNN` form assigns SQLite parameter index +`NNN` to a placeholder. Avoid mixing numbered and named parameters because they +share parameter indexes. + +```js +db.prepare('SELECT ? AS a, ? AS b').get('x', 42); +// { a: 'x', b: 42 } +db.prepare('SELECT ?2 AS a, ?1 AS b').get('first', 'second'); +// { a: 'second', b: 'first' } +``` + +Named parameters begin with one of the prefix characters `$`, `:`, or `@` in +SQL. They are bound from an object passed as the first argument. Repeating a +name in the SQL binds the same value to every occurrence. + +```js +db.prepare('SELECT $a AS a, $b AS b').get({ $a: 1, $b: 2 }); +// { a: 1, b: 2 } +db.prepare('SELECT :a AS a').get({ ':a': 1 }); +// { a: 1 } +db.prepare('SELECT @a AS a').get({ '@a': 1 }); +// { a: 1 } +db.prepare('SELECT $k AS a, $k AS b').get({ k: 7 }); +// { a: 7, b: 7 } +``` + +The last example omits the prefix character from the object key. Bare names are +allowed by default; see [`statement.setAllowBareNamedParameters()`][] for their +caveats. + +Binding a key that does not name a parameter of the statement throws an +`ERR_INVALID_STATE` error unless unknown named parameters are ignored. See +[`statement.setAllowUnknownNamedParameters()`][]. + +See [Type conversion between JavaScript and SQLite][] for the values that can be +bound. Binding any other value throws an `ERR_INVALID_ARG_TYPE` error. + ### `statement.all([namedParameters][, ...anonymousParameters])` * `stringElements` {string\[]} Template literal elements containing the SQL query. -* `...boundParameters` {null|number|bigint|string|Buffer|TypedArray|DataView} +* `...boundParameters` {null|number|bigint|boolean|string|Buffer|TypedArray|DataView|ArrayBuffer|SharedArrayBuffer} Parameter values to be bound to placeholders in the template string. * Returns: {Array} An array of objects representing the rows returned by the query. @@ -1217,11 +1322,18 @@ called directly. * `stringElements` {string\[]} Template literal elements containing the SQL query. -* `...boundParameters` {null|number|bigint|string|Buffer|TypedArray|DataView} +* `...boundParameters` {null|number|bigint|boolean|string|Buffer|TypedArray|DataView|ArrayBuffer|SharedArrayBuffer} Parameter values to be bound to placeholders in the template string. * Returns: {Object | undefined} An object representing the first row returned by the query, or `undefined` if no rows are returned. @@ -1235,11 +1347,18 @@ called directly. * `stringElements` {string\[]} Template literal elements containing the SQL query. -* `...boundParameters` {null|number|bigint|string|Buffer|TypedArray|DataView} +* `...boundParameters` {null|number|bigint|boolean|string|Buffer|TypedArray|DataView|ArrayBuffer|SharedArrayBuffer} Parameter values to be bound to placeholders in the template string. * Returns: {Iterator} An iterator that yields objects representing the rows returned by the query. @@ -1252,11 +1371,18 @@ called directly. * `stringElements` {string\[]} Template literal elements containing the SQL query. -* `...boundParameters` {null|number|bigint|string|Buffer|TypedArray|DataView} +* `...boundParameters` {null|number|bigint|boolean|string|Buffer|TypedArray|DataView|ArrayBuffer|SharedArrayBuffer} Parameter values to be bound to placeholders in the template string. * Returns: {Object} An object containing information about the execution, including `changes` and `lastInsertRowid`. @@ -1326,7 +1452,7 @@ changes: database that have been added with [`ATTACH DATABASE`][] **Default:** `'main'`. * `target` {string} Name of the target database. This can be `'main'` (the default primary database) or any other database that have been added with [`ATTACH DATABASE`][] **Default:** `'main'`. - * `rate` {number} Number of pages to be transmitted in each batch of the backup. **Default:** `100`. + * `rate` {integer} Positive number of pages to be transmitted in each batch of the backup. **Default:** `100`. * `progress` {Function} An optional callback function that will be called after each backup step. The argument passed to this callback is an {Object} with `remainingPages` and `totalPages` properties, describing the current progress of the backup operation. @@ -1411,11 +1537,11 @@ conflict resolution handler passed to [`database.applyChangeset()`][]. See also SQLITE_CHANGESET_CONSTRAINT - If foreign key handling is enabled, and applying a changeset leaves the database in a state containing foreign key violations, the conflict handler is invoked with this constant exactly once before the changeset is committed. If the conflict handler returns SQLITE_CHANGESET_OMIT, the changes, including those that caused the foreign key constraint violation, are committed. Or, if it returns SQLITE_CHANGESET_ABORT, the changeset is rolled back. + If any other constraint violation occurs while applying a change (i.e. a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is invoked with this constant. SQLITE_CHANGESET_FOREIGN_KEY - If any other constraint violation occurs while applying a change (i.e. a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is invoked with this constant. + If foreign key handling is enabled, and applying a changeset leaves the database in a state containing foreign key violations, the conflict handler is invoked with this constant exactly once before the changeset is committed. If the conflict handler returns SQLITE_CHANGESET_OMIT, the changes, including those that caused the foreign key constraint violation, are committed. Or, if it returns SQLITE_CHANGESET_ABORT, the changeset is rolled back. @@ -1618,6 +1744,7 @@ callback function to indicate what type of operation is being authorized. +[Binding parameters]: #binding-parameters [Changesets and Patchsets]: https://www.sqlite.org/sessionintro.html#changesets_and_patchsets [Constants Passed To The Conflict Handler]: https://www.sqlite.org/session/c_changeset_conflict.html [Constants Returned From The Conflict Handler]: https://www.sqlite.org/session/c_changeset_abort.html @@ -1665,6 +1792,8 @@ callback function to indicate what type of operation is being authorized. [`sqlite3session_create()`]: https://www.sqlite.org/session/sqlite3session_create.html [`sqlite3session_delete()`]: https://www.sqlite.org/session/sqlite3session_delete.html [`sqlite3session_patchset()`]: https://www.sqlite.org/session/sqlite3session_patchset.html +[`statement.setAllowBareNamedParameters()`]: #statementsetallowbarenamedparametersenabled +[`statement.setAllowUnknownNamedParameters()`]: #statementsetallowunknownnamedparametersenabled [busy timeout]: https://sqlite.org/c3ref/busy_timeout.html [connection]: https://www.sqlite.org/c3ref/sqlite3.html [data types]: https://www.sqlite.org/datatype3.html diff --git a/doc/api/stream.md b/doc/api/stream.md index b37fc5f3d20d..d4061bb5fce0 100644 --- a/doc/api/stream.md +++ b/doc/api/stream.md @@ -3615,13 +3615,18 @@ reader.read().then(({ value, done }) => { added: - v19.9.0 - v18.17.0 +changes: + - version: v22.0.0 + pr-url: https://github.com/nodejs/node/pull/52037 + description: bump default highWaterMark. --> * `objectMode` {boolean} * Returns: {integer} -Returns the default highWaterMark used by streams. -Defaults to `65536` (64 KiB), or `16` for `objectMode`. +Returns the default highWaterMark used by streams. Defaults to `16` for +`objectMode`. For byte streams, it defaults to `65536` (64 KiB) on non-Windows +platforms and `16384` (16 KiB) on Windows. ### `stream.setDefaultHighWaterMark(objectMode, value)` @@ -3751,7 +3756,7 @@ changes: * `options` {Object} * `highWaterMark` {number} Buffer level when [`stream.write()`][stream-write] starts returning `false`. **Default:** - `65536` (64 KiB), or `16` for `objectMode` streams. + See [`stream.getDefaultHighWaterMark()`][]. * `decodeStrings` {boolean} Whether to encode `string`s passed to [`stream.write()`][stream-write] to `Buffer`s (with the encoding specified in the [`stream.write()`][stream-write] call) before passing @@ -3784,7 +3789,7 @@ changes: -```js +```cjs const { Writable } = require('node:stream'); class MyWritable extends Writable { @@ -3796,18 +3801,18 @@ class MyWritable extends Writable { } ``` -Or, when using pre-ES6 style constructors: + -```js -const { Writable } = require('node:stream'); -const util = require('node:util'); +```mjs +import { Writable } from 'node:stream'; -function MyWritable(options) { - if (!(this instanceof MyWritable)) - return new MyWritable(options); - Writable.call(this, options); +class MyWritable extends Writable { + constructor(options) { + // Calls the stream.Writable() constructor. + super(options); + // ... + } } -util.inherits(MyWritable, Writable); ``` Or, using the simplified constructor approach: @@ -4125,7 +4130,7 @@ changes: * `options` {Object} * `highWaterMark` {number} The maximum [number of bytes][hwm-gotcha] to store in the internal buffer before ceasing to read from the underlying resource. - **Default:** `65536` (64 KiB), or `16` for `objectMode` streams. + **Default:** See [`stream.getDefaultHighWaterMark()`][]. * `encoding` {string} If specified, then buffers will be decoded to strings using the specified encoding. **Default:** `null`. * `objectMode` {boolean} Whether this stream should behave @@ -4157,20 +4162,6 @@ class MyReadable extends Readable { } ``` -Or, when using pre-ES6 style constructors: - -```js -const { Readable } = require('node:stream'); -const util = require('node:util'); - -function MyReadable(options) { - if (!(this instanceof MyReadable)) - return new MyReadable(options); - Readable.call(this, options); -} -util.inherits(MyReadable, Readable); -``` - Or, using the simplified constructor approach: ```js @@ -4489,7 +4480,7 @@ changes: -```js +```cjs const { Duplex } = require('node:stream'); class MyDuplex extends Duplex { @@ -4500,18 +4491,17 @@ class MyDuplex extends Duplex { } ``` -Or, when using pre-ES6 style constructors: + -```js -const { Duplex } = require('node:stream'); -const util = require('node:util'); +```mjs +import { Duplex } from 'node:stream'; -function MyDuplex(options) { - if (!(this instanceof MyDuplex)) - return new MyDuplex(options); - Duplex.call(this, options); +class MyDuplex extends Duplex { + constructor(options) { + super(options); + // ... + } } -util.inherits(MyDuplex, Duplex); ``` Or, using the simplified constructor approach: @@ -4686,7 +4676,7 @@ output on the `Readable` side is not consumed. -```js +```cjs const { Transform } = require('node:stream'); class MyTransform extends Transform { @@ -4697,18 +4687,17 @@ class MyTransform extends Transform { } ``` -Or, when using pre-ES6 style constructors: + -```js -const { Transform } = require('node:stream'); -const util = require('node:util'); +```mjs +import { Transform } from 'node:stream'; -function MyTransform(options) { - if (!(this instanceof MyTransform)) - return new MyTransform(options); - Transform.call(this, options); +class MyTransform extends Transform { + constructor(options) { + super(options); + // ... + } } -util.inherits(MyTransform, Transform); ``` Or, using the simplified constructor approach: @@ -5066,6 +5055,7 @@ contain multi-byte characters. [`stream.cork()`]: #writablecork [`stream.duplexPair()`]: #streamduplexpairoptions [`stream.finished()`]: #streamfinishedstream-options-callback +[`stream.getDefaultHighWaterMark()`]: #streamgetdefaulthighwatermarkobjectmode [`stream.pipe()`]: #readablepipedestination-options [`stream.pipeline()`]: #streampipelinesource-transforms-destination-callback [`stream.uncork()`]: #writableuncork diff --git a/doc/api/stream_iter.md b/doc/api/stream_iter.md index 6a2dd5fac8b0..cf2168e326b5 100644 --- a/doc/api/stream_iter.md +++ b/doc/api/stream_iter.md @@ -431,14 +431,16 @@ the write. Use [`ondrain()`][] to wait for capacity rather than polling. the pending `end()` call; it does not fail the writer itself. * Returns: {Promise} Fulfills with the total number of bytes written. -Signal that no more data will be written. +Signals that no more data will be written and waits for buffered data to drain. #### `writer.endSync()` -* Returns: {number} Total bytes written, or `-1` if the writer is not open. +* Returns: {number} Total bytes written, or `-1` if ending cannot complete + synchronously. -Synchronous variant of `writer.end()`. Returns `-1` if the writer is already -closed or errored. Can be used as a try-fallback pattern: +Synchronous variant of `writer.end()`. A return value of `-1` means closing has +started but requires asynchronous draining. Use the try-fallback pattern to +await completion: ```cjs const result = writer.endSync(); diff --git a/doc/api/synopsis.md b/doc/api/synopsis.md index 24bb35e08f8c..85b2b4cf7470 100644 --- a/doc/api/synopsis.md +++ b/doc/api/synopsis.md @@ -15,15 +15,8 @@ Please see the [Command-line options][] document for more information. An example of a [web server][] written with Node.js which responds with `'Hello, World!'`: -Commands in this document start with `$` or `>` to replicate how they would -appear in a user's terminal. Do not include the `$` and `>` characters. They are -there to show the start of each command. - -Lines that don't start with `$` or `>` character show the output of the previous -command. - First, make sure to have downloaded and installed Node.js. See -[Installing Node.js via package manager][] for further install information. +[Installing Node.js][] for further install information. Now, create an empty project folder called `projects`, then navigate into it. @@ -90,5 +83,5 @@ If the browser displays the string `Hello, World!`, that indicates the server is working. [Command-line options]: cli.md#options -[Installing Node.js via package manager]: https://nodejs.org/en/download/package-manager/ +[Installing Node.js]: https://nodejs.org/en/download [web server]: http.md diff --git a/doc/api/timers.md b/doc/api/timers.md index 7c91543c4573..cdbed03ba7ac 100644 --- a/doc/api/timers.md +++ b/doc/api/timers.md @@ -600,7 +600,7 @@ being developed as a standard Web Platform API. Calling `timersPromises.scheduler.yield()` is equivalent to calling `timersPromises.setImmediate()` with no arguments. -[Event Loop]: https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/#setimmediate-vs-settimeout +[Event Loop]: https://nodejs.org/learn/asynchronous-work/event-loop-timers-and-nexttick#setimmediate-vs-settimeout [Scheduling APIs]: https://github.com/WICG/scheduling-apis [`AbortController`]: globals.md#class-abortcontroller [`TypeError`]: errors.md#class-typeerror diff --git a/doc/api/tls.md b/doc/api/tls.md index ed8588179117..4ff31989bf3a 100644 --- a/doc/api/tls.md +++ b/doc/api/tls.md @@ -468,35 +468,64 @@ to set the security level to 0 while using the default OpenSSL cipher list, you ```mjs import { createServer, connect } from 'node:tls'; -const port = 443; +import { readFileSync } from 'node:fs'; +const port = 8000; -createServer({ ciphers: 'DEFAULT@SECLEVEL=0', minVersion: 'TLSv1' }, function(socket) { +createServer({ + key: readFileSync('server-key.pem'), + cert: readFileSync('server-cert.pem'), + ciphers: 'DEFAULT@SECLEVEL=0', + minVersion: 'TLSv1', +}, function(socket) { console.log('Client connected with protocol:', socket.getProtocol()); socket.end(); this.close(); }) .listen(port, () => { - connect(port, { ciphers: 'DEFAULT@SECLEVEL=0', maxVersion: 'TLSv1' }); + connect(port, { + ciphers: 'DEFAULT@SECLEVEL=0', + minVersion: 'TLSv1', + maxVersion: 'TLSv1', + ca: [ readFileSync('server-cert.pem') ], + }); }); ``` ```cjs const { createServer, connect } = require('node:tls'); -const port = 443; +const { readFileSync } = require('node:fs'); +const port = 8000; -createServer({ ciphers: 'DEFAULT@SECLEVEL=0', minVersion: 'TLSv1' }, function(socket) { +createServer({ + key: readFileSync('server-key.pem'), + cert: readFileSync('server-cert.pem'), + ciphers: 'DEFAULT@SECLEVEL=0', + minVersion: 'TLSv1', +}, function(socket) { console.log('Client connected with protocol:', socket.getProtocol()); socket.end(); this.close(); }) .listen(port, () => { - connect(port, { ciphers: 'DEFAULT@SECLEVEL=0', maxVersion: 'TLSv1' }); + connect(port, { + ciphers: 'DEFAULT@SECLEVEL=0', + minVersion: 'TLSv1', + maxVersion: 'TLSv1', + ca: [ readFileSync('server-cert.pem') ], + }); }); ``` This approach sets the security level to 0, allowing the use of legacy features while still leveraging the default OpenSSL ciphers. +To generate the certificate and key for this example, run: + +```bash +openssl req -x509 -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' \ + -keyout server-key.pem -out server-cert.pem +``` + ### Using [`--tls-cipher-list`][] You can also set the security level and ciphers from the command line using the diff --git a/doc/api/tty.md b/doc/api/tty.md index 03f86cd66052..552467725820 100644 --- a/doc/api/tty.md +++ b/doc/api/tty.md @@ -69,12 +69,18 @@ A `boolean` that is always `true` for `tty.ReadStream` instances. -* `mode` {boolean} If `true`, configures the `tty.ReadStream` to operate as a - raw device. If `false`, configures the `tty.ReadStream` to operate in its - default mode. The `readStream.isRaw` property will be set to the resulting - mode. +* `mode` {boolean|string} If `true` or `'raw'`, configures the + `tty.ReadStream` to operate as a raw device. If `'io'`, configures the + `tty.ReadStream` to operate in binary-safe I/O mode. If `false`, configures + the `tty.ReadStream` to operate in its default mode. The `readStream.isRaw` + property will be set to whether the stream is in raw mode, and the + `readStream.rawMode` property will be set to the resulting mode. * Returns: {this} The read stream instance. Allows configuration of `tty.ReadStream` so that it operates as a raw device. @@ -86,6 +92,27 @@ characters. Ctrl+C will no longer cause a `SIGINT` when in this mode. This mode does not affect terminal output processing, such as newline translation on Unix terminals. +On Windows, `setRawMode()` requires write permission to the console input +buffer. When opening `"\\\\.\\CONIN$"` with the [`fs.open()`][] family of APIs +(for passing into `new tty.ReadStream()`), be sure to use a read/write flag +such as `'r+'`. + +When in binary-safe I/O mode, terminal output processing is also disabled. +This corresponds to libuv's `UV_TTY_MODE_IO` mode and is not supported on +Windows. + +### `readStream.rawMode` + + + +* {boolean|string} + +The current raw mode for the `tty.ReadStream`. This is `false` when the stream +is in its default mode, `'raw'` when raw input mode is enabled, and `'io'` when +binary-safe I/O mode is enabled. + ## Class: `tty.WriteStream` + +* `string` {string} The input MIME to parse +* Returns: {MIMEType|null} + +Attempts to parse the given `string` as a MIMEType. If the string cannot be +parsed, `null` is returned. + ## Class: `util.MIMEParams` \n`; } const attrsString = ArrayPrototypeJoin( diff --git a/lib/internal/test_runner/runner.js b/lib/internal/test_runner/runner.js index 3bfe719ce5be..8bfdca00bf5c 100644 --- a/lib/internal/test_runner/runner.js +++ b/lib/internal/test_runner/runner.js @@ -182,7 +182,7 @@ function getRunArgs(path, { forceExit, inspectPort, testNamePatterns, testSkipPatterns, - testTagFilterExpressions, + testTagFilters, only, hasFiles, testFiles, @@ -224,8 +224,8 @@ function getRunArgs(path, { forceExit, if (testSkipPatterns != null) { ArrayPrototypeForEach(testSkipPatterns, (pattern) => ArrayPrototypePush(runArgs, `--test-skip-pattern=${pattern}`)); } - if (testTagFilterExpressions != null) { - ArrayPrototypeForEach(testTagFilterExpressions, (value) => ArrayPrototypePush(runArgs, `--experimental-test-tag-filter=${value}`)); + if (testTagFilters != null) { + ArrayPrototypeForEach(testTagFilters, (value) => ArrayPrototypePush(runArgs, `--experimental-test-tag-filter=${value}`)); } if (only === true) { ArrayPrototypePush(runArgs, '--test-only'); @@ -284,6 +284,14 @@ class FileTest extends Test { this.timeout = null; } + willBeFilteredByTags() { + // File wrappers have no tags of their own. Tag filtering applies to the + // tests inside the file, which run in a child process (or in-process + // import); filtering the wrapper would prevent the file from running at + // all. + return false; + } + #skipReporting() { return this.#reportedChildren > 0 && (!this.error || this.error.failureType === kSubtestsFailed); } @@ -863,7 +871,6 @@ function run(options = kEmptyObject) { }); } - let testTagFilterExpressions = null; if (testTagFilters != null) { if (!ArrayIsArray(testTagFilters)) { testTagFilters = [testTagFilters]; @@ -875,10 +882,8 @@ function run(options = kEmptyObject) { testTagFilters = ArrayPrototypeMap(testTagFilters, (value, i) => ( validateAndCanonicalizeTagFilter(value, `options.testTagFilters[${i}]`) )); - testTagFilterExpressions = testTagFilters; } } - testTagFilterExpressions ??= options.testTagFilterExpressions; validateOneOf(isolation, 'options.isolation', ['process', 'none']); validateBoolean(coverage, 'options.coverage'); @@ -908,7 +913,7 @@ function run(options = kEmptyObject) { } if (env != null) { - validateObject(env); + validateObject(env, 'options.env'); if (isolation === 'none') { throw new ERR_INVALID_ARG_VALUE('options.env', env, 'is not supported with isolation=\'none\''); @@ -936,6 +941,18 @@ function run(options = kEmptyObject) { testTagFilters, }; + if (isolation === 'none') { + if (testNamePatterns != null) { + globalOptions.testNamePatterns = testNamePatterns; + } + if (testSkipPatterns != null) { + globalOptions.testSkipPatterns = testSkipPatterns; + } + if (only != null) { + globalOptions.only = only; + } + } + const root = createTestTree(rootTestOptions, globalOptions); let testFiles = files ?? createTestFileList(globPatterns, cwd); const { isTestRunner } = globalOptions; @@ -979,7 +996,6 @@ function run(options = kEmptyObject) { testNamePatterns, testSkipPatterns, testTagFilters, - testTagFilterExpressions, hasFiles: files != null, globPatterns, only, diff --git a/lib/internal/test_runner/test.js b/lib/internal/test_runner/test.js index 6ae330ce005e..d7aa3ca7f1dd 100644 --- a/lib/internal/test_runner/test.js +++ b/lib/internal/test_runner/test.js @@ -2,6 +2,7 @@ const { ArrayFrom, ArrayPrototypeEvery, + ArrayPrototypeJoin, ArrayPrototypePush, ArrayPrototypePushApply, ArrayPrototypeShift, @@ -656,7 +657,7 @@ class Test extends AsyncResource { } if (isFilteringByTags) { - this.filteredByTag = !evaluateTagFilters(config.testTagFilters, this.tagSet); + this.filteredByTag = this.willBeFilteredByTags(); if (!this.filteredByTag) { for (let t = this.parent; t !== null && t.filteredByTag; t = t.parent) { t.filteredByTag = false; @@ -894,6 +895,10 @@ class Test extends AsyncResource { return false; } + willBeFilteredByTags() { + return !evaluateTagFilters(this.config.testTagFilters, this.tagSet); + } + /** * Returns a name of the test prefixed by name of all its ancestors in ascending order, separated by a space * Ex."grandparent parent test" @@ -1668,6 +1673,17 @@ class Test extends AsyncResource { details.passed_on_attempt = this.passedAttempt; } + // Generate classname from suite hierarchy for JUnit reporter + if (this.parent && this.parent !== this.root) { + const parts = []; + for (let t = this.parent; t !== t.root; t = t.parent) { + ArrayPrototypeUnshift(parts, t.name); + } + if (parts.length > 0) { + details.classname = ArrayPrototypeJoin(parts, '.'); + } + } + return { __proto__: null, details, directive }; } diff --git a/lib/internal/test_runner/tests_stream.js b/lib/internal/test_runner/tests_stream.js index 7fb514fb99e2..f8dd21152eeb 100644 --- a/lib/internal/test_runner/tests_stream.js +++ b/lib/internal/test_runner/tests_stream.js @@ -45,6 +45,7 @@ class TestsStream extends Readable { parentId, details, tags: ArrayPrototypeSlice(tags), + ...(details.classname && { __proto__: null, classname: details.classname }), ...loc, ...directive, }); @@ -60,6 +61,7 @@ class TestsStream extends Readable { parentId, details, tags: ArrayPrototypeSlice(tags), + ...(details.classname && { __proto__: null, classname: details.classname }), ...loc, ...directive, }); diff --git a/lib/internal/test_runner/utils.js b/lib/internal/test_runner/utils.js index 9937d9592a29..10083ceaac15 100644 --- a/lib/internal/test_runner/utils.js +++ b/lib/internal/test_runner/utils.js @@ -272,7 +272,6 @@ function parseCommandLine() { let testNamePatterns = mapPatternFlagToRegExArray('--test-name-pattern'); let testSkipPatterns = mapPatternFlagToRegExArray('--test-skip-pattern'); let testTagFilters = null; - let testTagFilterExpressions = null; if (isChildProcessV8) { kBuiltinReporters.set('v8-serializer', 'internal/test_runner/reporter/v8-serializer'); @@ -308,19 +307,14 @@ function parseCommandLine() { const tagFilterFlag = getOptionValue('--experimental-test-tag-filter'); if (tagFilterFlag?.length > 0) { emitExperimentalWarning('Test tags'); - testTagFilterExpressions = tagFilterFlag; - // Validate at parent startup so a malformed flag fails fast, - // independent of isolation mode. Under isolation='process' the - // validated strings go unused at the parent (children re-validate - // and apply the filter); the validation here only surfaces input - // errors early. - const validated = ArrayPrototypeMap( + // File wrappers are exempt from tag filtering, so holding the filters + // in the parent is safe under any isolation mode; under + // isolation='process' the canonical values are re-emitted to the + // child processes, which apply the filter themselves. + testTagFilters = ArrayPrototypeMap( tagFilterFlag, (value, i) => validateAndCanonicalizeTagFilter(value, `--experimental-test-tag-filter[${i}]`), ); - if (isolation === 'none') { - testTagFilters = validated; - } } if (isolation === 'none') { @@ -364,7 +358,6 @@ function parseCommandLine() { const tagFilterFlag = getOptionValue('--experimental-test-tag-filter'); if (tagFilterFlag?.length > 0) { emitExperimentalWarning('Test tags'); - testTagFilterExpressions = tagFilterFlag; testTagFilters = ArrayPrototypeMap( tagFilterFlag, (value, i) => validateAndCanonicalizeTagFilter(value, `--experimental-test-tag-filter[${i}]`), @@ -431,7 +424,6 @@ function parseCommandLine() { sourceMaps, testNamePatterns, testSkipPatterns, - testTagFilterExpressions, testTagFilters, timeout, updateSnapshots, diff --git a/lib/internal/tls/secure-context.js b/lib/internal/tls/secure-context.js index 41c3bb57acd8..862d7501a1d9 100644 --- a/lib/internal/tls/secure-context.js +++ b/lib/internal/tls/secure-context.js @@ -26,6 +26,7 @@ const { } = require('internal/util/types'); const { + validateArray, validateBuffer, validateInt32, validateObject, @@ -212,10 +213,7 @@ function configSecureContext(context, options = kEmptyObject, name = 'options') } if (certificateCompression != null) { - if (!ArrayIsArray(certificateCompression)) { - throw new ERR_INVALID_ARG_TYPE( - `${name}.certificateCompression`, 'Array', certificateCompression); - } + validateArray(certificateCompression, `${name}.certificateCompression`); if (certificateCompression.length > 0) { // Pack length + algorithm IDs into a single Uint32 for a cheap diff --git a/lib/internal/tls/wrap.js b/lib/internal/tls/wrap.js index 54bb09bdc641..89254b105b9b 100644 --- a/lib/internal/tls/wrap.js +++ b/lib/internal/tls/wrap.js @@ -1322,6 +1322,13 @@ function onServerSocketSecure() { if (verifyError) { this.authorizationError = verifyError.code; + if (this._rejectUnauthorized) + this.destroy(); + } else if (!this._handle.getPeerX509Certificate()) { + // Ncrypto reports X509_V_OK for TLS 1.3 resumption without a peer + // certificate, as it uses PSKs. Require one to authorize the socket. + this.authorizationError = 'UNABLE_TO_GET_ISSUER_CERT'; + if (this._rejectUnauthorized) this.destroy(); } else { diff --git a/lib/internal/url.js b/lib/internal/url.js index 0845f867fcd8..f58a26d94e7e 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -74,14 +74,10 @@ const { }, } = require('internal/errors'); const { - CHAR_AMPERSAND, CHAR_BACKWARD_SLASH, - CHAR_EQUAL, CHAR_FORWARD_SLASH, CHAR_LOWERCASE_A, CHAR_LOWERCASE_Z, - CHAR_PERCENT, - CHAR_PLUS, CHAR_COLON, } = require('internal/constants'); const path = require('path'); @@ -167,41 +163,62 @@ function lazyCryptoRandom() { return cryptoRandom; } +/** + * Copy href and the latest `urlComponents` snapshot into a URLContext. + * Property assignment order matches the historical URLContext fields so + * `util.inspect(..., { showHidden: true })` stays stable. + * @param {object} ctx + * @param {string} href + */ +function setURLContextFromBinding(ctx, href) { + const c = bindingUrl.urlComponents; + ctx.href = href; + ctx.protocol_end = c[0]; + ctx.username_end = c[1]; + ctx.host_start = c[2]; + ctx.host_end = c[3]; + ctx.pathname_start = c[5]; + ctx.search_start = c[6]; + ctx.hash_start = c[7]; + ctx.port = c[4]; + ctx.scheme_type = c[8]; +} + // This class provides the internal state of a URL object. An instance of this // class is stored in every URL object and is accessed internally by setters // and getters. It roughly corresponds to the concept of a URL record in the // URL Standard, with a few differences. It is also the object transported to // the C++ binding. // Refs: https://url.spec.whatwg.org/#concept-url +// +// scheme_type refers to ada::scheme::type: +// HTTP = 0, NOT_SPECIAL = 1, HTTPS = 2, WS = 3, FTP = 4, WSS = 5, FILE = 6 class URLContext { // This is the maximum value uint32_t can get. // Ada uses uint32_t(-1) for declaring omitted values. static #omitted = 4294967295; - href = ''; - protocol_end = 0; - username_end = 0; - host_start = 0; - host_end = 0; - pathname_start = 0; - search_start = 0; - hash_start = 0; - port = 0; /** - * Refers to `ada::scheme::type` - * - * enum type : uint8_t { - * HTTP = 0, - * NOT_SPECIAL = 1, - * HTTPS = 2, - * WS = 3, - * FTP = 4, - * WSS = 5, - * FILE = 6 - * }; - * @type {number} + * @param {string} [href] Parsed href. When omitted, create an empty context + * (used by `URL.parse` on invalid input). When provided, `bindingUrl.parse` + * / `update` has just written `urlComponents`. */ - scheme_type = 1; + constructor(href) { + if (href === undefined) { + this.href = ''; + this.protocol_end = 0; + this.username_end = 0; + this.host_start = 0; + this.host_end = 0; + this.pathname_start = 0; + this.search_start = 0; + this.hash_start = 0; + this.port = 0; + this.scheme_type = 1; + return; + } + setURLContextFromBinding(this, href); + } get hasPort() { return this.port !== URLContext.#omitted; @@ -220,6 +237,21 @@ let setURLSearchParamsModified; let setURLSearchParamsContext; let getURLSearchParamsList; let setURLSearchParams; +/** + * Brand check for URL instances created by this realm's URL constructor. + * + * Unlike `isURL()`, which duck-types so that URL objects coming from other + * implementations are recognized, this cannot be satisfied by an ordinary + * object that merely exposes `href` and `protocol`. Use it where treating an + * attacker-supplied plain object as a URL would be a security concern. + * @type {(value: unknown) => value is URL} + */ +let isURLInstance; +/** + * Returns the canonical serialization of a URL from its private state. + * @type {(value: URL) => string} + */ +let getURLHref; class URLSearchParamsIterator { #target; @@ -316,12 +348,17 @@ class URLSearchParams { // "associated url object" #context; + // Cached application/x-www-form-urlencoded serialization. Cleared on + // mutation so repeated toString()/URL.href reads stay cheap. + #serialized; + static { setURLSearchParamsContext = (obj, ctx) => { obj.#context = ctx; }; getURLSearchParamsList = (obj) => obj.#searchParams; setURLSearchParams = (obj, query) => { + obj.#serialized = undefined; if (query === undefined) { obj.#searchParams = []; } else { @@ -330,6 +367,13 @@ class URLSearchParams { }; } + #markUpdated() { + this.#serialized = undefined; + if (this.#context) { + setURLSearchParamsModified(this.#context); + } + } + // URL Standard says the default value is '', but as undefined and '' have // the same result, undefined is used to prevent unnecessary parsing. // Default parameter is necessary to keep URLSearchParams.length === 0 in @@ -346,6 +390,7 @@ class URLSearchParams { // shortcut to avoid having to go through the costly generic iterator. const childParams = init.#searchParams; this.#searchParams = childParams.slice(); + this.#serialized = init.#serialized; } else if (method != null) { // Sequence> if (typeof method !== 'function') { @@ -373,8 +418,8 @@ class URLSearchParams { // Append (innerSequence[0], innerSequence[1]) to query's list. ArrayPrototypePush( this.#searchParams, - StringPrototypeToWellFormed(`${pair[0]}`), - StringPrototypeToWellFormed(`${pair[1]}`), + toUSVString(pair[0]), + toUSVString(pair[1]), ); } else { if (((typeof pair !== 'object' && typeof pair !== 'function') || @@ -386,7 +431,7 @@ class URLSearchParams { for (const element of pair) { length++; - ArrayPrototypePush(this.#searchParams, StringPrototypeToWellFormed(`${element}`)); + ArrayPrototypePush(this.#searchParams, toUSVString(element)); } // If innerSequence's size is not 2, then throw a TypeError. @@ -404,8 +449,8 @@ class URLSearchParams { const key = keys[i]; const desc = ReflectGetOwnPropertyDescriptor(init, key); if (desc !== undefined && desc.enumerable) { - const typedKey = StringPrototypeToWellFormed(key); - const typedValue = StringPrototypeToWellFormed(`${init[key]}`); + const typedKey = toUSVString(key); + const typedValue = toUSVString(init[key]); // Two different keys may become the same USVString after normalization. // In that case, we retain the later one. Refer to WPT. @@ -422,7 +467,7 @@ class URLSearchParams { } } else { // https://url.spec.whatwg.org/#dom-urlsearchparams-urlsearchparams - init = StringPrototypeToWellFormed(`${init}`); + init = toUSVString(init); this.#searchParams = init ? parseParams(init) : []; } } @@ -476,13 +521,10 @@ class URLSearchParams { throw new ERR_MISSING_ARGS('name', 'value'); } - name = StringPrototypeToWellFormed(`${name}`); - value = StringPrototypeToWellFormed(`${value}`); + name = toUSVString(name); + value = toUSVString(value); ArrayPrototypePush(this.#searchParams, name, value); - - if (this.#context) { - setURLSearchParamsModified(this.#context); - } + this.#markUpdated(); } delete(name, value = undefined) { @@ -494,12 +536,12 @@ class URLSearchParams { } const list = this.#searchParams; - name = StringPrototypeToWellFormed(`${name}`); + name = toUSVString(name); const { length } = list; let write = 0; if (value !== undefined) { - value = StringPrototypeToWellFormed(`${value}`); + value = toUSVString(value); for (let i = 0; i < length; i += 2) { if (list[i] === name && list[i + 1] === value) { continue; @@ -523,8 +565,10 @@ class URLSearchParams { } } - if (write !== length) + if (write !== length) { list.length = write; + this.#serialized = undefined; + } if (this.#context) { setURLSearchParamsModified(this.#context); @@ -540,8 +584,9 @@ class URLSearchParams { } const list = this.#searchParams; - name = StringPrototypeToWellFormed(`${name}`); - for (let i = 0; i < list.length; i += 2) { + name = toUSVString(name); + const { length } = list; + for (let i = 0; i < length; i += 2) { if (list[i] === name) { return list[i + 1]; } @@ -559,10 +604,11 @@ class URLSearchParams { const list = this.#searchParams; const values = []; - name = StringPrototypeToWellFormed(`${name}`); - for (let i = 0; i < list.length; i += 2) { + name = toUSVString(name); + const { length } = list; + for (let i = 0; i < length; i += 2) { if (list[i] === name) { - values.push(list[i + 1]); + ArrayPrototypePush(values, list[i + 1]); } } return values; @@ -577,13 +623,14 @@ class URLSearchParams { } const list = this.#searchParams; - name = StringPrototypeToWellFormed(`${name}`); + name = toUSVString(name); if (value !== undefined) { - value = StringPrototypeToWellFormed(`${value}`); + value = toUSVString(value); } - for (let i = 0; i < list.length; i += 2) { + const { length } = list; + for (let i = 0; i < length; i += 2) { if (list[i] === name) { if (value === undefined || list[i + 1] === value) { return true; @@ -603,8 +650,8 @@ class URLSearchParams { } const list = this.#searchParams; - name = StringPrototypeToWellFormed(`${name}`); - value = StringPrototypeToWellFormed(`${value}`); + name = toUSVString(name); + value = toUSVString(value); const { length } = list; // If there are any name-value pairs whose name is `name`, in `list`, set @@ -641,9 +688,7 @@ class URLSearchParams { ArrayPrototypePush(list, name, value); } - if (this.#context) { - setURLSearchParamsModified(this.#context); - } + this.#markUpdated(); } sort() { @@ -690,9 +735,7 @@ class URLSearchParams { } } - if (this.#context) { - setURLSearchParamsModified(this.#context); - } + this.#markUpdated(); } // https://heycam.github.io/webidl/#es-iterators @@ -745,7 +788,12 @@ class URLSearchParams { if (typeof this !== 'object' || this === null || !(#searchParams in this)) throw new ERR_INVALID_THIS('URLSearchParams'); - return serializeParams(this.#searchParams); + if (this.#serialized !== undefined) { + return this.#serialized; + } + const serialized = serializeParams(this.#searchParams); + this.#serialized = serialized; + return serialized; } } @@ -804,11 +852,18 @@ const kCreateURLFromPosixPathSymbol = Symbol('kCreateURLFromPosixPath'); const kCreateURLFromWindowsPathSymbol = Symbol('kCreateURLFromWindowsPath'); class URL { - #context = new URLContext(); + #context; #searchParams; #searchParamsModified; static { + isURLInstance = (value) => typeof value === 'object' && value !== null && #context in value; + + getURLHref = (value) => { + value.#ensureSearchParamsUpdated(); + return value.#context.href; + }; + setURLSearchParamsModified = (obj) => { // When URLSearchParams changes, we lazily update URL on the next read/write for performance. obj.#searchParamsModified = true; @@ -822,16 +877,16 @@ class URL { } constructor(input, base = undefined, parseSymbol = undefined) { - markTransferMode(this, false, false); - if (arguments.length === 0) { throw new ERR_MISSING_ARGS('url'); } // StringPrototypeToWellFormed is not needed. - input = `${input}`; + if (typeof input !== 'string') { + input = `${input}`; + } - if (base !== undefined) { + if (base !== undefined && typeof base !== 'string') { base = `${base}`; } @@ -846,9 +901,12 @@ class URL { bindingUrl.pathToFileURL(input, interpretAsWindowsPath, base) : bindingUrl.parse(input, base, raiseException); } - if (href) { - this.#updateContext(href); - } + + // Delay context allocation until parse finishes so invalid URLs that + // throw do not pay for an unused URLContext. Initialize in one shot + // from the binding snapshot instead of writing an empty context first. + this.#context = href ? new URLContext(href) : new URLContext(); + markTransferMode(this, false, false); } static parse(input, base = undefined) { @@ -917,29 +975,7 @@ class URL { const previousSearch = shouldUpdateSearchParams && this.#searchParams && (this.#searchParamsModified ? this.#getSearchFromParams() : this.#getSearchFromContext()); - this.#context.href = href; - - const { - 0: protocol_end, - 1: username_end, - 2: host_start, - 3: host_end, - 4: port, - 5: pathname_start, - 6: search_start, - 7: hash_start, - 8: scheme_type, - } = bindingUrl.urlComponents; - - this.#context.protocol_end = protocol_end; - this.#context.username_end = username_end; - this.#context.host_start = host_start; - this.#context.host_end = host_end; - this.#context.port = port; - this.#context.pathname_start = pathname_start; - this.#context.search_start = search_start; - this.#context.hash_start = hash_start; - this.#context.scheme_type = scheme_type; + setURLContextFromBinding(this.#context, href); if (this.#searchParams) { // If the search string has updated, URL becomes the source of truth, and we update URLSearchParams. @@ -1164,10 +1200,12 @@ class URL { throw new ERR_MISSING_ARGS('url'); } - url = `${url}`; + if (typeof url !== 'string') { + url = `${url}`; + } if (base !== undefined) { - return bindingUrl.canParse(url, `${base}`); + return bindingUrl.canParse(url, typeof base === 'string' ? base : `${base}`); } // It is important to differentiate the canParse call statements @@ -1254,102 +1292,82 @@ function installObjectURLMethods() { }); } +function toUSVString(value) { + return typeof value === 'string' ? + StringPrototypeToWellFormed(value) : + StringPrototypeToWellFormed(`${value}`); +} + +function unescapeFormComponent(s) { + try { + return decodeURIComponent(s); + } catch { + return querystring.unescapeBuffer(s).toString(); + } +} + +function hasPercentHex(s) { + const end = s.length - 2; + for (let i = 0; i < end; i++) { + if (StringPrototypeCharCodeAt(s, i) === 37 && // '%' + isHexTable[StringPrototypeCharCodeAt(s, i + 1)] === 1 && + isHexTable[StringPrototypeCharCodeAt(s, i + 2)] === 1) { + return true; + } + } + return false; +} + +function decodeFormComponent(qs, start, end) { + if (start >= end) { + return ''; + } + const s = qs.slice(start, end); + const plus = s.indexOf('+'); + const pct = s.indexOf('%'); + if (plus === -1 && pct === -1) { + return s; + } + const replaced = plus === -1 ? s : s.replaceAll('+', ' '); + // Only percent-decode when a complete %HH sequence exists. A lone '%' or + // a '%' followed by a non-hex character must be left intact so later + // serialization can encode the raw bytes. + if (pct === -1 || !hasPercentHex(replaced)) { + return replaced; + } + return unescapeFormComponent(replaced); +} + // application/x-www-form-urlencoded parser // Ref: https://url.spec.whatwg.org/#concept-urlencoded-parser function parseParams(qs) { - const out = []; - let seenSep = false; - let buf = ''; - let encoded = false; - let encodeCheck = 0; + const len = qs.length; let i = qs[0] === '?' ? 1 : 0; - let pairStart = i; - let lastPos = i; - for (; i < qs.length; ++i) { - const code = StringPrototypeCharCodeAt(qs, i); - - // Try matching key/value pair separator - if (code === CHAR_AMPERSAND) { - if (pairStart === i) { - // We saw an empty substring between pair separators - lastPos = pairStart = i + 1; - continue; - } + if (i >= len) { + return []; + } - if (lastPos < i) - buf += qs.slice(lastPos, i); - if (encoded) - buf = querystring.unescape(buf); - out.push(buf); - - // If `buf` is the key, add an empty value. - if (!seenSep) - out.push(''); - - seenSep = false; - buf = ''; - encoded = false; - encodeCheck = 0; - lastPos = pairStart = i + 1; - continue; - } - - // Try matching key/value separator (e.g. '=') if we haven't already - if (!seenSep && code === CHAR_EQUAL) { - // Key/value separator match! - if (lastPos < i) - buf += qs.slice(lastPos, i); - if (encoded) - buf = querystring.unescape(buf); - out.push(buf); - - seenSep = true; - buf = ''; - encoded = false; - encodeCheck = 0; - lastPos = i + 1; - continue; - } - - // Handle + and percent decoding. - if (code === CHAR_PLUS) { - if (lastPos < i) - buf += StringPrototypeSlice(qs, lastPos, i); - buf += ' '; - lastPos = i + 1; - } else if (!encoded) { - // Try to match an (valid) encoded byte (once) to minimize unnecessary - // calls to string decoding functions - if (code === CHAR_PERCENT) { - encodeCheck = 1; - } else if (encodeCheck > 0) { - if (isHexTable[code] === 1) { - if (++encodeCheck === 3) { - encoded = true; - } - } else { - encodeCheck = 0; - } + const out = []; + // Native indexOf/slice/push outperform primordials on this tight loop. + const encoded = qs.indexOf('+', i) !== -1 || qs.indexOf('%', i) !== -1; + while (i < len) { + let amp = qs.indexOf('&', i); + if (amp === -1) { + amp = len; + } + if (amp !== i) { + const eq = qs.indexOf('=', i); + if (eq === -1 || eq > amp) { + out.push(encoded ? decodeFormComponent(qs, i, amp) : qs.slice(i, amp), ''); + } else { + out.push( + encoded ? decodeFormComponent(qs, i, eq) : qs.slice(i, eq), + encoded ? decodeFormComponent(qs, eq + 1, amp) : qs.slice(eq + 1, amp), + ); } } + i = amp + 1; } - - // Deal with any leftover key or value data - - // There is a trailing &. No more processing is needed. - if (pairStart === i) - return out; - - if (lastPos < i) - buf += StringPrototypeSlice(qs, lastPos, i); - if (encoded) - buf = querystring.unescape(buf); - ArrayPrototypePush(out, buf); - - // If `buf` is the key, add an empty value. - if (!seenSep) - ArrayPrototypePush(out, ''); - return out; } @@ -1380,17 +1398,17 @@ function serializeParams(array) { if (len === 0) return ''; - const firstEncodedParam = encodeStr(array[0], noEscape, paramHexTable); - const firstEncodedValue = encodeStr(array[1], noEscape, paramHexTable); - let output = `${firstEncodedParam}=${firstEncodedValue}`; - - for (let i = 2; i < len; i += 2) { - const encodedParam = encodeStr(array[i], noEscape, paramHexTable); - const encodedValue = encodeStr(array[i + 1], noEscape, paramHexTable); - output += `&${encodedParam}=${encodedValue}`; + if (len === 2) { + return encodeStr(array[0], noEscape, paramHexTable) + '=' + + encodeStr(array[1], noEscape, paramHexTable); } - return output; + const pairs = new Array(len / 2); + for (let i = 0, j = 0; i < len; i += 2, ++j) { + pairs[j] = encodeStr(array[i], noEscape, paramHexTable) + '=' + + encodeStr(array[i + 1], noEscape, paramHexTable); + } + return ArrayPrototypeJoin(pairs, '&'); } // for merge sort @@ -1721,6 +1739,8 @@ module.exports = { urlToHttpOptions, encodeStr, isURL, + isURLInstance, + getURLHref, urlUpdateActions: updateActions, getURLOrigin, diff --git a/lib/internal/util/comparisons.js b/lib/internal/util/comparisons.js index 9adc5665cf9b..1233fa78dc92 100644 --- a/lib/internal/util/comparisons.js +++ b/lib/internal/util/comparisons.js @@ -761,7 +761,7 @@ function setEquiv(a, b, mode, memo) { // If the specified value doesn't exist in the second set it's a object // (or in loose mode: a non-matching primitive). Find the // deep-(mode-)equal element in a set copy to reduce duplicate checks. - array.push(val); + ArrayPrototypePush(array, val); } } @@ -891,7 +891,7 @@ function mapEquiv(a, b, mode, memo) { } array = []; } - array.push(key2); + ArrayPrototypePush(array, key2); } else { // By directly retrieving the value we prevent another b.has(key2) check in // almost all possible cases. @@ -907,7 +907,7 @@ function mapEquiv(a, b, mode, memo) { if (array === undefined) { array = []; } - array.push(key2); + ArrayPrototypePush(array, key2); } } } diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index 88110719e417..17e9de541289 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -282,16 +282,14 @@ const meta = [ ]; // Regex used for ansi escape code splitting -// Ref: https://github.com/chalk/ansi-regex/blob/f338e1814144efb950276aac84135ff86b72dc8e/index.js +// Ref: https://github.com/chalk/ansi-regex/blob/72bc570aaf25fca25541b49c6a8564f3ec63e835/index.js // License: MIT by Sindre Sorhus // Matches all ansi escape code sequences in a string const ansi = new RegExp( - '[\\u001B\\u009B][[\\]()#;?]*' + - '(?:(?:(?:(?:;[-a-zA-Z\\d\\/\\#&.:=?%@~_]+)*' + - '|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/\\#&.:=?%@~_]*)*)?' + - '(?:\\u0007|\\u001B\\u005C|\\u009C))' + - '|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?' + - '[\\dA-PR-TZcf-nq-uy=><~]))', 'g', + '(?:\\u001B\\][\\s\\S]*?(?:\\u0007|\\u001B\\u005C|\\u009C))' + + '|[\\u001B\\u009B][[\\]()#;?]*' + + '(?:\\d{1,4}(?:[;:]\\d{0,4})*)?' + + '[\\dA-PR-TZcf-nq-uy=><~]', 'g', ); let getStringWidth; @@ -2304,7 +2302,7 @@ function formatProperty(ctx, value, recurseTimes, key, type, desc, const tmp = FunctionPrototypeCall(desc.get, original); if (tmp === null) { str = `${s(`[${label}:`, sp)} ${s('null', 'null')}${s(']', sp)}`; - } else if (typeof tmp === 'object') { + } else if (typeof tmp === 'object' || typeof tmp === 'function') { str = `${s(`[${label}]`, sp)} ${formatValue(ctx, tmp, recurseTimes)}`; } else { const primitive = formatPrimitive(s, tmp, ctx); @@ -2352,6 +2350,14 @@ function isBelowBreakLength(ctx, output, start, base) { // TODO(BridgeAR): Add unicode support. Use the readline getStringWidth // function. Check the performance overhead and make it an opt-in in case it's // significant. + // allow the single-line format if the length limit is infinite and no items have newlines + if (ctx.breakLength === Infinity) { + if (base !== '' && StringPrototypeIncludes(base, '\n')) return false; + for (let i = 0; i < output.length; i++) { + if (typeof output[i] === 'string' && StringPrototypeIncludes(output[i], '\n')) return false; + } + return true; + } let totalLength = output.length + start; if (totalLength + output.length > ctx.breakLength) return false; diff --git a/lib/internal/webidl.js b/lib/internal/webidl.js index 13575d4f730d..7f61bae8c21f 100644 --- a/lib/internal/webidl.js +++ b/lib/internal/webidl.js @@ -20,6 +20,7 @@ const { NumberIsNaN, NumberMAX_SAFE_INTEGER, NumberMIN_SAFE_INTEGER, + ObjectPrototypeHasOwnProperty, ObjectPrototypeIsPrototypeOf, SafeArrayIterator, SafeSet, @@ -699,16 +700,47 @@ function createDictionaryConverter( const dictionaries = ArrayIsArray(members[0]) ? members : [members]; const sortedDictionaries = []; + function ownMember(member, key) { + return ObjectPrototypeHasOwnProperty(member, key) ? member[key] : undefined; + } + + // Dictionaries with no defaults and no required members skip steps + // 4.1.5/4.1.6 entirely, keeping the absent-member path free. + let anyMissingMemberHandling = false; + // Web IDL dictionary conversion steps 3-4 process inherited dictionaries // from least-derived to most-derived and sort only within each dictionary. // Callers with inheritance pass one member array per dictionary level. for (let i = 0; i < dictionaries.length; i++) { - ArrayPrototypePush( - sortedDictionaries, - ArrayPrototypeToSorted(dictionaries[i], compareMembers), + const sortedMembers = ArrayPrototypeToSorted( + dictionaries[i], + compareMembers, ); + // Definition sites spell out only the members they need, so reading the + // optional ones below would resolve through %Object.prototype%. + // Re-materialize each descriptor once with every key present, copied from + // own properties only. The ordinary prototype is deliberate: nothing + // consults it now, and detaching it measurably slows these reads down. + for (let j = 0; j < sortedMembers.length; j++) { + const member = sortedMembers[j]; + const defaultValue = ownMember(member, 'defaultValue'); + const required = ownMember(member, 'required'); + if (typeof defaultValue === 'function' || required) { + anyMissingMemberHandling = true; + } + sortedMembers[j] = { + key: ownMember(member, 'key'), + converter: ownMember(member, 'converter'), + defaultValue, + required, + validator: ownMember(member, 'validator'), + }; + } + ArrayPrototypePush(sortedDictionaries, sortedMembers); } + const hasMissingMemberHandling = anyMissingMemberHandling; + return function(jsDict, options = kEmptyObject) { // Step 1: reject non-object, non-null, non-undefined values. if (jsDict != null && type(jsDict) !== 'Object') { @@ -747,14 +779,16 @@ function createDictionaryConverter( member.validator?.(idlMemberValue, jsDict); // Step 4.1.4.2: set idlDict[key] to the IDL value. idlDict[key] = idlMemberValue; - } else if (typeof member.defaultValue === 'function') { - // Step 4.1.5: store the member default value. - idlDict[key] = member.defaultValue(); - } else if (member.required) { - // Step 4.1.6: required missing members throw. - throw makeException( - missingDictionaryMemberMessage(dictionaryName, key), - makeOptions(options, options.context, 'ERR_MISSING_OPTION')); + } else if (hasMissingMemberHandling) { + if (typeof member.defaultValue === 'function') { + // Step 4.1.5: store the member default value. + idlDict[key] = member.defaultValue(); + } else if (member.required) { + // Step 4.1.6: required missing members throw. + throw makeException( + missingDictionaryMemberMessage(dictionaryName, key), + makeOptions(options, options.context, 'ERR_MISSING_OPTION')); + } } } } diff --git a/lib/internal/webstreams/encoding.js b/lib/internal/webstreams/encoding.js index f316222ccbf0..038b64030a7a 100644 --- a/lib/internal/webstreams/encoding.js +++ b/lib/internal/webstreams/encoding.js @@ -4,6 +4,7 @@ const { ObjectDefineProperties, String, StringPrototypeCharCodeAt, + StringPrototypeSlice, Uint8Array, } = primordials; @@ -31,6 +32,9 @@ const { kEnumerableProperty, } = require('internal/util'); +// Shared per-chunk decode options; decode() only reads the flag. +const kDecodeStreamingOptions = { __proto__: null, stream: true }; + /** * @typedef {import('./readablestream').ReadableStream} ReadableStream * @typedef {import('./writablestream').WritableStream} WritableStream @@ -46,34 +50,26 @@ class TextEncoderStream { this.#transform = new TransformStream({ transform: (chunk, controller) => { // https://encoding.spec.whatwg.org/#encode-and-enqueue-a-chunk + // The only cross-chunk state is a trailing high surrogate; + // encode() replaces interior lone surrogates with U+FFFD exactly + // like the spec's per-code-unit walk. chunk = String(chunk); - let finalChunk = ''; - for (let i = 0; i < chunk.length; i++) { - const item = chunk[i]; - const codeUnit = StringPrototypeCharCodeAt(item, 0); - if (this.#pendingHighSurrogate !== null) { - const highSurrogate = this.#pendingHighSurrogate; - this.#pendingHighSurrogate = null; - if (0xDC00 <= codeUnit && codeUnit <= 0xDFFF) { - finalChunk += highSurrogate + item; - continue; - } - finalChunk += '\uFFFD'; - } - if (0xD800 <= codeUnit && codeUnit <= 0xDBFF) { - this.#pendingHighSurrogate = item; - continue; - } - if (0xDC00 <= codeUnit && codeUnit <= 0xDFFF) { - finalChunk += '\uFFFD'; - continue; - } - finalChunk += item; + if (chunk.length === 0) + return; + if (this.#pendingHighSurrogate !== null) { + chunk = this.#pendingHighSurrogate + chunk; + this.#pendingHighSurrogate = null; } - if (finalChunk) { - const value = this.#handle.encode(finalChunk); - controller.enqueue(value); + const lastCodeUnit = + StringPrototypeCharCodeAt(chunk, chunk.length - 1); + if (0xD800 <= lastCodeUnit && lastCodeUnit <= 0xDBFF) { + this.#pendingHighSurrogate = + StringPrototypeSlice(chunk, -1); + chunk = StringPrototypeSlice(chunk, 0, -1); + if (chunk.length === 0) + return; } + controller.enqueue(this.#handle.encode(chunk)); }, flush: (controller) => { // https://encoding.spec.whatwg.org/#encode-and-flush @@ -137,7 +133,7 @@ class TextDecoderStream { if (chunk === undefined) { throw new ERR_INVALID_ARG_TYPE('chunk', 'string', chunk); } - const value = this.#handle.decode(chunk, { stream: true }); + const value = this.#handle.decode(chunk, kDecodeStreamingOptions); if (value) controller.enqueue(value); }, diff --git a/lib/internal/webstreams/readablestream.js b/lib/internal/webstreams/readablestream.js index 255832ee0bda..dfb3b7e11af5 100644 --- a/lib/internal/webstreams/readablestream.js +++ b/lib/internal/webstreams/readablestream.js @@ -62,6 +62,7 @@ const { const { validateAbortSignal, validateBuffer, + validateNumber, validateObject, kValidateObjectAllowObjects, kValidateObjectAllowObjectsAndNull, @@ -101,6 +102,7 @@ const { cloneAsUint8Array, copyArrayBuffer, createPromiseCallback1Param, + createRawCallback1Param, customInspect, defaultSizeAlgorithm, dequeueValue, @@ -110,17 +112,19 @@ const { getNonWritablePropertyDescriptor, isBrandCheck, kEmptyQueue, + kParkedAlgorithmResult, + kResolvedPromise, kState, kType, lazyTransfer, materializeQueue, + nonOpCallback, nonOpCancel, - nonOpPull, - nonOpStart, rejectedHandledRecord, resetQueue, resolvedRecord, setPromiseHandled, + thenAlgorithmResult, } = require('internal/webstreams/util'); const { @@ -137,7 +141,6 @@ const { writableStreamDefaultWriterRelease, writableStreamDefaultWriterWriteWithRequest, writerClosedPromise, - writerReadyPromise, } = require('internal/webstreams/writablestream'); const { Buffer } = require('buffer'); @@ -1060,17 +1063,7 @@ class ReadableStreamBYOBReader { async read(view, options = kEmptyObject) { if (!isReadableStreamBYOBReader(this)) throw new ERR_INVALID_THIS('ReadableStreamBYOBReader'); - if (!isArrayBufferView(view)) { - throw new ERR_INVALID_ARG_TYPE( - 'view', - [ - 'Buffer', - 'TypedArray', - 'DataView', - ], - view, - ); - } + validateBuffer(view, 'view'); validateObject(options, 'options', kValidateObjectAllowObjectsAndNull); const viewByteLength = ArrayBufferViewGetByteLength(view); @@ -1095,8 +1088,7 @@ class ReadableStreamBYOBReader { // detached, but there's no API available to use to check that. const min = options?.min ?? 1; - if (typeof min !== 'number') - throw new ERR_INVALID_ARG_TYPE('options.min', 'number', min); + validateNumber(min, 'options.min'); if (!NumberIsInteger(min)) throw new ERR_INVALID_ARG_VALUE('options.min', min, 'must be an integer'); if (min <= 0) @@ -1455,19 +1447,85 @@ function readableStreamFromIterable(iterable) { if (iterator === null || (typeof iterator !== 'object' && typeof iterator !== 'function')) { throw new ERR_INVALID_STATE.TypeError('The iterator method must return an object'); } - const startAlgorithm = nonOpStart; + // Per GetIteratorDirect, the next method is looked up once. + const nextMethod = iterator.next; + const startAlgorithm = nonOpCallback; - async function pullAlgorithm() { - const iterResult = await iterator.next(); + // Callback-style pull: the reaction steps are reused across chunks and + // completion is delivered to the controller's cached pull reactions + // (the kParkedAlgorithmResult contract). One pull runs at a time, so a + // single slot carries a non-thenable next() result between steps. + let pendingIterResult; + + function rejectPull(error) { + readableStreamDefaultControllerError(stream[kState].controller, error); + } + + function processIterResult(iterResult) { + const controller = stream[kState].controller; if (typeof iterResult !== 'object' || iterResult === null) { - throw new ERR_INVALID_STATE.TypeError( - 'The promise returned by the iterator.next() method must fulfill with an object'); + rejectPull(new ERR_INVALID_STATE.TypeError( + 'The promise returned by the iterator.next() method must fulfill with an object')); + return; } - if (iterResult.done) { - readableStreamDefaultControllerClose(stream[kState].controller); - } else { - readableStreamDefaultControllerEnqueue(stream[kState].controller, await iterResult.value); + try { + if (iterResult.done) { + readableStreamDefaultControllerClose(controller); + } else { + const value = iterResult.value; + if (value !== null && + (typeof value === 'object' || typeof value === 'function')) { + // Adopted like `await iterResult.value`, keeping the observable + // .then lookup on plain objects. + PromisePrototypeThen(PromiseResolve(value), enqueueValue, rejectPull); + return; + } + readableStreamDefaultControllerEnqueue(controller, value); + } + } catch (error) { + rejectPull(error); + return; + } + // pullFulfilled exists: the controller creates it before the pull. + controller[kState].pullFulfilled(); + } + + function enqueueValue(value) { + const controller = stream[kState].controller; + try { + readableStreamDefaultControllerEnqueue(controller, value); + } catch (error) { + rejectPull(error); + return; } + controller[kState].pullFulfilled(); + } + + function processPendingIterResult() { + const iterResult = pendingIterResult; + pendingIterResult = undefined; + processIterResult(iterResult); + } + + function pullAlgorithm() { + let nextResult; + try { + nextResult = FunctionPrototypeCall(nextMethod, iterator); + } catch (error) { + return PromiseReject(error); + } + if (nextResult !== null && + (typeof nextResult === 'object' || typeof nextResult === 'function')) { + // Mirrors `await iterator.next()`: processIterResult runs at the + // microtask position the await resumed. + PromisePrototypeThen( + PromiseResolve(nextResult), processIterResult, rejectPull); + return kParkedAlgorithmResult; + } + // A non-thenable next() result fails validation a microtask later. + pendingIterResult = nextResult; + PromisePrototypeThen(kResolvedPromise, processPendingIterResult); + return kParkedAlgorithmResult; } async function cancelAlgorithm(reason) { @@ -1674,11 +1732,31 @@ function readableStreamPipeTo( // the chunk travels through `pendingChunk`. let pendingChunk; let readRequest; + let readyHook; // Ready promise rejection is handled by the destination-errored // watcher. function ignoreReadyRejection() {} + // Parks the pump on the destination's backpressure by installing a + // record that duck-types the writer's lazily-materialized + // [[readyPromise]] record: writableStreamUpdateBackpressure resolves it + // when backpressure clears (after publishing the new backpressure + // state), which re-enters the pump directly instead of rotating a + // fresh promise record plus reaction per flip. The pipe holds the only + // reference to the writer, so the record is never observable as a real + // ready promise; the erroring/release paths probe `promise` via + // isPromisePending() and call `reject`, so it carries a real + // forever-pending promise and a no-op reject. + function parkOnReady() { + readyHook ??= { + promise: new Promise(nonOpCallback), + resolve: pump, + reject: ignoreReadyRejection, + }; + writer[kState].ready = readyHook; + } + function forwardChunk() { const chunk = pendingChunk; pendingChunk = undefined; @@ -1690,10 +1768,7 @@ function readableStreamPipeTo( if (shuttingDown) return; if (dest[kState].backpressure) { - PromisePrototypeThen( - writerReadyPromise(writer).promise, - pump, - ignoreReadyRejection); + parkOnReady(); return; } @@ -1738,9 +1813,18 @@ function readableStreamPipeTo( return; } - // Yield to microtask queue between batches to allow events/signals - // to fire - queueMicrotask(pump); + // Park on backpressure directly: the ready hook resumes the pump + // when a completed write clears it. + if (dest[kState].backpressure) { + parkOnReady(); + return; + } + + // Yield to the microtask queue between batches so completed-write + // reactions and events/signals fire; a shared resolved promise + // enqueues the continuation at the same position as queueMicrotask + // without the per-batch scheduling overhead. + PromisePrototypeThen(kResolvedPromise, pump); return; } @@ -1752,7 +1836,7 @@ function readableStreamPipeTo( // synchronous write during enqueue(). See WHATWG Streams spec // "ReadableStreamPipeTo" step 15's "chunk steps". pendingChunk = chunk; - queueMicrotask(forwardChunk); + PromisePrototypeThen(kResolvedPromise, forwardChunk); }, [kClose]() {}, [kError]() {}, @@ -1867,7 +1951,7 @@ function readableStreamDefaultTee(stream, cloneForBranch2) { // The microtask is required by the spec (ReadableStreamTee's // "chunk steps" queue one). pendingChunk = value; - queueMicrotask(forwardChunk); + PromisePrototypeThen(kResolvedPromise, forwardChunk); }, [kClose]() { // The `process.nextTick()` is not part of the spec. @@ -1911,9 +1995,9 @@ function readableStreamDefaultTee(stream, cloneForBranch2) { } branch1 = - createReadableStream(nonOpStart, pullAlgorithm, cancel1Algorithm); + createReadableStream(nonOpCallback, pullAlgorithm, cancel1Algorithm); branch2 = - createReadableStream(nonOpStart, pullAlgorithm, cancel2Algorithm); + createReadableStream(nonOpCallback, pullAlgorithm, cancel2Algorithm); PromisePrototypeThen( readerClosedPromise(reader).promise, @@ -2020,7 +2104,7 @@ function readableByteStreamTee(stream) { defaultReadRequest ??= { [kChunk](chunk) { pendingChunk = chunk; - queueMicrotask(forwardChunk); + PromisePrototypeThen(kResolvedPromise, forwardChunk); }, [kClose]() { reading = false; @@ -2199,9 +2283,9 @@ function readableByteStreamTee(stream) { } branch1 = - createReadableByteStream(nonOpStart, pull1Algorithm, cancel1Algorithm); + createReadableByteStream(nonOpCallback, pull1Algorithm, cancel1Algorithm); branch2 = - createReadableByteStream(nonOpStart, pull2Algorithm, cancel2Algorithm); + createReadableByteStream(nonOpCallback, pull2Algorithm, cancel2Algorithm); forwardReaderError(reader); @@ -2709,8 +2793,18 @@ function readableStreamDefaultControllerPull(controller) { controller[kState].pullRejected = (error) => readableStreamDefaultControllerError(controller, error); } - PromisePrototypeThen( - controller[kState].pullAlgorithm(controller), + // The pull algorithm may be a raw callback (a wrapped user source.pull + // returns its result uncoerced; a synchronous throw surfaces here) or an + // internal algorithm that always returns a promise; thenAlgorithmResult + // handles both. + let result; + try { + result = controller[kState].pullAlgorithm(controller); + } catch (error) { + result = PromiseReject(error); + } + thenAlgorithmResult( + result, controller[kState].pullFulfilled, controller[kState].pullRejected); } @@ -2834,10 +2928,10 @@ function setupReadableStreamDefaultControllerFromSource( const cancel = source?.cancel; const startAlgorithm = start ? FunctionPrototypeBind(start, source, controller) : - nonOpStart; + nonOpCallback; const pullAlgorithm = pull ? - createPromiseCallback1Param('source.pull', pull, source) : - nonOpPull; + createRawCallback1Param('source.pull', pull, source) : + nonOpCallback; const cancelAlgorithm = cancel ? createPromiseCallback1Param('source.cancel', cancel, source) : nonOpCancel; @@ -3529,8 +3623,15 @@ function readableByteStreamControllerCallPullIfNeeded(controller) { controller[kState].pullRejected = (error) => readableByteStreamControllerError(controller, error); } - PromisePrototypeThen( - controller[kState].pullAlgorithm(controller), + // See readableStreamDefaultControllerPull for the raw-callback contract. + let result; + try { + result = controller[kState].pullAlgorithm(controller); + } catch (error) { + result = PromiseReject(error); + } + thenAlgorithmResult( + result, controller[kState].pullFulfilled, controller[kState].pullRejected); } @@ -3708,10 +3809,10 @@ function setupReadableByteStreamControllerFromSource( const autoAllocateChunkSize = source?.autoAllocateChunkSize; const startAlgorithm = start ? FunctionPrototypeBind(start, source, controller) : - nonOpStart; + nonOpCallback; const pullAlgorithm = pull ? - createPromiseCallback1Param('source.pull', pull, source) : - nonOpPull; + createRawCallback1Param('source.pull', pull, source) : + nonOpCallback; const cancelAlgorithm = cancel ? createPromiseCallback1Param('source.cancel', cancel, source) : nonOpCancel; diff --git a/lib/internal/webstreams/transformstream.js b/lib/internal/webstreams/transformstream.js index 535c783a3a31..30b7b1c8fac1 100644 --- a/lib/internal/webstreams/transformstream.js +++ b/lib/internal/webstreams/transformstream.js @@ -5,6 +5,8 @@ const { ObjectDefineProperties, ObjectSetPrototypeOf, PromisePrototypeThen, + PromiseReject, + PromiseResolve, PromiseWithResolvers, Symbol, SymbolToStringTag, @@ -44,12 +46,14 @@ const { const { createPromiseCallback1Param, - createPromiseCallback2Params, + createRawCallback2Params, customInspect, extractHighWaterMark, extractSizeAlgorithm, getNonWritablePropertyDescriptor, isBrandCheck, + kParkedAlgorithmResult, + kResolvedPromise, kState, kType, nonOpCancel, @@ -258,7 +262,10 @@ function InternalTransferredTransformStream() { readable: undefined, writable: undefined, backpressure: undefined, - backpressureChange: undefined, + pullPending: false, + pendingWrite: undefined, + pendingWriteChunk: undefined, + writeContinuation: undefined, controller: undefined, }; } @@ -348,7 +355,9 @@ const isTransformStream = const isTransformStreamDefaultController = isBrandCheck('TransformStreamDefaultController'); -async function defaultTransformAlgorithm(chunk, controller) { +// Raw callback (see createRawCallback*): invoked inside the try/catch of +// transformStreamDefaultControllerPerformTransform. +function defaultTransformAlgorithm(chunk, controller) { transformStreamDefaultControllerEnqueue(controller, chunk); } @@ -385,7 +394,12 @@ function initializeTransformStream( writable, controller: undefined, backpressure: undefined, - backpressureChange: undefined, + // Continuation slots replacing the spec's + // [[backpressureChangePromise]]; see transformStreamSetBackpressure. + pullPending: false, + pendingWrite: undefined, + pendingWriteChunk: undefined, + writeContinuation: undefined, }; transformStreamSetBackpressure(stream, true); @@ -422,24 +436,30 @@ function transformStreamUnblockWrite(stream) { // The spec's [[backpressureChangePromise]] is only ever observed by the // source pull algorithm (settles when backpressure next becomes true) and // by a sink write arriving while backpressure is set (settles when -// backpressure next becomes false). Instead of allocating a fresh promise -// record on every flip, the record is materialized lazily on first -// observation and dropped once settled; flips nobody is waiting on -// allocate nothing. -function transformStreamBackpressureChangePromise(stream) { - const state = stream[kState]; - return (state.backpressureChange ??= PromiseWithResolvers()).promise; -} - +// backpressure next becomes false). Both observers are internal, so the +// promise record is replaced by continuation slots: a parked pull is +// completed by delivering the readable controller's pull-fulfilled step, +// and a parked write by the cached write continuation (see +// transformStreamDefaultSinkWriteAlgorithm). Each is enqueued on the +// shared resolved promise at the exact microtask position the old +// record's reaction would have had. function transformStreamSetBackpressure(stream, backpressure) { const state = stream[kState]; assert(state.backpressure !== backpressure); - const backpressureChange = state.backpressureChange; - if (backpressureChange !== undefined) { - state.backpressureChange = undefined; - backpressureChange.resolve(); - } state.backpressure = backpressure; + if (backpressure) { + if (state.pullPending) { + state.pullPending = false; + // The pull-fulfilled step exists: a pull parked it (see + // transformStreamDefaultSourcePullAlgorithm), and the readable + // controller creates it before invoking the pull algorithm. + PromisePrototypeThen( + kResolvedPromise, + state.readable[kState].controller[kState].pullFulfilled); + } + } else if (state.pendingWrite !== undefined) { + PromisePrototypeThen(kResolvedPromise, state.writeContinuation); + } } function setupTransformStreamDefaultController( @@ -456,6 +476,7 @@ function setupTransformStreamDefaultController( transformAlgorithm, flushAlgorithm, cancelAlgorithm, + performTransformRejected: undefined, }; stream[kState].controller = controller; } @@ -468,7 +489,7 @@ function setupTransformStreamDefaultControllerFromTransformer( const flush = transformer?.flush; const cancel = transformer?.cancel; const transformAlgorithm = transform ? - createPromiseCallback2Params('transformer.transform', transform, transformer) : + createRawCallback2Params('transformer.transform', transform, transformer) : defaultTransformAlgorithm; const flushAlgorithm = flush ? createPromiseCallback1Param('transformer.flush', flush, transformer) : @@ -521,18 +542,40 @@ function transformStreamDefaultControllerError(controller, error) { transformStreamError(controller[kState].stream, error); } -async function transformStreamDefaultControllerPerformTransform(controller, chunk) { +// Mirrors the reference implementation's +// `promiseCall(transformAlgorithm, ...).then(undefined, rejectionSteps)`: +// the returned promise settles one microtask after the (coerced) result +// does, and a rejection errors the transform stream before propagating. +// The raw transform callback plus the shared resolved promise for +// non-thenable results replace the previous async wrapper's two implicit +// promises per chunk. +function transformStreamDefaultControllerPerformTransform(controller, chunk) { + const controllerState = controller[kState]; + const transformAlgorithm = controllerState.transformAlgorithm; + if (transformAlgorithm === undefined) { + // Algorithms were cleared by a concurrent cancel/abort/close. + return kResolvedPromise; + } + let result; try { - const transformAlgorithm = controller[kState].transformAlgorithm; - if (transformAlgorithm === undefined) { - // Algorithms were cleared by a concurrent cancel/abort/close. - return; - } - return await transformAlgorithm(chunk, controller); + result = transformAlgorithm(chunk, controller); } catch (error) { + result = PromiseReject(error); + } + if (result === null || + (typeof result !== 'object' && typeof result !== 'function')) { + result = kResolvedPromise; + } else { + result = PromiseResolve(result); + } + controllerState.performTransformRejected ??= (error) => { transformStreamError(controller[kState].stream, error); throw error; - } + }; + return PromisePrototypeThen( + result, + undefined, + controllerState.performTransformRejected); } function transformStreamDefaultControllerTerminate(controller) { @@ -553,26 +596,42 @@ function transformStreamDefaultControllerTerminate(controller) { } function transformStreamDefaultSinkWriteAlgorithm(stream, chunk) { + const state = stream[kState]; const { writable, controller, - } = stream[kState]; + } = state; assert(writable[kState].state === 'writable'); - if (stream[kState].backpressure) { - const backpressureChange = transformStreamBackpressureChangePromise(stream); - return PromisePrototypeThen( - backpressureChange, - () => { - const { - writable, - } = stream[kState]; - if (writable[kState].state === 'erroring') - throw writable[kState].storedError; - assert(writable[kState].state === 'writable'); - return transformStreamDefaultControllerPerformTransform( + if (state.backpressure) { + // Park the chunk and one promise record; the backpressure -> false + // flip delivers the cached continuation (see + // transformStreamSetBackpressure) at the same microtask position as + // the old [[backpressureChangePromise]] reaction. The continuation + // resolves the sink promise with the perform-transform promise, so + // adoption reproduces the old derived-chain settle depth exactly. + // The writable dispatches a single write at a time, so one pending + // slot suffices. + assert(state.pendingWrite === undefined); + const pendingWrite = PromiseWithResolvers(); + state.pendingWrite = pendingWrite; + state.pendingWriteChunk = chunk; + state.writeContinuation ??= () => { + const pending = state.pendingWrite; + const pendingChunk = state.pendingWriteChunk; + state.pendingWrite = undefined; + state.pendingWriteChunk = undefined; + const writableState = state.writable[kState]; + if (writableState.state === 'erroring') { + pending.reject(writableState.storedError); + return; + } + assert(writableState.state === 'writable'); + pending.resolve( + transformStreamDefaultControllerPerformTransform( controller, - chunk); - }); + pendingChunk)); + }; + return pendingWrite.promise; } return transformStreamDefaultControllerPerformTransform(controller, chunk); } @@ -642,9 +701,15 @@ function transformStreamDefaultSinkCloseAlgorithm(stream) { } function transformStreamDefaultSourcePullAlgorithm(stream) { - assert(stream[kState].backpressure); + const state = stream[kState]; + assert(state.backpressure); transformStreamSetBackpressure(stream, false); - return transformStreamBackpressureChangePromise(stream); + // Park the pull: the next backpressure -> true flip delivers the + // pull-fulfilled step (see transformStreamSetBackpressure). The old + // [[backpressureChangePromise]] this replaces was only ever resolved, + // so the parked pull needs no rejection delivery. + state.pullPending = true; + return kParkedAlgorithmResult; } function transformStreamDefaultSourceCancelAlgorithm(stream, reason) { diff --git a/lib/internal/webstreams/util.js b/lib/internal/webstreams/util.js index 8bc4c02be31e..9a93a2b17d41 100644 --- a/lib/internal/webstreams/util.js +++ b/lib/internal/webstreams/util.js @@ -338,6 +338,48 @@ function createPromiseCallbackNoParams(name, fn, thisArg) { return async () => FunctionPrototypeCall(fn, thisArg); } +// Raw variants that skip the async wrapper's implicit result promise. +// Consumers of a raw callback invoke it inside try/catch and route the +// result through thenAlgorithmResult() below. +function createRawCallback1Param(name, fn, thisArg) { + validateFunction(fn, name); + return (arg) => FunctionPrototypeCall(fn, thisArg, arg); +} + +function createRawCallback2Params(name, fn, thisArg) { + validateFunction(fn, name); + return (arg1, arg2) => FunctionPrototypeCall(fn, thisArg, arg1, arg2); +} + +// A single shared, forever-resolved promise used to enqueue a reaction at +// the next microtask checkpoint without allocating a fresh promise. +const kResolvedPromise = PromiseResolve(); + +// Returned by an internal algorithm to signal that it parked the +// operation and takes responsibility for delivering the fulfilled (or +// rejected) continuation itself later, instead of settling a promise +// (see the transform stream source pull algorithm). +const kParkedAlgorithmResult = Symbol('kParkedAlgorithmResult'); + +// Wires the (possibly non-thenable) result of an underlying algorithm +// callback to its fulfilled/rejected continuations. A non-thenable result +// means fulfillment is guaranteed and no then() lookup is observable, so +// the fulfillment step is enqueued directly at the exact microtask +// position the coerced promise's reaction would have had, skipping the +// per-chunk promise allocation. For thenable results PromiseResolve() +// matches the spec's "a promise resolved with" conversion (identity for +// native promises). +function thenAlgorithmResult(result, onFulfilled, onRejected) { + if (result === kParkedAlgorithmResult) + return; + if (result === null || + (typeof result !== 'object' && typeof result !== 'function')) { + PromisePrototypeThen(kResolvedPromise, onFulfilled); + } else { + PromisePrototypeThen(PromiseResolve(result), onFulfilled, onRejected); + } +} + function createPromiseCallback1Param(name, fn, thisArg) { validateFunction(fn, name); return async (arg) => FunctionPrototypeCall(fn, thisArg, arg); @@ -384,14 +426,14 @@ function setPromiseHandled(promise) { async function nonOpFlush() {} -function nonOpStart() {} - -async function nonOpPull() {} +// Shared non-op for the start/pull/write algorithm callbacks, which all +// follow the raw-callback contract (see createRawCallback*): the +// non-thenable return takes the allocation-free fast path in +// thenAlgorithmResult(). +function nonOpCallback() {} async function nonOpCancel() {} -async function nonOpWrite() {} - let transfer; function lazyTransfer() { if (transfer === undefined) @@ -411,6 +453,8 @@ module.exports = { createPromiseCallbackNoParams, createPromiseCallback1Param, createPromiseCallback2Params, + createRawCallback1Param, + createRawCallback2Params, customInspect, defaultSizeAlgorithm, dequeueValue, @@ -421,18 +465,20 @@ module.exports = { isBrandCheck, isPromisePending, kEmptyQueue, + kParkedAlgorithmResult, + kResolvedPromise, kState, kType, lazyTransfer, materializeQueue, + nonOpCallback, nonOpCancel, nonOpFlush, - nonOpPull, - nonOpStart, - nonOpWrite, + peekQueueValue, rejectedHandledRecord, resetQueue, resolvedRecord, setPromiseHandled, + thenAlgorithmResult, }; diff --git a/lib/internal/webstreams/writablestream.js b/lib/internal/webstreams/writablestream.js index 87e3bcaa2850..1e9ca02cfe96 100644 --- a/lib/internal/webstreams/writablestream.js +++ b/lib/internal/webstreams/writablestream.js @@ -56,7 +56,7 @@ const { Queue, createPromiseCallbackNoParams, createPromiseCallback1Param, - createPromiseCallback2Params, + createRawCallback2Params, customInspect, defaultSizeAlgorithm, dequeueValue, @@ -70,14 +70,14 @@ const { kState, kType, lazyTransfer, + nonOpCallback, nonOpCancel, - nonOpStart, - nonOpWrite, peekQueueValue, rejectedHandledRecord, resetQueue, resolvedRecord, setPromiseHandled, + thenAlgorithmResult, } = require('internal/webstreams/util'); const { @@ -701,15 +701,18 @@ function writerReadyPromise(writer) { } function writableStreamAbort(stream, reason) { - const { - state, - controller, - } = stream[kState]; + const { controller } = stream[kState]; + + let state = stream[kState].state; if (state === 'closed' || state === 'errored') return PromiseResolve(); controller[kState].abortController.abort(reason); + state = stream[kState].state; + if (state === 'closed' || state === 'errored') + return PromiseResolve(); + if (stream[kState].pendingAbortRequest.abort.promise !== undefined) return stream[kState].pendingAbortRequest.abort.promise; @@ -766,7 +769,12 @@ function writableStreamUpdateBackpressure(controller, streamState) { const backpressure = controllerState.highWaterMark - controllerState.queueTotalSize <= 0; const writer = streamState.writer; - if (writer !== undefined && streamState.backpressure !== backpressure) { + const changed = streamState.backpressure !== backpressure; + // The state field is published before the ready record is resolved so + // that a ready resolve hook (pipeTo's pump continuation) observes the + // new value. + streamState.backpressure = backpressure; + if (writer !== undefined && changed) { if (backpressure) { // The spec replaces [[readyPromise]] with a fresh pending promise; // dropping the cache lets the next observation derive it. @@ -775,7 +783,6 @@ function writableStreamUpdateBackpressure(controller, streamState) { writer[kState].ready?.resolve(); } } - streamState.backpressure = backpressure; } function writableStreamStartErroring(stream, reason) { @@ -807,7 +814,7 @@ function writableStreamRejectCloseAndClosedPromiseIfNeeded(stream) { } const closedPromiseCache = stream[kState].closedPromise; - if (closedPromiseCache !== undefined) { + if (closedPromiseCache !== undefined && isPromisePending(closedPromiseCache.promise)) { setPromiseHandled(closedPromiseCache.promise); closedPromiseCache.reject(stream[kState].storedError); } @@ -817,7 +824,7 @@ function writableStreamRejectCloseAndClosedPromiseIfNeeded(stream) { } = stream[kState]; if (writer !== undefined) { const closeCache = writer[kState].close; - if (closeCache !== undefined) { + if (closeCache !== undefined && isPromisePending(closeCache.promise)) { setPromiseHandled(closeCache.promise); closeCache.reject(stream[kState].storedError); } @@ -1194,8 +1201,18 @@ function writableStreamDefaultControllerProcessWrite(controller, chunk) { }; } - PromisePrototypeThen( - writeAlgorithm(chunk, controller), + // The write algorithm may be a raw callback (a wrapped user sink.write + // returns its result uncoerced; a synchronous throw surfaces here) or an + // internal algorithm that always returns a promise; thenAlgorithmResult + // handles both. + let result; + try { + result = writeAlgorithm(chunk, controller); + } catch (error) { + result = PromiseReject(error); + } + thenAlgorithmResult( + result, controller[kState].writeFulfilled, controller[kState].writeRejected); } @@ -1318,10 +1335,10 @@ function setupWritableStreamDefaultControllerFromSink( const abort = sink?.abort; const startAlgorithm = start ? FunctionPrototypeBind(start, sink, controller) : - nonOpStart; + nonOpCallback; const writeAlgorithm = write ? - createPromiseCallback2Params('sink.write', write, sink) : - nonOpWrite; + createRawCallback2Params('sink.write', write, sink) : + nonOpCallback; const closeAlgorithm = close ? createPromiseCallbackNoParams('sink.close', close, sink) : nonOpCancel; diff --git a/lib/net.js b/lib/net.js index 55fc6ea843ce..36e1531a780c 100644 --- a/lib/net.js +++ b/lib/net.js @@ -736,7 +736,9 @@ ObjectSetPrototypeOf(Socket, stream.Duplex); // Refresh existing timeouts. Socket.prototype._unrefTimer = function _unrefTimer() { - for (let s = this; s !== null; s = s._parent) { + // `_parent` may be null; we use a loose `!= null` check in case external + // code sets it to undefined. + for (let s = this; s != null; s = s._parent) { if (s[kTimeout]) s[kTimeout].refresh(); } @@ -1097,7 +1099,9 @@ Socket.prototype._destroy = function(exception, cb) { this.connecting = false; - for (let s = this; s !== null; s = s._parent) { + // `_parent` may be null; we use a loose `!= null` check in case external + // code sets it to undefined. + for (let s = this; s != null; s = s._parent) { clearTimeout(s[kTimeout]); } diff --git a/lib/tls.js b/lib/tls.js index 296f6189da17..a1d978c50f27 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -70,7 +70,7 @@ const { canonicalizeIP } = internalBinding('cares_wrap'); const tlsCommon = require('internal/tls/common'); const tlsWrap = require('internal/tls/wrap'); const { domainToASCII } = require('internal/url'); -const { validateString } = require('internal/validators'); +const { validateArray, validateString } = require('internal/validators'); const { namespace: { @@ -206,9 +206,7 @@ function getCACertificates(type = 'default') { exports.getCACertificates = getCACertificates; function setDefaultCACertificates(certs) { - if (!ArrayIsArray(certs)) { - throw new ERR_INVALID_ARG_TYPE('certs', 'Array', certs); - } + validateArray(certs, 'certs'); // Verify that all elements in the array are strings for (let i = 0; i < certs.length; i++) { @@ -253,6 +251,10 @@ function convertProtocols(protocols) { const lens = new Array(protocols.length); const buff = Buffer.allocUnsafe(protocols.reduce((p, c, i) => { const len = Buffer.byteLength(c); + if (len === 0) { + throw new ERR_INVALID_ARG_VALUE(`protocols[${i}]`, c, + 'must be a non-empty string'); + } if (len > 255) { throw new ERR_OUT_OF_RANGE('The byte length of the protocol at index ' + `${i} exceeds the maximum length.`, '<= 255', len, true); @@ -271,18 +273,41 @@ function convertProtocols(protocols) { return buff; } +function validateALPNBuffer(buffer) { + // Wire format: sequence of where len is 1 byte (1-255) and + // exactly len bytes follow, no trailing bytes, no zero-length entries. + // Empty buffer is allowed and means skip ALPN (same as []). + let offset = 0; + while (offset < buffer.length) { + const len = buffer[offset]; + if (len === 0) { + throw new ERR_INVALID_ARG_VALUE('ALPNProtocols', buffer, + 'must not contain zero-length protocol'); + } + if (offset + 1 + len > buffer.length) { + throw new ERR_INVALID_ARG_VALUE('ALPNProtocols', buffer, + 'contains truncated protocol'); + } + offset += 1 + len; + } +} + exports.convertALPNProtocols = function convertALPNProtocols(protocols, out) { // If protocols is Array - translate it into buffer if (ArrayIsArray(protocols)) { out.ALPNProtocols = convertProtocols(protocols); } else if (isUint8Array(protocols)) { // Copy new buffer not to be modified by user. - out.ALPNProtocols = Buffer.from(protocols); + const buf = Buffer.from(protocols); + validateALPNBuffer(buf); + out.ALPNProtocols = buf; } else if (isArrayBufferView(protocols)) { - out.ALPNProtocols = Buffer.from(protocols.buffer.slice( + const buf = Buffer.from(protocols.buffer.slice( protocols.byteOffset, protocols.byteOffset + protocols.byteLength, )); + validateALPNBuffer(buf); + out.ALPNProtocols = buf; } }; diff --git a/lib/tty.js b/lib/tty.js index b1a2d3e7a9bc..309930f67c35 100644 --- a/lib/tty.js +++ b/lib/tty.js @@ -27,10 +27,17 @@ const { } = primordials; const net = require('net'); -const { TTY, isTTY } = internalBinding('tty_wrap'); +const { + TTY, + UV_TTY_MODE_IO, + UV_TTY_MODE_NORMAL, + UV_TTY_MODE_RAW_VT, + isTTY, +} = internalBinding('tty_wrap'); const { ErrnoException, codes: { + ERR_INVALID_ARG_VALUE, ERR_INVALID_FD, ERR_TTY_INIT_FAILED, }, @@ -68,20 +75,36 @@ function ReadStream(fd, options) { }); this.isRaw = false; + this.rawMode = false; this.isTTY = true; } ObjectSetPrototypeOf(ReadStream.prototype, net.Socket.prototype); ObjectSetPrototypeOf(ReadStream, net.Socket); -ReadStream.prototype.setRawMode = function(flag) { - flag = !!flag; - const err = this._handle?.setRawMode(flag); +ReadStream.prototype.setRawMode = function(mode) { + let rawMode; + if (mode === 'io' || mode === 'raw') { + rawMode = mode; + } else if (typeof mode === 'string') { + throw new ERR_INVALID_ARG_VALUE( + 'mode', mode, "must be true, false, 'raw', or 'io'"); + } else { + rawMode = mode ? 'raw' : false; + } + let ttyMode = UV_TTY_MODE_NORMAL; + if (rawMode === 'io') { + ttyMode = UV_TTY_MODE_IO; + } else if (rawMode === 'raw') { + ttyMode = UV_TTY_MODE_RAW_VT; + } + const err = this._handle?.setRawMode(ttyMode); if (err) { this.emit('error', new ErrnoException(err, 'setRawMode')); return this; } - this.isRaw = flag; + this.isRaw = rawMode !== false; + this.rawMode = rawMode; return this; }; diff --git a/lib/util.js b/lib/util.js index a00def99a1e4..e5a3aea4a9e1 100644 --- a/lib/util.js +++ b/lib/util.js @@ -514,8 +514,7 @@ function reconstructCallSite(callSite) { if (!entry?.originalSource) return; return { __proto__: null, - // If the name is not found, it is an empty string to match the behavior of `util.getCallSite()` - functionName: entry.name ?? '', + functionName: entry.name || callSite.functionName, scriptName: entry.originalSource, lineNumber: entry.originalLine + 1, column: entry.originalColumn + 1, diff --git a/node.gyp b/node.gyp index c58f4812e2e1..988838e85858 100644 --- a/node.gyp +++ b/node.gyp @@ -172,6 +172,7 @@ 'src/node_zlib.cc', 'src/path.cc', 'src/permission/child_process_permission.cc', + 'src/permission/openssl_store_permission.cc', 'src/permission/fs_permission.cc', 'src/permission/inspector_permission.cc', 'src/permission/permission.cc', @@ -308,6 +309,7 @@ 'src/node_worker.h', 'src/path.h', 'src/permission/child_process_permission.h', + 'src/permission/openssl_store_permission.h', 'src/permission/fs_permission.h', 'src/permission/inspector_permission.h', 'src/permission/permission.h', @@ -950,7 +952,7 @@ ], }, 'conditions': [ - ['openssl_is_fips!=""', { + ['openssl_is_fips=="true"', { 'variables': { 'mkssldef_flags': ['-DOPENSSL_FIPS'] }, }], ], diff --git a/onboarding.md b/onboarding.md index bc690190b490..74c114526044 100644 --- a/onboarding.md +++ b/onboarding.md @@ -283,8 +283,8 @@ needs to be pointed out separately during the onboarding. including accommodations, transportation, and visa fees (even in case the visa is denied) if needed. Check out the [summit](https://github.com/nodejs/summit) repository for details. -* If you are interested in helping to fix coverity reports consider requesting - access to the projects coverity project as outlined in [static-analysis][]. +* If you are interested in helping to fix coverity reports, consider requesting + access to the project's coverity project as outlined in [static-analysis][]. * If you are interested in helping out with CI reliability, check out the [reliability repository][] and [guide on how to deal with CI flakes][]. When fixing a flaky test, it is recommended to run [`node-stress-single-test`][] diff --git a/pgo.ps1 b/pgo.ps1 new file mode 100644 index 000000000000..39f5352463e3 --- /dev/null +++ b/pgo.ps1 @@ -0,0 +1,162 @@ +# PGO (Profile-Guided Optimization) training script for Node.js (Clang / LLVM) +# +# Runs PGO training workloads against an instrumented Node.js binary +# (Release\node.exe) and merges the resulting .profraw files into +# node.profdata for use with -fprofile-use. +# +# Usage (from a VS Developer Command Prompt): +# .\pgo.ps1 # Run workloads (15s each) and merge +# .\pgo.ps1 -Duration 30 # Run workloads (30s each) and merge +# +# Prerequisites: +# - Release\node.exe must be an instrumented build (built with pgo-generate) +# - llvm-profdata must be available (shipped with VS LLVM toolset) +# +# Output: +# - node.profdata in the repo root (ready for vcbuild.bat pgo-use) + +param( + [int]$Duration = 15 +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +# --------------------------------------------------------------------------- +# Locate llvm-profdata shipped with Visual Studio's LLVM toolset +# --------------------------------------------------------------------------- + +function Find-LlvmProfdata { + # vcbuild.bat uses %VCINSTALLDIR%\Tools\Llvm\x64\bin for clang.exe - same spot for profdata + $vcInstallDir = $env:VCINSTALLDIR + + if ($vcInstallDir) { + $candidate = Join-Path $vcInstallDir "Tools\Llvm\x64\bin\llvm-profdata.exe" + if (Test-Path $candidate) { + return $candidate + } + } + + # Fallback: try VS 2022 / 2026 default install locations + $vsPaths = @( + "${env:ProgramFiles}\Microsoft Visual Studio\2026\Enterprise\VC\Tools\Llvm\x64\bin", + "${env:ProgramFiles}\Microsoft Visual Studio\2026\Community\VC\Tools\Llvm\x64\bin", + "${env:ProgramFiles}\Microsoft Visual Studio\2022\Enterprise\VC\Tools\Llvm\x64\bin", + "${env:ProgramFiles}\Microsoft Visual Studio\2022\Community\VC\Tools\Llvm\x64\bin" + ) + foreach ($dir in $vsPaths) { + $candidate = Join-Path $dir "llvm-profdata.exe" + if (Test-Path $candidate) { + return $candidate + } + } + + # Last resort: PATH + $fromPath = Get-Command llvm-profdata -ErrorAction SilentlyContinue + if ($fromPath) { + return $fromPath.Source + } + + return $null +} + +# --------------------------------------------------------------------------- +# Validate prerequisites +# --------------------------------------------------------------------------- + +$instrumentedNode = Join-Path $PSScriptRoot "Release\node.exe" +if (-not (Test-Path $instrumentedNode)) { + Write-Error "Instrumented binary not found: $instrumentedNode`nBuild with: vcbuild.bat pgo-generate" + exit 1 +} + +$pgoRunAll = Join-Path $PSScriptRoot "tools\pgo\pgo-run-all.js" +if (-not (Test-Path $pgoRunAll)) { + Write-Error "PGO training script not found: $pgoRunAll" + exit 1 +} + +$llvmProfdata = Find-LlvmProfdata +if (-not $llvmProfdata) { + Write-Error "llvm-profdata not found. Install the LLVM toolset via Visual Studio Installer." + exit 1 +} + +# --------------------------------------------------------------------------- +# STEP 1 – Run workloads with the instrumented binary to collect profiles +# --------------------------------------------------------------------------- + +Write-Host "`n=== STEP 1: Collect PGO profiles ===" -ForegroundColor Cyan + +# Directory that will receive .profraw files from the instrumented binary. +# %p (PID) and %m (module hash) keep concurrent/fork'd processes from colliding. +$profileDir = Join-Path $PSScriptRoot "pgo-profiles" + +if (Test-Path $profileDir) { + Remove-Item -Recurse -Force $profileDir +} +New-Item -ItemType Directory -Path $profileDir | Out-Null + +$env:LLVM_PROFILE_FILE = Join-Path $profileDir "node-%p-%m.profraw" + +Write-Host "Instrumented node : $instrumentedNode" +Write-Host "Profile output : $($env:LLVM_PROFILE_FILE)" +Write-Host "Duration per script: ${Duration}s" +Write-Host "" + +$sw = [System.Diagnostics.Stopwatch]::StartNew() +$proc = Start-Process ` + -FilePath $instrumentedNode ` + -ArgumentList "`"$pgoRunAll`" --verbose --duration=$Duration" ` + -Wait -PassThru -NoNewWindow +$sw.Stop() +Write-Host ("PGO training completed in {0}m {1}s (exit code: {2})" -f ` + $sw.Elapsed.Minutes, $sw.Elapsed.Seconds, $proc.ExitCode) +if ($proc.ExitCode -ne 0) { + Write-Warning "PGO training exited with code $($proc.ExitCode) - continuing with merge" +} + +# Remove the env var so subsequent builds are not affected +Remove-Item Env:\LLVM_PROFILE_FILE -ErrorAction SilentlyContinue + +# --------------------------------------------------------------------------- +# STEP 2 – Merge .profraw files -> node.profdata +# --------------------------------------------------------------------------- + +Write-Host "`n=== STEP 2: Merge profile data ===" -ForegroundColor Cyan + +Write-Host "Using llvm-profdata: $llvmProfdata" + +$profrawFiles = Get-ChildItem -Path $profileDir -Filter "*.profraw" -ErrorAction SilentlyContinue +if ($profrawFiles.Count -eq 0) { + Write-Error "No .profraw files found in '$profileDir'. The instrumented binary may not have generated profile data." + exit 1 +} + +$totalSize = ($profrawFiles | Measure-Object -Property Length -Sum).Sum +$totalSizeMB = [math]::Round($totalSize / 1MB, 1) +Write-Host "Found $($profrawFiles.Count) .profraw file(s), ${totalSizeMB} MB total" + +$profdata = Join-Path $PSScriptRoot "node.profdata" +$mergeArgs = @("merge", "--output=$profdata") + ($profrawFiles | Select-Object -ExpandProperty FullName) + +$mergeStopwatch = [System.Diagnostics.Stopwatch]::StartNew() +& $llvmProfdata @mergeArgs +$mergeExitCode = $LASTEXITCODE +$mergeStopwatch.Stop() + +if ($mergeExitCode -ne 0) { + Write-Error "llvm-profdata merge failed (exit code $mergeExitCode)" + exit $mergeExitCode +} + +$profdataSize = [math]::Round((Get-Item $profdata).Length / 1MB, 1) +Write-Host "Merge completed in $([math]::Round($mergeStopwatch.Elapsed.TotalSeconds, 1))s" + +# Clean up .profraw files now that they've been merged +Remove-Item -Recurse -Force $profileDir +Write-Host "Removed $($profrawFiles.Count) .profraw file(s) (${totalSizeMB} MB reclaimed)" + +Write-Host "`n=== PGO training complete ===" -ForegroundColor Green +Write-Host " Profile data: $profdata (${profdataSize} MB)" +Write-Host " Next step: vcbuild.bat pgo-use" diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index acacc7d0bc05..a61a8c623fad 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -2137,13 +2137,13 @@ void SetServers(const FunctionCallbackInfo& args) { if (!elm->Get(env->context(), 1).ToLocal(&ipValue)) return; if (!elm->Get(env->context(), 2).ToLocal(&portValue)) return; - CHECK(familyValue->Int32Value(env->context()).FromJust()); + CHECK(familyValue->IsInt32()); CHECK(ipValue->IsString()); - CHECK(portValue->Int32Value(env->context()).FromJust()); + CHECK(portValue->IsInt32()); - int fam = familyValue->Int32Value(env->context()).FromJust(); + int32_t fam = familyValue.As()->Value(); node::Utf8Value ip(env->isolate(), ipValue); - int port = portValue->Int32Value(env->context()).FromJust(); + int32_t port = portValue.As()->Value(); ares_addr_port_node* cur = &servers[i]; diff --git a/src/crypto/crypto_cipher.cc b/src/crypto/crypto_cipher.cc index 56c35246aada..0df4daa25023 100644 --- a/src/crypto/crypto_cipher.cc +++ b/src/crypto/crypto_cipher.cc @@ -870,7 +870,11 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); unsigned int offset = 0; - auto data = KeyObjectData::GetPublicOrPrivateKeyFromJs(args, &offset); + // TODO(panva): Use GetPrivateKeyFromJs() for private operations, then + // remove allow_private_key_store and URL handling from + // GetPublicOrPrivateKeyFromJs(). + auto data = KeyObjectData::GetPublicOrPrivateKeyFromJs( + args, &offset, operation == PublicKeyCipher::kPrivate); if (!data) return; const auto& pkey = data.GetAsymmetricKey(); if (!pkey) return; diff --git a/src/crypto/crypto_context.cc b/src/crypto/crypto_context.cc index 05fc2a00b362..af8d52fbe699 100644 --- a/src/crypto/crypto_context.cc +++ b/src/crypto/crypto_context.cc @@ -2247,12 +2247,9 @@ void SecureContext::GetCertificateCompressionAlgorithms( Environment* env = Environment::GetCurrent(args); LocalVector algs(env->isolate()); #ifdef NODE_OPENSSL_HAS_CERT_COMP - if (BIO_f_zlib() != nullptr) - algs.push_back(FIXED_ONE_BYTE_STRING(env->isolate(), "zlib")); - if (BIO_f_brotli() != nullptr) - algs.push_back(FIXED_ONE_BYTE_STRING(env->isolate(), "brotli")); - if (BIO_f_zstd() != nullptr) - algs.push_back(FIXED_ONE_BYTE_STRING(env->isolate(), "zstd")); + if (BIO_f_zlib() != nullptr) algs.push_back(env->zlib_string()); + if (BIO_f_brotli() != nullptr) algs.push_back(env->brotli_string()); + if (BIO_f_zstd() != nullptr) algs.push_back(env->zstd_string()); #endif args.GetReturnValue().Set( Array::New(env->isolate(), algs.data(), algs.size())); diff --git a/src/crypto/crypto_dh.cc b/src/crypto/crypto_dh.cc index 40f21fcc3437..6418283e7e4e 100644 --- a/src/crypto/crypto_dh.cc +++ b/src/crypto/crypto_dh.cc @@ -319,12 +319,10 @@ void ComputeSecret(const FunctionCallbackInfo& args) { case DHPointer::CheckPublicKeyResult::CHECK_FAILED: return THROW_ERR_CRYPTO_INVALID_KEYTYPE(env, "Unspecified validation error"); -#ifndef OPENSSL_IS_BORINGSSL case DHPointer::CheckPublicKeyResult::TOO_SMALL: return THROW_ERR_CRYPTO_INVALID_KEYLEN(env, "Supplied key is too small"); case DHPointer::CheckPublicKeyResult::TOO_LARGE: return THROW_ERR_CRYPTO_INVALID_KEYLEN(env, "Supplied key is too large"); -#endif case DHPointer::CheckPublicKeyResult::INVALID: return THROW_ERR_CRYPTO_INVALID_KEYTYPE(env, "Supplied key is invalid"); case DHPointer::CheckPublicKeyResult::NONE: diff --git a/src/crypto/crypto_ec.cc b/src/crypto/crypto_ec.cc index e6684c4be139..807428d69110 100644 --- a/src/crypto/crypto_ec.cc +++ b/src/crypto/crypto_ec.cc @@ -612,13 +612,15 @@ bool ExportJWKEcKey(Environment* env, THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK EC key"); return false; } + // A provider-backed key need not expose its public point. + if (ec.getPublicKey() == nullptr) return false; const auto pub = ec.getPublicKey(); const auto group = ec.getGroup(); int degree_bits = EC_GROUP_get_degree(group); int degree_bytes = - (degree_bits / CHAR_BIT) + (7 + (degree_bits % CHAR_BIT)) / 8; + (degree_bits / CHAR_BIT) + (7 + (degree_bits % CHAR_BIT)) / 8; auto x = BignumPointer::New(); auto y = BignumPointer::New(); @@ -655,16 +657,16 @@ bool ExportJWKEcKey(Environment* env, const int nid = EC_GROUP_get_curve_name(group); switch (nid) { case NID_X9_62_prime256v1: - crv_name = FIXED_ONE_BYTE_STRING(env->isolate(), "P-256"); + crv_name = env->p256_string(); break; case NID_secp256k1: - crv_name = FIXED_ONE_BYTE_STRING(env->isolate(), "secp256k1"); + crv_name = env->secp256k1_string(); break; case NID_secp384r1: - crv_name = FIXED_ONE_BYTE_STRING(env->isolate(), "P-384"); + crv_name = env->p384_string(); break; case NID_secp521r1: - crv_name = FIXED_ONE_BYTE_STRING(env->isolate(), "P-521"); + crv_name = env->p521_string(); break; default: { THROW_ERR_CRYPTO_JWK_UNSUPPORTED_CURVE( @@ -680,6 +682,7 @@ bool ExportJWKEcKey(Environment* env, if (key.GetKeyType() == kKeyTypePrivate) { auto pvt = ec.getPrivateKey(); + if (pvt == nullptr) return false; return SetEncodedValue(env, target, env->jwk_d_string(), pvt, degree_bytes) .IsJust(); } diff --git a/src/crypto/crypto_keys.cc b/src/crypto/crypto_keys.cc index ed418ce94029..c501a64ce8fb 100644 --- a/src/crypto/crypto_keys.cc +++ b/src/crypto/crypto_keys.cc @@ -12,6 +12,7 @@ #include "memory_tracker-inl.h" #include "node.h" #include "node_buffer.h" +#include "permission/permission.h" #include "string_bytes.h" #include "threadpoolwork-inl.h" #include "util-inl.h" @@ -391,6 +392,12 @@ bool KeyObjectData::ToEncodedPublicKey( THROW_ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(env); return false; } + // A provider-backed key need not expose its public point. + if (ec_key.getPublicKey() == nullptr) { + THROW_ERR_CRYPTO_OPERATION_FAILED(env, + "Failed to export EC public key"); + return false; + } auto form = static_cast(config.ec_point_form); const auto group = ec_key.getGroup(); const auto point = ec_key.getPublicKey(); @@ -442,7 +449,8 @@ bool KeyObjectData::ToEncodedPrivateKey( } const BIGNUM* private_key = ec_key.getPrivateKey(); if (private_key == nullptr) { - THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Failed to get EC private key"); + THROW_ERR_CRYPTO_OPERATION_FAILED(env, + "Failed to export EC private key"); return false; } const auto group = ec_key.getGroup(); @@ -765,7 +773,103 @@ KeyObjectData KeyObjectData::GetPrivateKeyFromJs( bool allow_key_object) { Environment* env = Environment::GetCurrent(args); - // JWK format: data is a JS Object (not buffer), format int is JWK. + // Store descriptor: data is a { uri, properties } object, format int is + // STORE, and the passphrase slot carries an optional passphrase/PIN. + if (args[*offset]->IsObject() && !IsAnyBufferSource(args[*offset]) && + args[*offset + 1]->IsInt32() && + static_cast( + args[*offset + 1].As()->Value()) == + EVPKeyPointer::PKFormatType::STORE) { + Local store = args[*offset].As(); + Local uri_value; + if (!store + ->Get(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), "uri")) + .ToLocal(&uri_value)) { + return {}; + } + CHECK(uri_value->IsString()); + Utf8Value uri(env->isolate(), uri_value); + + Local properties_value; + if (!store + ->Get(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "properties")) + .ToLocal(&properties_value)) { + return {}; + } + std::string properties_storage; + std::optional properties; + if (properties_value->IsString()) { + Utf8Value properties_string(env->isolate(), properties_value); + std::string_view properties_view = properties_string.ToStringView(); + properties_storage.assign(properties_view.data(), properties_view.size()); + properties = std::string_view(properties_storage); + } else { + CHECK(properties_value->IsNullOrUndefined()); + } + + // OpenSSLStore is a global permission. URIs passed to STORE loaders can + // contain credentials, so they must not be exposed through permission + // errors or diagnostics. + THROW_IF_INSUFFICIENT_PERMISSIONS( + env, permission::PermissionScope::kOpenSSLStore, "", KeyObjectData()); + + std::optional> passphrase_content; + std::optional> passphrase; + if (IsAnyBufferSource(args[*offset + 3])) { + passphrase_content.emplace(args[*offset + 3]); + if (!passphrase_content->CheckSizeInt32()) [[unlikely]] { + THROW_ERR_OUT_OF_RANGE(env, "passphrase is too big"); + return {}; + } + passphrase = ncrypto::Buffer{ + .data = passphrase_content->data(), + .len = passphrase_content->size(), + }; + } else { + CHECK(args[*offset + 3]->IsNullOrUndefined()); + } + + *offset += 5; + EVPKeyPointer::StorePrivateKeyConfig config{ + .uri = uri.ToStringView(), + .properties = properties, + .passphrase = passphrase, + }; + auto res = EVPKeyPointer::TryLoadPrivateKeyFromStore(config); + if (res) { + return CreateAsymmetric(KeyType::kKeyTypePrivate, std::move(res.value)); + } + switch (res.error.value()) { + case EVPKeyPointer::PKParseError::NEED_PASSPHRASE: + ERR_clear_error(); + THROW_ERR_MISSING_PASSPHRASE(env, + "Passphrase required for encrypted key"); + break; + case EVPKeyPointer::PKParseError::NOT_RECOGNIZED: + ERR_clear_error(); + THROW_ERR_CRYPTO_OPERATION_FAILED( + env, "No private key found through the OpenSSL STORE loader"); + break; + default: { + static constexpr const char* msg = + "Failed to load private key through an OpenSSL STORE loader"; + // A loader may report a failure without leaving anything in the error + // queue, in which case ThrowCryptoError() would produce a bare Error + // carrying no code at all. + if (res.openssl_error.value_or(0) == 0) { + THROW_ERR_CRYPTO_OPERATION_FAILED(env, msg); + } else { + ThrowCryptoError(env, res.openssl_error.value(), msg); + } + break; + } + } + return {}; + } + + // Object formats: data is a JS Object (not buffer), format int determines + // whether this is a JWK or an OpenSSL STORE loader descriptor. if (args[*offset]->IsObject() && !IsAnyBufferSource(args[*offset]) && args[*offset + 1]->IsInt32()) { auto format = static_cast( @@ -819,7 +923,9 @@ KeyObjectData KeyObjectData::GetPrivateKeyFromJs( } KeyObjectData KeyObjectData::GetPublicOrPrivateKeyFromJs( - const FunctionCallbackInfo& args, unsigned int* offset) { + const FunctionCallbackInfo& args, + unsigned int* offset, + bool allow_private_key_store) { Environment* env = Environment::GetCurrent(args); // JWK format: data is a JS Object (not buffer), format int is JWK. @@ -832,6 +938,15 @@ KeyObjectData KeyObjectData::GetPublicOrPrivateKeyFromJs( *offset += 5; return data; } + if (format == EVPKeyPointer::PKFormatType::STORE) { + if (allow_private_key_store) { + return GetPrivateKeyFromJs(args, offset, false); + } + THROW_ERR_INVALID_ARG_VALUE( + env, + "URLs for OpenSSL STORE loaders are only accepted for private keys"); + return {}; + } } if (args[*offset]->IsString() || IsAnyBufferSource(args[*offset])) { @@ -1468,8 +1583,11 @@ void KeyObjectHandle::ExportECPublicRaw( } ECKeyPointer ec_key(m_pkey); - if (!ec_key) { - return THROW_ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(env); + if (!ec_key) return THROW_ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(env); + // A provider-backed key need not expose its public point. + if (ec_key.getPublicKey() == nullptr) { + return THROW_ERR_CRYPTO_OPERATION_FAILED(env, + "Failed to export EC public key"); } CHECK(args[0]->IsInt32()); @@ -1501,14 +1619,12 @@ void KeyObjectHandle::ExportECPrivateRaw( } ECKeyPointer ec_key(m_pkey); - if (!ec_key) { - return THROW_ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(env); - } + if (!ec_key) return THROW_ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(env); const BIGNUM* private_key = ec_key.getPrivateKey(); if (private_key == nullptr) { return THROW_ERR_CRYPTO_OPERATION_FAILED(env, - "Failed to get EC private key"); + "Failed to export EC private key"); } const auto group = ec_key.getGroup(); @@ -1568,6 +1684,8 @@ void KeyObjectHandle::ExportJWK( if (ExportJWKInner(env, key->Data(), args[0], args[1]->IsTrue())) { args.GetReturnValue().Set(args[0]); + } else if (!env->isolate()->HasPendingException()) { + THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Failed to export JWK"); } } @@ -1679,8 +1797,7 @@ BaseObjectPtr NativeKeyObject::KeyObjectTransferData::Deserialize( return {}; Local key_ctor; - Local arg = FIXED_ONE_BYTE_STRING(env->isolate(), - "internal/crypto/keys"); + Local arg = env->internal_crypto_keys_string(); if (env->builtin_module_require() ->Call(context, Null(env->isolate()), 1, &arg) .IsEmpty()) { @@ -1784,7 +1901,7 @@ MaybeLocal NativeCryptoKey::Create(Environment* env, if (!KeyObjectHandle::Create(env, data).ToLocal(&handle)) return {}; if (env->crypto_internal_cryptokey_constructor().IsEmpty()) { - Local arg = FIXED_ONE_BYTE_STRING(isolate, "internal/crypto/keys"); + Local arg = env->internal_crypto_keys_string(); if (env->builtin_module_require() ->Call(context, Null(isolate), 1, &arg) .IsEmpty()) { @@ -1926,7 +2043,6 @@ Maybe NativeCryptoKey::FinalizeTransferRead( } CHECK(bundle_v->IsObject()); Local bundle = bundle_v.As(); - Isolate* isolate = env()->isolate(); Local obj = object(); // The partially-initialized object produced by @@ -1934,23 +2050,21 @@ Maybe NativeCryptoKey::FinalizeTransferRead( CHECK(obj->GetInternalField(kAlgorithmField).As()->IsUndefined()); Local algorithm_v; - if (!bundle->Get(context, FIXED_ONE_BYTE_STRING(isolate, "algorithm")) - .ToLocal(&algorithm_v)) { + if (!bundle->Get(context, env()->algorithm_string()).ToLocal(&algorithm_v)) { return Nothing(); } CHECK(algorithm_v->IsObject()); obj->SetInternalField(kAlgorithmField, algorithm_v); Local usages_v; - if (!bundle->Get(context, FIXED_ONE_BYTE_STRING(isolate, "usages")) - .ToLocal(&usages_v)) { + if (!bundle->Get(context, env()->usages_string()).ToLocal(&usages_v)) { return Nothing(); } CHECK(usages_v->IsUint32()); usages_mask_ = usages_v.As()->Value(); Local extractable_v; - if (!bundle->Get(context, FIXED_ONE_BYTE_STRING(isolate, "extractable")) + if (!bundle->Get(context, env()->extractable_string()) .ToLocal(&extractable_v)) { return Nothing(); } @@ -1963,21 +2077,19 @@ Maybe NativeCryptoKey::FinalizeTransferRead( Maybe NativeCryptoKey::CryptoKeyTransferData::FinalizeTransferWrite( Local context, v8::ValueSerializer* serializer) { Isolate* isolate = Isolate::GetCurrent(); + Environment* env = Environment::GetCurrent(isolate); CHECK(!algorithm_.IsEmpty()); Local bundle = Object::New(isolate); Local algorithm_v = PersistentToLocal::Strong(algorithm_); - if (bundle - ->Set( - context, FIXED_ONE_BYTE_STRING(isolate, "algorithm"), algorithm_v) - .IsNothing() || + if (bundle->Set(context, env->algorithm_string(), algorithm_v).IsNothing() || bundle ->Set(context, - FIXED_ONE_BYTE_STRING(isolate, "usages"), + env->usages_string(), Uint32::NewFromUnsigned(isolate, usages_mask_)) .IsNothing() || bundle ->Set(context, - FIXED_ONE_BYTE_STRING(isolate, "extractable"), + env->extractable_string(), v8::Boolean::New(isolate, extractable_)) .IsNothing()) { return Nothing(); @@ -2003,7 +2115,7 @@ BaseObjectPtr NativeCryptoKey::CryptoKeyTransferData::Deserialize( // Make sure internal/crypto/keys has been loaded so that the // CryptoKey constructor is registered with the Environment. Isolate* isolate = env->isolate(); - Local arg = FIXED_ONE_BYTE_STRING(isolate, "internal/crypto/keys"); + Local arg = env->internal_crypto_keys_string(); if (env->builtin_module_require() ->Call(context, Null(isolate), 1, &arg) .IsEmpty()) { @@ -2065,6 +2177,8 @@ void Initialize(Environment* env, Local target) { static_cast(EVPKeyPointer::PKFormatType::RAW_PRIVATE); constexpr int kKeyFormatRawSeed = static_cast(EVPKeyPointer::PKFormatType::RAW_SEED); + constexpr int kKeyFormatStore = + static_cast(EVPKeyPointer::PKFormatType::STORE); constexpr auto kSigEncDER = DSASigEnc::DER; constexpr auto kSigEncP1363 = DSASigEnc::P1363; @@ -2111,6 +2225,7 @@ void Initialize(Environment* env, Local target) { NODE_DEFINE_CONSTANT(target, kKeyFormatRawPublic); NODE_DEFINE_CONSTANT(target, kKeyFormatRawPrivate); NODE_DEFINE_CONSTANT(target, kKeyFormatRawSeed); + NODE_DEFINE_CONSTANT(target, kKeyFormatStore); NODE_DEFINE_CONSTANT(target, kKeyTypeSecret); NODE_DEFINE_CONSTANT(target, kKeyTypePublic); NODE_DEFINE_CONSTANT(target, kKeyTypePrivate); diff --git a/src/crypto/crypto_keys.h b/src/crypto/crypto_keys.h index 145483029646..00ff1d4402fa 100644 --- a/src/crypto/crypto_keys.h +++ b/src/crypto/crypto_keys.h @@ -77,7 +77,9 @@ class KeyObjectData final : public MemoryRetainer { bool allow_key_object); static KeyObjectData GetPublicOrPrivateKeyFromJs( - const v8::FunctionCallbackInfo& args, unsigned int* offset); + const v8::FunctionCallbackInfo& args, + unsigned int* offset, + bool allow_private_key_store = false); static v8::Maybe GetPrivateKeyEncodingFromJs(const v8::FunctionCallbackInfo& args, diff --git a/src/crypto/crypto_rsa.cc b/src/crypto/crypto_rsa.cc index 22b277676ff8..82d7affccc30 100644 --- a/src/crypto/crypto_rsa.cc +++ b/src/crypto/crypto_rsa.cc @@ -137,18 +137,6 @@ Maybe RsaKeyGenTraits::AdditionalConfig( params->params.modulus_bits = args[*offset + 1].As()->Value(); params->params.exponent = args[*offset + 2].As()->Value(); -#ifdef OPENSSL_IS_BORINGSSL - // BoringSSL hangs indefinitely generating an RSA key with e=1, and for - // other invalid exponents (e=0, even values) reports the misleading error - // RSA_R_TOO_MANY_ITERATIONS only after running the full keygen loop. Reject - // those up-front with a clear error. The constraint here (odd integer >= 3) - // matches BoringSSL's own rsa_check_public_key validation. - if (params->params.exponent < 3 || (params->params.exponent & 1) == 0) { - THROW_ERR_OUT_OF_RANGE(env, "publicExponent is invalid"); - return Nothing(); - } -#endif - *offset += 3; if (params->params.variant == kKeyVariantRSA_PSS) { diff --git a/src/crypto/crypto_sig.cc b/src/crypto/crypto_sig.cc index 0c3a29561c1f..3e065857cff8 100644 --- a/src/crypto/crypto_sig.cc +++ b/src/crypto/crypto_sig.cc @@ -8,6 +8,10 @@ #include "env-inl.h" #include "memory_tracker-inl.h" #include "openssl/ec.h" +#if NCRYPTO_USE_OPENSSL3_PROVIDER +#include +#include +#endif #include "threadpoolwork-inl.h" #include "v8.h" @@ -18,6 +22,7 @@ using ncrypto::ClearErrorOnReturn; using ncrypto::DataPointer; using ncrypto::Digest; using ncrypto::ECDSASigPointer; +using ncrypto::ECKeyPointer; using ncrypto::EVPKeyCtxPointer; using ncrypto::EVPKeyPointer; using ncrypto::EVPMDCtxPointer; @@ -390,6 +395,113 @@ bool SupportsContextString(const EVPKeyPointer& key) { #endif return false; } + +// Returns true unless the key is known not to be SM2, so that a key whose curve +// cannot be determined opts out of the prehashed fallback rather than into it. +bool MayBeSM2Key(const EVPKeyPointer& key) { +#ifdef OPENSSL_IS_BORINGSSL + return false; +#else + if (key.id() == EVP_PKEY_SM2) return true; + if (key.id() != EVP_PKEY_EC) return false; + +#if NCRYPTO_USE_OPENSSL3_PROVIDER + // An ECKeyPointer would also need the public point, which a provider-backed + // key need not expose. + char group_name[64]; + size_t group_name_len = 0; + if (EVP_PKEY_get_utf8_string_param(key.get(), + OSSL_PKEY_PARAM_GROUP_NAME, + group_name, + sizeof(group_name), + &group_name_len) != 1) { + return true; + } + return OBJ_sn2nid(group_name) == NID_sm2 || + EC_curve_nist2nid(group_name) == NID_sm2; +#else + ECKeyPointer ec(key); + if (!ec) return true; + + const EC_GROUP* group = ec.getGroup(); + if (group == nullptr) return true; + return EC_GROUP_get_curve_name(group) == NID_sm2; +#endif +#endif +} + +bool CanUsePrehashedFallback(const EVPKeyPointer& key, + const Digest& digest, + bool has_context) { + if (!digest || has_context) return false; + + if (key.isRsaVariant()) return true; + + // SM2 digest signing first hashes the algorithm-specific Z value, so the + // lower-level prehashed sign/verify operation is not equivalent. + return key.isSigVariant() && !MayBeSM2Key(key); +} + +ByteSource SignPrehashed(Environment* env, + const EVPKeyPointer& key, + const Digest& digest, + const ByteSource& input, + int padding, + std::optional salt_length, + DSASigEnc dsa_encoding) { + EVPMDCtxPointer context = EVPMDCtxPointer::New(); + if (!context || !context.digestInit(digest) || !context.digestUpdate(input)) + [[unlikely]] { + return {}; + } + + auto data = context.digestFinal(context.getExpectedSize()); + if (!data) [[unlikely]] { + return {}; + } + + EVPKeyCtxPointer pkctx = key.newCtx(); + if (!pkctx || pkctx.initForSign() <= 0 || + !ApplyRSAOptions(key, pkctx.get(), padding, salt_length) || + !pkctx.setSignatureMd(context)) [[unlikely]] { + return {}; + } + + auto signature = pkctx.sign(data); + if (!signature) [[unlikely]] { + return {}; + } + + DCHECK(!signature.isSecure()); + auto out = ByteSource::Allocated(signature.release()); + if (UseP1363Encoding(key, dsa_encoding)) { + return ConvertSignatureToP1363(env, key, std::move(out)); + } + return out; +} + +bool VerifyPrehashed(const EVPKeyPointer& key, + const Digest& digest, + const ByteSource& input, + const ByteSource& signature, + int padding, + std::optional salt_length) { + EVPMDCtxPointer context = EVPMDCtxPointer::New(); + if (!context || !context.digestInit(digest) || !context.digestUpdate(input)) + [[unlikely]] { + return false; + } + + auto data = context.digestFinal(context.getExpectedSize()); + if (!data) [[unlikely]] { + return false; + } + + EVPKeyCtxPointer pkctx = key.newCtx(); + return pkctx && pkctx.initForVerify() > 0 && + ApplyRSAOptions(key, pkctx.get(), padding, salt_length) && + pkctx.setSignatureMd(context) && pkctx.verify(signature, data); +} } // namespace SignBase::Error SignBase::Init(const char* digest) { @@ -807,9 +919,6 @@ bool SignTraits::DeriveBits(Environment* env, ByteSource* out, CryptoJobMode mode) { bool can_throw = mode == CryptoJobMode::kCryptoJobSync; - auto context = EVPMDCtxPointer::New(); - if (!context) [[unlikely]] - return false; const auto& key = params.key.GetAsymmetricKey(); bool has_context = (params.flags & SignConfiguration::kHasContextString && @@ -820,6 +929,19 @@ bool SignTraits::DeriveBits(Environment* env, return false; } + int padding = params.flags & SignConfiguration::kHasPadding + ? params.padding + : key.getDefaultSignPadding(); + + std::optional salt_length = + params.flags & SignConfiguration::kHasSaltLength + ? std::optional(params.salt_length) + : std::nullopt; + + auto context = EVPMDCtxPointer::New(); + if (!context) [[unlikely]] + return false; + auto ctx = ([&] { if (has_context) { ncrypto::Buffer context_buf{ @@ -849,15 +971,6 @@ bool SignTraits::DeriveBits(Environment* env, return false; } - int padding = params.flags & SignConfiguration::kHasPadding - ? params.padding - : key.getDefaultSignPadding(); - - std::optional salt_length = - params.flags & SignConfiguration::kHasSaltLength - ? std::optional(params.salt_length) - : std::nullopt; - if (!ApplyRSAOptions(key, *ctx, padding, salt_length)) { if (can_throw) crypto::CheckThrow(env, SignBase::Error::PrivateKey); return false; @@ -875,6 +988,22 @@ bool SignTraits::DeriveBits(Environment* env, *out = ByteSource::Allocated(data.release()); } else { auto data = context.sign(params.data); + // Only evaluated on the failure path: CanUsePrehashedFallback() has to + // reconstruct EC key material to detect SM2, which is far too + // expensive to pay for on every successful sign. + if (!data && CanUsePrehashedFallback(key, params.digest, has_context)) { + *out = SignPrehashed(env, + key, + params.digest, + params.data, + padding, + salt_length, + params.dsa_encoding); + if (!*out && can_throw) { + crypto::CheckThrow(env, SignBase::Error::PrivateKey); + } + return static_cast(*out); + } if (!data) [[unlikely]] { if (can_throw) crypto::CheckThrow(env, SignBase::Error::PrivateKey); return false; @@ -893,9 +1022,24 @@ bool SignTraits::DeriveBits(Environment* env, case SignConfiguration::Mode::Verify: { auto buf = DataPointer::Alloc(1); static_cast(buf.get())[0] = 0; - if (context.verify(params.data, params.signature) && + // EVP_DigestVerify() documents 0 as a verification mismatch. In its + // Update/Final path, it maps a failed EVP_DigestVerifyUpdate() to -1. + // Some providers fail that combined operation but support raw + // verification of a precomputed digest, so only retry negative results. + // Retrying 0 would perform a second verification for every mismatch. + int verify_result = context.verifyOneShot(params.data, params.signature); + if (verify_result == 1 && !HasSmallOrderEdDsaPoint(key, params.signature)) { static_cast(buf.get())[0] = 1; + } else if (verify_result < 0 && + CanUsePrehashedFallback(key, params.digest, has_context) && + VerifyPrehashed(key, + params.digest, + params.data, + params.signature, + padding, + salt_length)) { + static_cast(buf.get())[0] = 1; } *out = ByteSource::Allocated(buf.release()); } diff --git a/src/crypto/crypto_util.cc b/src/crypto/crypto_util.cc index 17248bef7d96..3f5f70bf3200 100644 --- a/src/crypto/crypto_util.cc +++ b/src/crypto/crypto_util.cc @@ -99,20 +99,36 @@ int NoPasswordCallback(char* buf, int size, int rwflag, void* u) { return 0; } -bool ProcessFipsOptions() { - /* Override FIPS settings in configuration file, if needed. */ - if (per_process::cli_options->enable_fips_crypto || - per_process::cli_options->force_fips_crypto) { +std::optional ProcessFipsOptions() { + const bool enable_fips = per_process::cli_options->enable_fips_crypto; + const bool force_fips = per_process::cli_options->force_fips_crypto; + if (!enable_fips && !force_fips) return std::nullopt; + #if OPENSSL_VERSION_MAJOR >= 3 - if (!ncrypto::testFipsEnabled()) return false; - return ncrypto::setFipsEnabled(true, nullptr); -#else - // TODO(@jasnell): Remove this ifdef branch when openssl 1.1.1 is - // no longer supported. - if (FIPS_mode() == 0) return FIPS_mode_set(1); + // Whether FIPS-approved implementations are reachable is decided by the + // OpenSSL configuration, not by Node.js. Refuse to start rather than + // restrict the default property query to a provider that is not there, + // which would leave every operation failing as unsupported. + if (!ncrypto::testFipsEnabled()) { + const std::string option = force_fips ? "--force-fips" : "--enable-fips"; + return option + " requires an active OpenSSL provider named \"fips\". " + "FIPS mode is configured through OpenSSL; see " + "https://nodejs.org/api/crypto.html#fips-mode"; + } #endif + + CryptoErrorList errors{CryptoErrorList::Option::NONE}; + if (!ncrypto::setFipsEnabled(true, &errors)) { + std::string error = "OpenSSL error when trying to enable FIPS"; + if (!errors.empty()) error += ':'; + for (const auto& openssl_error : errors) { + error += '\n'; + error += openssl_error; + } + return error; } - return true; + + return std::nullopt; } bool InitCryptoOnce(Isolate* isolate) { @@ -248,7 +264,7 @@ MaybeLocal cryptoErrorListToException(Environment* env, // If there are no errors, it is likely a bug but we will return // an error anyway. if (errors.empty()) { - return Exception::Error(FIXED_ONE_BYTE_STRING(env->isolate(), "Ok")); + return Exception::Error(env->ok_string()); } // The last error in the list is the one that will be used as the @@ -739,13 +755,9 @@ MaybeLocal CreateWebCryptoJobError(Environment* env, CHECK(domexception_ctor->IsFunction()); Local options = Object::New(isolate); - if (options - ->Set(context, - FIXED_ONE_BYTE_STRING(isolate, "name"), - FIXED_ONE_BYTE_STRING(isolate, "OperationError")) + if (options->Set(context, env->name_string(), env->operationerror_string()) .IsNothing() || - options->Set(context, FIXED_ONE_BYTE_STRING(isolate, "cause"), cause) - .IsNothing()) { + options->Set(context, env->cause_string(), cause).IsNothing()) { return {}; } diff --git a/src/crypto/crypto_util.h b/src/crypto/crypto_util.h index ca6157e42821..27d698107113 100644 --- a/src/crypto/crypto_util.h +++ b/src/crypto/crypto_util.h @@ -62,7 +62,10 @@ constexpr T NumBitsToBytes(T bits) { return (bits / CHAR_BIT) + ((CHAR_BIT - 1 + (bits % CHAR_BIT)) / CHAR_BIT); } -bool ProcessFipsOptions(); +// Applies the FIPS related command line options. Returns a description of +// what went wrong, or std::nullopt when there was nothing to do or the +// options were applied successfully. +std::optional ProcessFipsOptions(); bool InitCryptoOnce(v8::Isolate* isolate); void InitCryptoOnce(); @@ -463,7 +466,7 @@ class CryptoJob : public AsyncWrap, public ThreadPoolWork { { node::errors::TryCatchScope try_catch(env); if (value->IsObject()) { - then_key = FIXED_ONE_BYTE_STRING(env->isolate(), "then"); + then_key = env->then_string(); v8::Local object = value.As(); v8::Maybe has_own_then = object->HasOwnProperty(context, then_key); diff --git a/src/env-inl.h b/src/env-inl.h index 74bbb9fb8324..5f04e7085f42 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -615,6 +615,10 @@ inline void Environment::set_can_call_into_js(bool can_call_into_js) { can_call_into_js_ = can_call_into_js; } +inline bool Environment::is_processing_v8_interrupt() const { + return is_processing_v8_interrupt_; +} + inline bool Environment::has_run_bootstrapping_code() const { return principal_realm_->has_run_bootstrapping_code(); } @@ -841,6 +845,13 @@ void Environment::set_process_exit_handler( #undef VY #undef VP +#define V(Name, label, _, __) \ + inline v8::Local IsolateData::Name##_permission_string() const { \ + return Name##_permission_string##_.Get(isolate_); \ + } + PERMISSIONS(V) +#undef V + #define VM(PropertyName) V(PropertyName##_binding_template, v8::ObjectTemplate) #define V(PropertyName, TypeName) \ inline v8::Local IsolateData::PropertyName() const { \ @@ -870,6 +881,13 @@ void Environment::set_process_exit_handler( #undef VY #undef VP +#define V(Name, label, _, __) \ + inline v8::Local Environment::Name##_permission_string() const { \ + return isolate_data()->Name##_permission_string(); \ + } + PERMISSIONS(V) +#undef V + #define V(PropertyName, TypeName) \ inline v8::Local Environment::PropertyName() const { \ return isolate_data()->PropertyName(); \ diff --git a/src/env.cc b/src/env.cc index 7a8c470e7abb..84957de5cb01 100644 --- a/src/env.cc +++ b/src/env.cc @@ -76,6 +76,8 @@ using v8::Undefined; using v8::Value; using worker::Worker; +constexpr size_t kManagedBufferCacheSize = 64 * 1024; + int const ContextEmbedderTag::kNodeContextTag = 0x6e6f64; void* const ContextEmbedderTag::kNodeContextTagPtr = const_cast( static_cast(&ContextEmbedderTag::kNodeContextTag)); @@ -352,6 +354,12 @@ IsolateDataSerializeInfo IsolateData::Serialize(SnapshotCreator* creator) { #undef VS #undef VP +#define V(Name, label, _, __) \ + info.primitive_values.push_back( \ + creator->AddData(Name##_permission_string##_.Get(isolate))); + PERMISSIONS(V) +#undef V + info.primitive_values.reserve(info.primitive_values.size() + AsyncWrap::PROVIDERS_LENGTH); for (size_t i = 0; i < AsyncWrap::PROVIDERS_LENGTH; i++) { @@ -411,6 +419,20 @@ void IsolateData::DeserializeProperties(const IsolateDataSerializeInfo* info) { #undef VS #undef VP +#define V(Name, label, _, __) \ + do { \ + MaybeLocal maybe_field = \ + isolate_->GetDataFromSnapshotOnce( \ + info->primitive_values[i++]); \ + Local field; \ + if (!maybe_field.ToLocal(&field)) { \ + fprintf(stderr, "Failed to deserialize " #Name "_permission_string\n"); \ + } \ + Name##_permission_string##_.Set(isolate_, field); \ + } while (0); + PERMISSIONS(V) +#undef V + for (size_t j = 0; j < AsyncWrap::PROVIDERS_LENGTH; j++) { MaybeLocal maybe_field = isolate_->GetDataFromSnapshotOnce(info->primitive_values[i++]); @@ -512,6 +534,17 @@ void IsolateData::CreateProperties() { PER_ISOLATE_STRING_PROPERTIES(V) #undef V +#define V(Name, label, _, __) \ + Name##_permission_string##_.Set( \ + isolate_, \ + String::NewFromOneByte(isolate_, \ + reinterpret_cast(#Name), \ + NewStringType::kInternalized, \ + sizeof(#Name) - 1) \ + .ToLocalChecked()); + PERMISSIONS(V) +#undef V + // Create all the provider strings that will be passed to JS. Place them in // an array so the array index matches the PROVIDER id offset. This way the // strings can be retrieved quickly. @@ -622,6 +655,11 @@ void IsolateData::MemoryInfo(MemoryTracker* tracker) const { PER_ISOLATE_STRING_PROPERTIES(V) #undef V +#define V(Name, label, _, __) \ + tracker->TrackField(#Name "_permission_string", Name##_permission_string()); + PERMISSIONS(V) +#undef V + tracker->TrackField("async_wrap_providers", async_wrap_providers_); if (node_allocator_ != nullptr) { @@ -730,10 +768,16 @@ void Environment::add_refs(int64_t diff) { } uv_buf_t Environment::allocate_managed_buffer(const size_t suggested_size) { - std::unique_ptr bs = ArrayBuffer::NewBackingStore( - isolate(), - suggested_size, - BackingStoreInitializationMode::kUninitialized); + std::unique_ptr bs; + if (suggested_size == kManagedBufferCacheSize && + managed_buffer_cache_ != nullptr) { + bs = std::move(managed_buffer_cache_); + } else { + bs = ArrayBuffer::NewBackingStore( + isolate(), + suggested_size, + BackingStoreInitializationMode::kUninitialized); + } uv_buf_t buf = uv_buf_init(static_cast(bs->Data()), bs->ByteLength()); released_allocated_buffers_.emplace(buf.base, std::move(bs)); return buf; @@ -751,6 +795,11 @@ std::unique_ptr Environment::release_managed_buffer( return bs; } +void Environment::recycle_managed_buffer(std::unique_ptr bs) { + if (bs != nullptr && bs->ByteLength() == kManagedBufferCacheSize) + managed_buffer_cache_ = std::move(bs); +} + std::string Environment::GetExecPath(const std::vector& argv) { char exec_path_buf[2 * PATH_MAX]; size_t exec_path_len = sizeof(exec_path_buf); @@ -920,6 +969,10 @@ Environment::Environment(IsolateData* isolate_data, permission()->Apply( this, {"*"}, permission::PermissionScope::kChildProcess); } + if (!options_->allow_openssl_store) { + permission()->Apply( + this, {"*"}, permission::PermissionScope::kOpenSSLStore); + } if (!options_->allow_worker_threads) { permission()->Apply( this, {"*"}, permission::PermissionScope::kWorkerThreads); @@ -1475,7 +1528,9 @@ void Environment::RequestInterruptFromV8() { return; } env->interrupt_data_.store(nullptr); + env->is_processing_v8_interrupt_ = true; env->RunAndClearInterrupts(); + env->is_processing_v8_interrupt_ = false; }, interrupt_data); } diff --git a/src/env.h b/src/env.h index 639e3498bbb9..c5501cd7914a 100644 --- a/src/env.h +++ b/src/env.h @@ -188,6 +188,11 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer { #undef VS #undef VP +#define V(Name, label, _, __) \ + inline v8::Local Name##_permission_string() const; + PERMISSIONS(V) +#undef V + #define VM(PropertyName) V(PropertyName##_binding_template, v8::ObjectTemplate) #define V(PropertyName, TypeName) \ inline v8::Local PropertyName() const; \ @@ -233,6 +238,12 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer { #undef VS #undef VY #undef VP + +#define V(Name, label, _, __) \ + v8::Eternal Name##_permission_string##_; + PERMISSIONS(V) +#undef V + // Keep a list of all Persistent strings used for AsyncWrap Provider types. std::array, AsyncWrap::PROVIDERS_LENGTH> async_wrap_providers_; @@ -780,6 +791,12 @@ class Environment final : public MemoryRetainer { inline bool can_call_into_js() const; inline void set_can_call_into_js(bool can_call_into_js); + // True while RequestInterrupt() callbacks are being invoked from the + // v8::Isolate::RequestInterrupt() handler, i.e. potentially at an + // arbitrary point during JS execution. Calling into JS must be avoided + // in that case. + inline bool is_processing_v8_interrupt() const; + // Increase or decrease a counter that manages whether this Environment // keeps the event loop alive on its own or not. The counter starts out at 0, // meaning it does not, and any positive value will make it keep the event @@ -870,6 +887,11 @@ class Environment final : public MemoryRetainer { #undef VY #undef VP +#define V(Name, label, _, __) \ + inline v8::Local Name##_permission_string() const; + PERMISSIONS(V) +#undef V + #define V(PropertyName, TypeName) \ inline v8::Local PropertyName() const; \ inline void set_ ## PropertyName(v8::Local value); @@ -1035,6 +1057,8 @@ class Environment final : public MemoryRetainer { uv_buf_t allocate_managed_buffer(const size_t suggested_size); std::unique_ptr release_managed_buffer(const uv_buf_t& buf); + // Only buffers that were not exposed externally may be recycled. + void recycle_managed_buffer(std::unique_ptr bs); void AddUnmanagedFd(int fd); void RemoveUnmanagedFd(int fd); @@ -1231,6 +1255,7 @@ class Environment final : public MemoryRetainer { bool task_queues_async_initialized_ = false; std::atomic interrupt_data_ {nullptr}; + bool is_processing_v8_interrupt_ = false; void RequestInterruptFromV8(); static void CheckImmediate(uv_check_t* handle); @@ -1251,6 +1276,7 @@ class Environment final : public MemoryRetainer { // track of the BackingStore for a given pointer. std::unordered_map> released_allocated_buffers_; + std::unique_ptr managed_buffer_cache_; v8::CpuProfiler* cpu_profiler_ = nullptr; std::vector pending_profiles_; diff --git a/src/env_properties.h b/src/env_properties.h index ccf11e66e53e..36e1f9209793 100644 --- a/src/env_properties.h +++ b/src/env_properties.h @@ -74,6 +74,7 @@ V(__dirname_string, "__dirname") \ V(ack_string, "ack") \ V(address_string, "address") \ + V(algorithm_string, "algorithm") \ V(aliases_string, "aliases") \ V(allow_bare_named_params_string, "allowBareNamedParameters") \ V(allow_unknown_named_params_string, "allowUnknownNamedParameters") \ @@ -84,6 +85,7 @@ V(backup_string, "backup") \ V(base_string, "base") \ V(base_url_string, "baseURL") \ + V(brotli_string, "brotli") \ V(buffer_string, "buffer") \ V(bytes_parsed_string, "bytesParsed") \ V(bytes_read_string, "bytesRead") \ @@ -91,6 +93,7 @@ V(cached_data_produced_string, "cachedDataProduced") \ V(cached_data_rejected_string, "cachedDataRejected") \ V(cached_data_string, "cachedData") \ + V(cause_string, "cause") \ V(change_string, "change") \ V(changes_string, "changes") \ V(chunks_sent_since_last_write_string, "chunksSentSinceLastWrite") \ @@ -171,6 +174,7 @@ V(exponent_string, "exponent") \ V(exports_string, "exports") \ V(external_stream_string, "_externalStream") \ + V(extractable_string, "extractable") \ V(family_string, "family") \ V(fatal_exception_string, "_fatalException") \ V(fd_string, "fd") \ @@ -206,6 +210,7 @@ V(ignore_string, "ignore") \ V(inherit_string, "inherit") \ V(input_string, "input") \ + V(internal_crypto_keys_string, "internal/crypto/keys") \ V(inverse_string, "inverse") \ V(ipv4_string, "IPv4") \ V(ipv6_string, "IPv6") \ @@ -255,6 +260,7 @@ V(node_string, "node") \ V(object_string, "Object") \ V(ocsp_request_string, "OCSPRequest") \ + V(ok_string, "ok") \ V(oncertcb_string, "oncertcb") \ V(onchange_string, "onchange") \ V(onclienthello_string, "onclienthello") \ @@ -278,10 +284,14 @@ V(onwrite_string, "onwrite") \ V(ongracefulclosecomplete_string, "ongracefulclosecomplete") \ V(openssl_error_stack, "opensslErrorStack") \ + V(operationerror_string, "OperationError") \ V(options_string, "options") \ V(original_string, "original") \ V(output_string, "output") \ V(overlapped_string, "overlapped") \ + V(p256_string, "P-256") \ + V(p384_string, "P-384") \ + V(p521_string, "P-521") \ V(parse_error_string, "Parse Error") \ V(password_string, "password") \ V(path_string, "path") \ @@ -322,6 +332,7 @@ V(result_string, "result") \ V(return_arrays_string, "returnArrays") \ V(salt_length_string, "saltLength") \ + V(secp256k1_string, "secp256k1") \ V(search_string, "search") \ V(servername_string, "servername") \ V(session_id_string, "sessionId") \ @@ -350,6 +361,7 @@ V(syscall_string, "syscall") \ V(table_string, "table") \ V(target_string, "target") \ + V(then_string, "then") \ V(thread_id_string, "threadId") \ V(thread_name_string, "threadName") \ V(tls_group_string, "TLSGroup") \ @@ -368,6 +380,7 @@ V(uid_string, "uid") \ V(unknown_string, "") \ V(url_string, "url") \ + V(usages_string, "usages") \ V(username_string, "username") \ V(value_string, "value") \ V(verify_error_string, "verifyError") \ @@ -377,7 +390,9 @@ V(wrap_string, "wrap") \ V(writable_string, "writable") \ V(write_host_object_string, "_writeHostObject") \ - V(write_queue_size_string, "writeQueueSize") + V(write_queue_size_string, "writeQueueSize") \ + V(zlib_string, "zlib") \ + V(zstd_string, "zstd") #define PER_ISOLATE_TEMPLATE_PROPERTIES(V) \ V(a_record_template, v8::DictionaryTemplate) \ @@ -431,6 +446,7 @@ V(naptr_record_template, v8::DictionaryTemplate) \ V(object_stats_template, v8::DictionaryTemplate) \ V(page_stats_template, v8::DictionaryTemplate) \ + V(permission_diagnostic_channel_message, v8::DictionaryTemplate) \ V(pipe_constructor_template, v8::FunctionTemplate) \ V(script_context_constructor_template, v8::FunctionTemplate) \ V(secure_context_constructor_template, v8::FunctionTemplate) \ diff --git a/src/heap_utils.cc b/src/heap_utils.cc index e52685546a7a..72c1a73aa6c0 100644 --- a/src/heap_utils.cc +++ b/src/heap_utils.cc @@ -57,19 +57,13 @@ class JSGraphJSNode : public EmbedderGraph::Node { CHECK(!val.IsEmpty()); } - struct Equal { - inline bool operator()(JSGraphJSNode* a, JSGraphJSNode* b) const { - Local data_a = a->V8Value(); - Local data_b = a->V8Value(); - if (data_a->IsValue()) { - if (!data_b->IsValue()) { - return false; - } - return data_a.As()->SameValue(data_b.As()); - } - return data_a == data_b; + bool IsSame(Local other) { + Local value = V8Value(); + if (value->IsValue() && other->IsValue()) { + return value.As()->SameValue(other.As()); } - }; + return value == other; + } private: Global persistent_; @@ -80,12 +74,15 @@ class JSGraph : public EmbedderGraph { explicit JSGraph(Isolate* isolate) : isolate_(isolate) {} Node* V8Node(const Local& value) override { - std::unique_ptr n { new JSGraphJSNode(isolate_, value) }; - auto it = engine_nodes_.find(n.get()); - if (it != engine_nodes_.end()) - return *it; - engine_nodes_.insert(n.get()); - return AddNode(std::unique_ptr(n.release())); + for (JSGraphJSNode* node : engine_nodes_) { + if (node->IsSame(value)) { + return node; + } + } + + auto node = std::make_unique(isolate_, value); + engine_nodes_.push_back(node.get()); + return AddNode(std::move(node)); } Node* V8Node(const Local& value) override { @@ -207,7 +204,7 @@ class JSGraph : public EmbedderGraph { private: Isolate* isolate_; std::unordered_set> nodes_; - std::set engine_nodes_; + std::vector engine_nodes_; std::unordered_map>> edges_; }; @@ -215,6 +212,11 @@ void BuildEmbedderGraph(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); JSGraph graph(env->isolate()); Environment::BuildEmbedderGraph(env->isolate(), &graph, env); + // This binding is used only by tests. Include supplied values so tests can + // verify that JSGraph returns one graph node for each distinct V8 value. + for (int i = 0; i < args.Length(); i++) { + graph.V8Node(args[i]); + } Local ret; if (graph.CreateObject().ToLocal(&ret)) args.GetReturnValue().Set(ret); diff --git a/src/histogram-inl.h b/src/histogram-inl.h index 3b8712c87879..eea0e89bef11 100644 --- a/src/histogram-inl.h +++ b/src/histogram-inl.h @@ -9,58 +9,124 @@ namespace node { +void Histogram::UpdateEwma(double value) { + // Called inside a write lock. No-op when EWMA is disabled. + if (ewma_alpha_ <= 0) return; + if (!ewma_initialized_) { + ewma_mean_ = value; + ewma_variance_ = 0; + ewma_initialized_ = true; + if (threshold_ > 0) { + ewma_error_rate_ = (value > static_cast(threshold_)) ? 1.0 : 0.0; + } + return; + } + double diff = value - ewma_mean_; + ewma_mean_ += ewma_alpha_ * diff; + ewma_variance_ = + (1.0 - ewma_alpha_) * (ewma_variance_ + ewma_alpha_ * diff * diff); + + // Binary EWMA for SLO error rate: feed 1 if over threshold, 0 otherwise. + if (threshold_ > 0) { + double exceeded = (value > static_cast(threshold_)) ? 1.0 : 0.0; + ewma_error_rate_ += ewma_alpha_ * (exceeded - ewma_error_rate_); + } +} + void Histogram::Reset() { - Mutex::ScopedLock lock(mutex_); + RwLock::ScopedWriteLock lock(mutex_); hdr_reset(histogram_.get()); exceeds_ = 0; - count_ = 0; prev_ = 0; + ewma_mean_ = 0; + ewma_variance_ = 0; + ewma_error_rate_ = 0; + ewma_initialized_ = false; } double Histogram::Add(const Histogram& other) { - Mutex::ScopedLock lock(mutex_); - count_ += other.count_; - exceeds_ += other.exceeds_; - if (other.prev_ > prev_) - prev_ = other.prev_; - return static_cast(hdr_add(histogram_.get(), other.histogram_.get())); + auto do_add = [&]() { + exceeds_ += other.exceeds_; + if (other.prev_ > prev_) prev_ = other.prev_; + // hdr_add merges all bucket counts and total_count internally. + return static_cast( + hdr_add(histogram_.get(), other.histogram_.get())); + }; + + // When adding a histogram to itself, a single write lock suffices. + if (this == &other) { + RwLock::ScopedWriteLock lock(mutex_); + return do_add(); + } + + // Write-lock this (modified), read-lock other (only read). + // Lock in pointer order to prevent deadlock. + if (this < &other) { + RwLock::ScopedWriteLock lock1(mutex_); + RwLock::ScopedReadLock lock2(other.mutex_); + return do_add(); + } + + RwLock::ScopedReadLock lock1(other.mutex_); + RwLock::ScopedWriteLock lock2(mutex_); + return do_add(); } size_t Histogram::Count() const { - Mutex::ScopedLock lock(mutex_); - return count_; + RwLock::ScopedReadLock lock(mutex_); + return static_cast(histogram_->total_count); +} + +size_t Histogram::Exceeds() const { + RwLock::ScopedReadLock lock(mutex_); + return exceeds_; } int64_t Histogram::Min() const { - Mutex::ScopedLock lock(mutex_); + RwLock::ScopedReadLock lock(mutex_); return hdr_min(histogram_.get()); } int64_t Histogram::Max() const { - Mutex::ScopedLock lock(mutex_); + RwLock::ScopedReadLock lock(mutex_); return hdr_max(histogram_.get()); } double Histogram::Mean() const { - Mutex::ScopedLock lock(mutex_); + RwLock::ScopedReadLock lock(mutex_); return hdr_mean(histogram_.get()); } double Histogram::Stddev() const { - Mutex::ScopedLock lock(mutex_); + RwLock::ScopedReadLock lock(mutex_); return hdr_stddev(histogram_.get()); } +double Histogram::EwmaMean() const { + RwLock::ScopedReadLock lock(mutex_); + return ewma_initialized_ ? ewma_mean_ : 0; +} + +double Histogram::EwmaStddev() const { + RwLock::ScopedReadLock lock(mutex_); + return ewma_initialized_ ? std::sqrt(ewma_variance_) : 0; +} + +double Histogram::EwmaErrorRate() const { + RwLock::ScopedReadLock lock(mutex_); + return ewma_initialized_ ? ewma_error_rate_ : 0; +} + int64_t Histogram::Percentile(double percentile) const { - Mutex::ScopedLock lock(mutex_); + RwLock::ScopedReadLock lock(mutex_); CHECK_GT(percentile, 0); CHECK_LE(percentile, 100); return hdr_value_at_percentile(histogram_.get(), percentile); } template -void Histogram::Percentiles(Iterator&& fn) { - Mutex::ScopedLock lock(mutex_); +void Histogram::Percentiles(Iterator&& fn) const { + RwLock::ScopedReadLock lock(mutex_); hdr_iter iter; hdr_iter_percentile_init(&iter, histogram_.get(), 1); while (hdr_iter_next(&iter)) { @@ -69,37 +135,75 @@ void Histogram::Percentiles(Iterator&& fn) { } } +int64_t Histogram::CountAt(int64_t value) const { + RwLock::ScopedReadLock lock(mutex_); + return hdr_count_at_value(histogram_.get(), value); +} + +bool Histogram::RecordCorrected(int64_t value, int64_t expected_interval) { + RwLock::ScopedWriteLock lock(mutex_); + bool recorded = + hdr_record_corrected_value(histogram_.get(), value, expected_interval); + if (!recorded) + exceeds_++; + else + UpdateEwma(static_cast(value)); + return recorded; +} + bool Histogram::Record(int64_t value) { - Mutex::ScopedLock lock(mutex_); + RwLock::ScopedWriteLock lock(mutex_); bool recorded = hdr_record_value(histogram_.get(), value); if (!recorded) exceeds_++; else - count_++; + UpdateEwma(static_cast(value)); return recorded; } uint64_t Histogram::RecordDelta() { - Mutex::ScopedLock lock(mutex_); + RwLock::ScopedWriteLock lock(mutex_); uint64_t time = uv_hrtime(); int64_t delta = 0; if (prev_ > 0) { CHECK_GE(time, prev_); delta = time - prev_; - if (hdr_record_value(histogram_.get(), delta)) - count_++; - else + if (!hdr_record_value(histogram_.get(), delta)) exceeds_++; + else + UpdateEwma(static_cast(delta)); } prev_ = time; return delta; } size_t Histogram::GetMemorySize() const { - Mutex::ScopedLock lock(mutex_); + RwLock::ScopedReadLock lock(mutex_); return hdr_get_memory_size(histogram_.get()); } +template +void Histogram::LinearBuckets(int64_t step_size, Iterator&& fn) const { + RwLock::ScopedReadLock lock(mutex_); + hdr_iter iter; + hdr_iter_linear_init(&iter, histogram_.get(), step_size); + while (hdr_iter_next(&iter)) { + fn(iter.value, iter.specifics.linear.count_added_in_this_iteration_step); + } +} + +template +void Histogram::LogBuckets(int64_t first_bucket, + double log_base, + Iterator&& fn) const { + RwLock::ScopedReadLock lock(mutex_); + hdr_iter iter; + hdr_iter_log_init(&iter, histogram_.get(), first_bucket, log_base); + while (hdr_iter_next(&iter)) { + fn(iter.value, iter.specifics.log.count_added_in_this_iteration_step); + } +} + } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS diff --git a/src/histogram.cc b/src/histogram.cc index a676d3024666..7127bb80cc8f 100644 --- a/src/histogram.cc +++ b/src/histogram.cc @@ -6,12 +6,19 @@ #include "node_errors.h" #include "node_external_reference.h" #include "util.h" +#include "v8-typed-array.h" + +#include +#include +#include namespace node { +using v8::Array; using v8::BigInt; using v8::CFunction; using v8::Context; +using v8::Float64Array; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Integer; @@ -46,12 +53,543 @@ Histogram::Histogram(const Options& options) { options.figures, &histogram)); histogram_.reset(histogram); + + // alpha = 1 - 2^(-1/halfLife). With halfLife <= 0, EWMA is disabled. + if (options.half_life > 0) { + ewma_alpha_ = 1.0 - std::exp(-std::log(2.0) / options.half_life); + } + threshold_ = options.threshold; } void Histogram::MemoryInfo(MemoryTracker* tracker) const { tracker->TrackFieldWithSize("histogram", GetMemorySize()); } +bool Histogram::IsCompatible(const Histogram& other) const { + return histogram_->counts_len == other.histogram_->counts_len && + histogram_->lowest_discernible_value == + other.histogram_->lowest_discernible_value && + histogram_->highest_trackable_value == + other.histogram_->highest_trackable_value && + histogram_->significant_figures == + other.histogram_->significant_figures; +} + +double Histogram::Cdf(int64_t value) const { + RwLock::ScopedReadLock lock(mutex_); + int64_t total = histogram_->total_count; + if (total == 0) return 0.0; + + hdr_iter iter; + hdr_iter_init(&iter, histogram_.get()); + while (hdr_iter_next(&iter)) { + if (iter.highest_equivalent_value >= value) { + return static_cast(iter.cumulative_count) / + static_cast(total); + } + // All recorded data accounted for; remaining buckets are empty. + if (iter.cumulative_count >= total) break; + } + return 1.0; +} + +double Histogram::Skewness() const { + RwLock::ScopedReadLock lock(mutex_); + int64_t total = histogram_->total_count; + if (total < 3) return 0.0; + + // Compute mean in one pass, then variance and skewness in a second + // pass. This avoids calling hdr_stddev (which internally recomputes + // hdr_mean), reducing the total from 4 iterations to 2. + double mean = hdr_mean(histogram_.get()); + + double m2 = 0.0; + double m3 = 0.0; + hdr_iter iter; + hdr_iter_recorded_init(&iter, histogram_.get()); + while (hdr_iter_next(&iter)) { + double dev = static_cast(hdr_median_equivalent_value( + histogram_.get(), iter.value)) - + mean; + double d2 = dev * dev; + m2 += static_cast(iter.count) * d2; + m3 += static_cast(iter.count) * d2 * dev; + } + + double n = static_cast(total); + double variance = m2 / n; + if (variance == 0.0) return 0.0; + double s3 = variance * std::sqrt(variance); // stddev^3 + return (m3 / n) / s3; +} + +double Histogram::Kurtosis() const { + RwLock::ScopedReadLock lock(mutex_); + int64_t total = histogram_->total_count; + if (total < 4) return 0.0; + + // Same single-pass approach as Skewness: compute mean first, then + // variance and excess kurtosis together in one iteration. + double mean = hdr_mean(histogram_.get()); + + double m2 = 0.0; + double m4 = 0.0; + hdr_iter iter; + hdr_iter_recorded_init(&iter, histogram_.get()); + while (hdr_iter_next(&iter)) { + double dev = static_cast(hdr_median_equivalent_value( + histogram_.get(), iter.value)) - + mean; + double d2 = dev * dev; + m2 += static_cast(iter.count) * d2; + m4 += static_cast(iter.count) * d2 * d2; + } + + double n = static_cast(total); + double variance = m2 / n; + if (variance == 0.0) return 0.0; + double s4 = variance * variance; // stddev^4 + return (m4 / n) / s4 - 3.0; +} + +double Histogram::Subtract(const Histogram& other) { + auto do_subtract = [&]() -> double { + int64_t dropped = 0; + int32_t len = + std::min(histogram_->counts_len, other.histogram_->counts_len); + for (int32_t i = 0; i < len; i++) { + int64_t count = histogram_->counts[i] - other.histogram_->counts[i]; + if (count < 0) { + dropped += -count; + count = 0; + } + histogram_->counts[i] = count; + } + hdr_reset_internal_counters(histogram_.get()); + exceeds_ = (exceeds_ > other.exceeds_) ? exceeds_ - other.exceeds_ : 0; + return static_cast(dropped); + }; + + if (this == &other) { + RwLock::ScopedWriteLock lock(mutex_); + return do_subtract(); + } + + if (this < &other) { + RwLock::ScopedWriteLock lock1(mutex_); + RwLock::ScopedReadLock lock2(other.mutex_); + return do_subtract(); + } + + RwLock::ScopedReadLock lock1(other.mutex_); + RwLock::ScopedWriteLock lock2(mutex_); + return do_subtract(); +} + +double Histogram::KsTest(const Histogram& other) const { + auto do_ks = [&]() -> double { + int64_t n1 = histogram_->total_count; + int64_t n2 = other.histogram_->total_count; + if (n1 == 0 || n2 == 0) return 0.0; + + double max_d = 0.0; + int64_t cum1 = 0, cum2 = 0; + int32_t len = + std::max(histogram_->counts_len, other.histogram_->counts_len); + + for (int32_t i = 0; i < len; i++) { + if (i < histogram_->counts_len) cum1 += histogram_->counts[i]; + if (i < other.histogram_->counts_len) cum2 += other.histogram_->counts[i]; + double cdf1 = static_cast(cum1) / static_cast(n1); + double cdf2 = static_cast(cum2) / static_cast(n2); + double d = cdf1 > cdf2 ? cdf1 - cdf2 : cdf2 - cdf1; + if (d > max_d) max_d = d; + } + return max_d; + }; + + if (this == &other) return 0.0; + + if (this < &other) { + RwLock::ScopedReadLock lock1(mutex_); + RwLock::ScopedReadLock lock2(other.mutex_); + return do_ks(); + } + + RwLock::ScopedReadLock lock1(other.mutex_); + RwLock::ScopedReadLock lock2(mutex_); + return do_ks(); +} + +void Histogram::PercentilesAt(const double* percentiles, + int64_t* values, + size_t length) const { + RwLock::ScopedReadLock lock(mutex_); + hdr_value_at_percentiles(histogram_.get(), percentiles, values, length); +} + +namespace { +// Continued fraction evaluation for the regularized incomplete beta +// function using Lentz's modified method. Reference: Numerical Recipes +// in C, 2nd edition, section 6.4. +static double BetaContinuedFraction(double a, double b, double x) { + constexpr double FPMIN = 1e-30; + constexpr int MAXIT = 200; + constexpr double EPS = 3e-12; + + double qab = a + b; + double qap = a + 1.0; + double qam = a - 1.0; + double c = 1.0; + double d = 1.0 - qab * x / qap; + if (std::fabs(d) < FPMIN) d = FPMIN; + d = 1.0 / d; + double h = d; + + for (int m = 1; m <= MAXIT; m++) { + int m2 = 2 * m; + // Even step. + double aa = m * (b - m) * x / ((qam + m2) * (a + m2)); + d = 1.0 + aa * d; + if (std::fabs(d) < FPMIN) d = FPMIN; + c = 1.0 + aa / c; + if (std::fabs(c) < FPMIN) c = FPMIN; + d = 1.0 / d; + h *= d * c; + // Odd step. + aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2)); + d = 1.0 + aa * d; + if (std::fabs(d) < FPMIN) d = FPMIN; + c = 1.0 + aa / c; + if (std::fabs(c) < FPMIN) c = FPMIN; + d = 1.0 / d; + double del = d * c; + h *= del; + if (std::fabs(del - 1.0) <= EPS) break; + } + return h; +} + +// Regularized incomplete beta function I_x(a, b). +// Returns the probability that a Beta(a,b) random variable is <= x. +static double RegularizedIncompleteBeta(double a, double b, double x) { + if (x <= 0.0) return 0.0; + if (x >= 1.0) return 1.0; + + double ln_front = std::lgamma(a + b) - std::lgamma(a) - std::lgamma(b) + + a * std::log(x) + b * std::log(1.0 - x); + double bt = std::exp(ln_front); + + // Use the symmetry relation to ensure the continued fraction + // converges in the region where it is most accurate. + if (x < (a + 1.0) / (a + b + 2.0)) { + return bt * BetaContinuedFraction(a, b, x) / a; + } + return 1.0 - bt * BetaContinuedFraction(b, a, 1.0 - x) / b; +} + +// Standard normal CDF: Phi(x) = P(Z <= x). +static double NormalCdf(double x) { + return 0.5 * std::erfc(-x * std::numbers::sqrt2 / 2.0); +} + +// Student's t-distribution CDF: P(T <= t) for df degrees of freedom. +static double StudentTCdf(double t, double df) { + double x = df / (df + t * t); + double ibeta = RegularizedIncompleteBeta(df / 2.0, 0.5, x); + if (t >= 0.0) { + return 1.0 - 0.5 * ibeta; + } + return 0.5 * ibeta; +} + +// Student's t-distribution quantile (inverse CDF) using bisection. +// Returns the value t such that P(T <= t) = p. +static double StudentTQuantile(double p, double df) { + if (p <= 0.0) return -std::numeric_limits::infinity(); + if (p >= 1.0) return std::numeric_limits::infinity(); + if (p == 0.5) return 0.0; + + // Bisection search. The range [-1e6, 1e6] is sufficient for any + // practical confidence level and degrees of freedom. + double lo = -1e6; + double hi = 1e6; + for (int i = 0; i < 100; i++) { + double mid = (lo + hi) / 2.0; + if (StudentTCdf(mid, df) < p) { + lo = mid; + } else { + hi = mid; + } + } + return (lo + hi) / 2.0; +} + +// Binomial CDF: P(X <= k) for X ~ Binomial(n, p). +// Uses the identity P(X <= k) = I_{1-p}(n-k, k+1). +static double BinomialCdf(int64_t k, int64_t n, double p) { + if (k < 0) return 0.0; + if (k >= n) return 1.0; + return RegularizedIncompleteBeta( + static_cast(n - k), static_cast(k + 1), 1.0 - p); +} +} // namespace + +Histogram::WelchTestResult Histogram::WelchTest(const Histogram& other, + double confidence) const { + auto do_welch = [&]() -> WelchTestResult { + int64_t n1 = histogram_->total_count; + int64_t n2 = other.histogram_->total_count; + if (n1 < 2 || n2 < 2) return {0, 0, 1, 0, 0}; + + double mean1 = hdr_mean(histogram_.get()); + double mean2 = hdr_mean(other.histogram_.get()); + double sd1 = hdr_stddev(histogram_.get()); + double sd2 = hdr_stddev(other.histogram_.get()); + + // HdrHistogram computes population stddev (divides by N). + // Welch's t-test requires sample variance (divides by N-1). + double var1 = + sd1 * sd1 * static_cast(n1) / static_cast(n1 - 1); + double var2 = + sd2 * sd2 * static_cast(n2) / static_cast(n2 - 1); + + double se1 = var1 / static_cast(n1); + double se2 = var2 / static_cast(n2); + double se_sum = se1 + se2; + if (se_sum == 0.0) return {0, 0, 1, 0, 0}; + + double t = (mean1 - mean2) / std::sqrt(se_sum); + + // Welch-Satterthwaite degrees of freedom. + double df = (se_sum * se_sum) / (se1 * se1 / static_cast(n1 - 1) + + se2 * se2 / static_cast(n2 - 1)); + + // Two-tailed p-value. + double p = 2.0 * StudentTCdf(-std::fabs(t), df); + + // Confidence interval on the difference of means. + double alpha = 1.0 - confidence; + double t_crit = StudentTQuantile(1.0 - alpha / 2.0, df); + double margin = t_crit * std::sqrt(se_sum); + double diff = mean1 - mean2; + + return {t, df, p, diff - margin, diff + margin}; + }; + + if (this == &other) return {0, 0, 1, 0, 0}; + + if (this < &other) { + RwLock::ScopedReadLock lock1(mutex_); + RwLock::ScopedReadLock lock2(other.mutex_); + return do_welch(); + } + + RwLock::ScopedReadLock lock1(other.mutex_); + RwLock::ScopedReadLock lock2(mutex_); + return do_welch(); +} + +Histogram::MannWhitneyResult Histogram::MannWhitneyTest( + const Histogram& other) const { + auto do_mw = [&]() -> MannWhitneyResult { + int64_t n1 = histogram_->total_count; + int64_t n2 = other.histogram_->total_count; + if (n1 == 0 || n2 == 0) return {0, 0, 1}; + + // Walk the counts arrays to compute the U statistic. + // At each bucket index, values from histogram 1 at index i "beat" + // all values from histogram 2 at indices < i (concordant pairs). + int32_t len = + std::max(histogram_->counts_len, other.histogram_->counts_len); + + // Forward pass: count concordant pairs (h1 values > h2 values). + int64_t cum2 = 0; + double concordant = 0.0; + double tied = 0.0; + for (int32_t i = 0; i < len; i++) { + int64_t c1 = (i < histogram_->counts_len) ? histogram_->counts[i] : 0; + int64_t c2 = + (i < other.histogram_->counts_len) ? other.histogram_->counts[i] : 0; + concordant += static_cast(c1) * static_cast(cum2); + tied += static_cast(c1) * static_cast(c2); + cum2 += c2; + } + + // U statistic for sample 1: concordant + half of ties. + double u = concordant + 0.5 * tied; + double dn1 = static_cast(n1); + double dn2 = static_cast(n2); + double mu = dn1 * dn2 / 2.0; + + // Tie correction for the variance. + // sigma^2 = n1*n2/12 * (N+1 - sum(t_k^3 - t_k) / (N*(N-1))) + // where t_k is the number of observations tied at rank k. + double n_total = dn1 + dn2; + double tie_correction = 0.0; + for (int32_t i = 0; i < len; i++) { + int64_t c1 = (i < histogram_->counts_len) ? histogram_->counts[i] : 0; + int64_t c2 = + (i < other.histogram_->counts_len) ? other.histogram_->counts[i] : 0; + double tk = static_cast(c1 + c2); + if (tk > 1) { + tie_correction += tk * tk * tk - tk; + } + } + + double sigma_sq = + (dn1 * dn2 / 12.0) * + (n_total + 1.0 - tie_correction / (n_total * (n_total - 1.0))); + if (sigma_sq <= 0.0) return {u, 0, 1}; + + // Continuity-corrected z-score. + double z = (u - mu) / std::sqrt(sigma_sq); + // Two-tailed p-value using normal approximation. + double p = 2.0 * NormalCdf(-std::fabs(z)); + + return {u, z, p}; + }; + + if (this == &other) return {0, 0, 1}; + + if (this < &other) { + RwLock::ScopedReadLock lock1(mutex_); + RwLock::ScopedReadLock lock2(other.mutex_); + return do_mw(); + } + + RwLock::ScopedReadLock lock1(other.mutex_); + RwLock::ScopedReadLock lock2(mutex_); + return do_mw(); +} + +double Histogram::CohensD(const Histogram& other) const { + auto do_cohens = [&]() -> double { + int64_t n1 = histogram_->total_count; + int64_t n2 = other.histogram_->total_count; + if (n1 < 2 || n2 < 2) return 0.0; + + double mean1 = hdr_mean(histogram_.get()); + double mean2 = hdr_mean(other.histogram_.get()); + double sd1 = hdr_stddev(histogram_.get()); + double sd2 = hdr_stddev(other.histogram_.get()); + + // Convert population variance to sample variance (Bessel's correction). + double var1 = + sd1 * sd1 * static_cast(n1) / static_cast(n1 - 1); + double var2 = + sd2 * sd2 * static_cast(n2) / static_cast(n2 - 1); + + double pooled_sd = std::sqrt((static_cast(n1 - 1) * var1 + + static_cast(n2 - 1) * var2) / + static_cast(n1 + n2 - 2)); + if (pooled_sd == 0.0) return 0.0; + + return (mean1 - mean2) / pooled_sd; + }; + + if (this == &other) return 0.0; + + if (this < &other) { + RwLock::ScopedReadLock lock1(mutex_); + RwLock::ScopedReadLock lock2(other.mutex_); + return do_cohens(); + } + + RwLock::ScopedReadLock lock1(other.mutex_); + RwLock::ScopedReadLock lock2(mutex_); + return do_cohens(); +} + +double Histogram::CliffsD(const Histogram& other) const { + auto do_cliffs = [&]() -> double { + int64_t n1 = histogram_->total_count; + int64_t n2 = other.histogram_->total_count; + if (n1 == 0 || n2 == 0) return 0.0; + + int32_t len = + std::max(histogram_->counts_len, other.histogram_->counts_len); + + // Forward pass: count pairs where h1 value > h2 value (concordant). + int64_t cum2 = 0; + double concordant = 0.0; + double tied = 0.0; + for (int32_t i = 0; i < len; i++) { + int64_t c1 = (i < histogram_->counts_len) ? histogram_->counts[i] : 0; + int64_t c2 = + (i < other.histogram_->counts_len) ? other.histogram_->counts[i] : 0; + concordant += static_cast(c1) * static_cast(cum2); + tied += static_cast(c1) * static_cast(c2); + cum2 += c2; + } + + double discordant = + static_cast(n1) * static_cast(n2) - concordant - tied; + + return (concordant - discordant) / + (static_cast(n1) * static_cast(n2)); + }; + + if (this == &other) return 0.0; + + if (this < &other) { + RwLock::ScopedReadLock lock1(mutex_); + RwLock::ScopedReadLock lock2(other.mutex_); + return do_cliffs(); + } + + RwLock::ScopedReadLock lock1(other.mutex_); + RwLock::ScopedReadLock lock2(mutex_); + return do_cliffs(); +} + +Histogram::PercentileCIResult Histogram::PercentileCI(double percentile, + double confidence) const { + RwLock::ScopedReadLock lock(mutex_); + + int64_t value = hdr_value_at_percentile(histogram_.get(), percentile); + int64_t n = histogram_->total_count; + + if (n < 2) { + return {value, value, value}; + } + + double p = percentile / 100.0; + double alpha = 1.0 - confidence; + + // Lower rank: largest j such that BinomialCdf(j-1, n, p) <= alpha/2. + // Binary search over [0, n]. + int64_t lo = 0; + int64_t hi = n; + while (lo < hi) { + int64_t mid = lo + (hi - lo + 1) / 2; + if (BinomialCdf(mid - 1, n, p) <= alpha / 2.0) { + lo = mid; + } else { + hi = mid - 1; + } + } + double lower_pct = static_cast(lo) / static_cast(n) * 100.0; + + // Upper rank: smallest k such that BinomialCdf(k-1, n, p) >= 1 - alpha/2. + lo = 0; + hi = n; + while (lo < hi) { + int64_t mid = lo + (hi - lo) / 2; + if (BinomialCdf(mid - 1, n, p) >= 1.0 - alpha / 2.0) { + hi = mid; + } else { + lo = mid + 1; + } + } + double upper_pct = static_cast(lo) / static_cast(n) * 100.0; + + int64_t lower_val = hdr_value_at_percentile(histogram_.get(), lower_pct); + int64_t upper_val = hdr_value_at_percentile(histogram_.get(), upper_pct); + + return {value, lower_val, upper_val}; +} + HistogramImpl::HistogramImpl(const Histogram::Options& options) : histogram_(new Histogram(options)) {} @@ -74,6 +612,20 @@ CFunction HistogramImpl::fast_get_stddev_( CFunction::Make(&HistogramImpl::FastGetStddev)); CFunction HistogramImpl::fast_get_percentile_( CFunction::Make(&HistogramImpl::FastGetPercentile)); +CFunction HistogramImpl::fast_get_skewness_( + CFunction::Make(&HistogramImpl::FastGetSkewness)); +CFunction HistogramImpl::fast_get_kurtosis_( + CFunction::Make(&HistogramImpl::FastGetKurtosis)); +CFunction HistogramImpl::fast_get_cdf_( + CFunction::Make(&HistogramImpl::FastGetCdf)); +CFunction HistogramImpl::fast_get_count_at_( + CFunction::Make(&HistogramImpl::FastGetCountAt)); +CFunction HistogramImpl::fast_get_ewma_mean_( + CFunction::Make(&HistogramImpl::FastGetEwmaMean)); +CFunction HistogramImpl::fast_get_ewma_stddev_( + CFunction::Make(&HistogramImpl::FastGetEwmaStddev)); +CFunction HistogramImpl::fast_get_ewma_error_rate_( + CFunction::Make(&HistogramImpl::FastGetEwmaErrorRate)); CFunction HistogramBase::fast_record_( CFunction::Make(&HistogramBase::FastRecord)); CFunction HistogramBase::fast_record_delta_( @@ -112,6 +664,32 @@ void HistogramImpl::AddMethods(Isolate* isolate, Local tmpl) { isolate, instance, "stddev", GetStddev, &fast_get_stddev_); SetFastMethodNoSideEffect( isolate, instance, "percentile", GetPercentile, &fast_get_percentile_); + SetFastMethodNoSideEffect( + isolate, instance, "skewness", GetSkewness, &fast_get_skewness_); + SetFastMethodNoSideEffect( + isolate, instance, "kurtosis", GetKurtosis, &fast_get_kurtosis_); + SetFastMethodNoSideEffect(isolate, instance, "cdf", GetCdf, &fast_get_cdf_); + SetFastMethodNoSideEffect( + isolate, instance, "countAt", GetCountAt, &fast_get_count_at_); + SetProtoMethodNoSideEffect(isolate, tmpl, "ksTest", GetKsTest); + SetProtoMethodNoSideEffect(isolate, tmpl, "percentilesAt", GetPercentilesAt); + SetProtoMethodNoSideEffect(isolate, tmpl, "linearBuckets", GetLinearBuckets); + SetProtoMethodNoSideEffect(isolate, tmpl, "logBuckets", GetLogBuckets); + SetProtoMethodNoSideEffect(isolate, tmpl, "welchTest", GetWelchTest); + SetProtoMethodNoSideEffect( + isolate, tmpl, "mannWhitneyTest", GetMannWhitneyTest); + SetProtoMethodNoSideEffect(isolate, tmpl, "cohensD", GetCohensD); + SetProtoMethodNoSideEffect(isolate, tmpl, "cliffsD", GetCliffsD); + SetProtoMethodNoSideEffect(isolate, tmpl, "percentileCI", GetPercentileCI); + SetFastMethodNoSideEffect( + isolate, instance, "ewmaMean", GetEwmaMean, &fast_get_ewma_mean_); + SetFastMethodNoSideEffect( + isolate, instance, "ewmaStddev", GetEwmaStddev, &fast_get_ewma_stddev_); + SetFastMethodNoSideEffect(isolate, + instance, + "ewmaErrorRate", + GetEwmaErrorRate, + &fast_get_ewma_error_rate_); SetFastMethod(isolate, instance, "reset", DoReset, &fast_reset_); } @@ -142,6 +720,29 @@ void HistogramImpl::RegisterExternalReferences( registry->Register(fast_get_exceeds_); registry->Register(fast_get_stddev_); registry->Register(fast_get_percentile_); + registry->Register(GetSkewness); + registry->Register(GetKurtosis); + registry->Register(GetCdf); + registry->Register(GetCountAt); + registry->Register(GetKsTest); + registry->Register(GetPercentilesAt); + registry->Register(GetLinearBuckets); + registry->Register(GetLogBuckets); + registry->Register(GetWelchTest); + registry->Register(GetMannWhitneyTest); + registry->Register(GetCohensD); + registry->Register(GetCliffsD); + registry->Register(GetPercentileCI); + registry->Register(GetEwmaMean); + registry->Register(GetEwmaStddev); + registry->Register(GetEwmaErrorRate); + registry->Register(fast_get_ewma_mean_); + registry->Register(fast_get_ewma_stddev_); + registry->Register(fast_get_ewma_error_rate_); + registry->Register(fast_get_skewness_); + registry->Register(fast_get_kurtosis_); + registry->Register(fast_get_cdf_); + registry->Register(fast_get_count_at_); is_registered = true; } @@ -221,6 +822,39 @@ void HistogramBase::Add(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(count); } +void HistogramBase::Subtract(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + HistogramBase* histogram; + ASSIGN_OR_RETURN_UNWRAP(&histogram, args.This()); + + CHECK(GetConstructorTemplate(env->isolate_data())->HasInstance(args[0])); + HistogramBase* other; + ASSIGN_OR_RETURN_UNWRAP(&other, args[0]); + + double dropped = (*histogram)->Subtract(*(other->histogram())); + args.GetReturnValue().Set(dropped); +} + +void HistogramBase::RecordCorrected(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + CHECK_IMPLIES(!args[0]->IsNumber(), args[0]->IsBigInt()); + CHECK_IMPLIES(!args[1]->IsNumber(), args[1]->IsBigInt()); + bool lossless = true; + int64_t value = args[0]->IsBigInt() + ? args[0].As()->Int64Value(&lossless) + : static_cast(args[0].As()->Value()); + if (!lossless || value < 1) + return THROW_ERR_OUT_OF_RANGE(env, "value is out of range"); + int64_t expected_interval = + args[1]->IsBigInt() ? args[1].As()->Int64Value(&lossless) + : static_cast(args[1].As()->Value()); + if (!lossless || expected_interval < 1) + return THROW_ERR_OUT_OF_RANGE(env, "expected_interval is out of range"); + HistogramBase* histogram; + ASSIGN_OR_RETURN_UNWRAP(&histogram, args.This()); + (*histogram)->RecordCorrected(value, expected_interval); +} + BaseObjectPtr HistogramBase::Create( Environment* env, const Histogram::Options& options) { @@ -259,24 +893,37 @@ void HistogramBase::New(const FunctionCallbackInfo& args) { int64_t lowest = 1; int64_t highest = std::numeric_limits::max(); - bool lossless_ignored; + bool lossless = true; if (args[0]->IsNumber()) { lowest = args[0].As()->Value(); } else if (args[0]->IsBigInt()) { - lowest = args[0].As()->Int64Value(&lossless_ignored); + lowest = args[0].As()->Int64Value(&lossless); + if (!lossless) + return THROW_ERR_OUT_OF_RANGE(env, "options.lowest is out of range"); } if (args[1]->IsNumber()) { highest = args[1].As()->Value(); } else if (args[1]->IsBigInt()) { - highest = args[1].As()->Int64Value(&lossless_ignored); + highest = args[1].As()->Int64Value(&lossless); + if (!lossless) + return THROW_ERR_OUT_OF_RANGE(env, "options.highest is out of range"); } int32_t figures = args[2].As()->Value(); - new HistogramBase(env, args.This(), Histogram::Options { - lowest, highest, figures - }); + double half_life = 0; + if (args.Length() > 3 && args[3]->IsNumber()) { + half_life = args[3].As()->Value(); + } + int64_t threshold = 0; + if (args.Length() > 4 && args[4]->IsNumber()) { + threshold = static_cast(args[4].As()->Value()); + } + new HistogramBase( + env, + args.This(), + Histogram::Options{lowest, highest, figures, half_life, threshold}); } Local HistogramBase::GetConstructorTemplate( @@ -293,6 +940,8 @@ Local HistogramBase::GetConstructorTemplate( SetFastMethod( isolate, instance, "recordDelta", RecordDelta, &fast_record_delta_); SetProtoMethod(isolate, tmpl, "add", Add); + SetProtoMethod(isolate, tmpl, "subtract", Subtract); + SetProtoMethod(isolate, tmpl, "recordCorrected", RecordCorrected); HistogramImpl::AddMethods(isolate, tmpl); isolate_data->set_histogram_ctor_template(tmpl); } @@ -303,8 +952,10 @@ void HistogramBase::RegisterExternalReferences( ExternalReferenceRegistry* registry) { registry->Register(New); registry->Register(Add); + registry->Register(Subtract); registry->Register(Record); registry->Register(RecordDelta); + registry->Register(RecordCorrected); registry->Register(fast_record_); registry->Register(fast_record_delta_); HistogramImpl::RegisterExternalReferences(registry); @@ -343,11 +994,7 @@ Local IntervalHistogram::GetConstructorTemplate( tmpl = NewFunctionTemplate(isolate, nullptr); tmpl->Inherit(HandleWrap::GetConstructorTemplate(env)); tmpl->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "Histogram")); - auto instance = tmpl->InstanceTemplate(); - instance->SetInternalFieldCount(IntervalHistogram::kInternalFieldCount); - HistogramImpl::AddMethods(isolate, tmpl); - SetFastMethod(isolate, instance, "start", Start, &fast_start_); - SetFastMethod(isolate, instance, "stop", Stop, &fast_stop_); + InitTemplate(isolate, tmpl, IntervalHistogram::kInternalFieldCount); env->set_intervalhistogram_constructor_template(tmpl); } return tmpl; @@ -362,21 +1009,16 @@ void IntervalHistogram::RegisterExternalReferences( HistogramImpl::RegisterExternalReferences(registry); } -IntervalHistogram::IntervalHistogram( - Environment* env, - Local wrap, - AsyncWrap::ProviderType type, - int32_t interval, - std::function on_interval, - const Histogram::Options& options) - : HandleWrap( - env, - wrap, - reinterpret_cast(&timer_), - type), +IntervalHistogram::IntervalHistogram(Environment* env, + Local wrap, + AsyncWrap::ProviderType type, + int32_t interval, + OnInterval on_interval, + const Histogram::Options& options) + : HandleWrap(env, wrap, reinterpret_cast(&timer_), type), HistogramImpl(options), interval_(interval), - on_interval_(std::move(on_interval)) { + on_interval_(on_interval) { MakeWeak(); wrap->SetAlignedPointerInInternalField( HistogramImpl::InternalFields::kImplField, @@ -387,8 +1029,9 @@ IntervalHistogram::IntervalHistogram( BaseObjectPtr IntervalHistogram::Create( Environment* env, int32_t interval, - std::function on_interval, - const Histogram::Options& options) { + OnInterval on_interval, + const Histogram::Options& options, + AsyncWrap::ProviderType type) { Local obj; if (!GetConstructorTemplate(env) ->InstanceTemplate() @@ -397,12 +1040,7 @@ BaseObjectPtr IntervalHistogram::Create( } return MakeBaseObject( - env, - obj, - AsyncWrap::PROVIDER_ELDHISTOGRAM, - interval, - std::move(on_interval), - options); + env, obj, type, interval, on_interval, options); } void IntervalHistogram::TimerCB(uv_timer_t* handle) { @@ -433,19 +1071,11 @@ void IntervalHistogram::OnStop() { uv_timer_stop(&timer_); } -void IntervalHistogram::Start(const FunctionCallbackInfo& args) { - StartHandleHistogram(args.This(), args[0]->IsTrue()); -} - void IntervalHistogram::FastStart(Local receiver, bool reset) { TRACK_V8_FAST_API_CALL("histogram.start"); StartHandleHistogram(receiver, reset); } -void IntervalHistogram::Stop(const FunctionCallbackInfo& args) { - StopHandleHistogram(args.This()); -} - void IntervalHistogram::FastStop(Local receiver) { TRACK_V8_FAST_API_CALL("histogram.stop"); StopHandleHistogram(receiver); @@ -459,11 +1089,7 @@ Local IterationHistogram::GetConstructorTemplate( tmpl = NewFunctionTemplate(isolate, nullptr); tmpl->Inherit(HandleWrap::GetConstructorTemplate(env)); tmpl->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "Histogram")); - auto instance = tmpl->InstanceTemplate(); - instance->SetInternalFieldCount(IterationHistogram::kInternalFieldCount); - HistogramImpl::AddMethods(isolate, tmpl); - SetFastMethod(isolate, instance, "start", Start, &fast_start_); - SetFastMethod(isolate, instance, "stop", Stop, &fast_stop_); + InitTemplate(isolate, tmpl, IterationHistogram::kInternalFieldCount); env->set_iterationhistogram_constructor_template(tmpl); } return tmpl; @@ -493,11 +1119,12 @@ IterationHistogram::IterationHistogram(Environment* env, uv_prepare_init(env->event_loop(), &prepare_handle_); uv_unref(reinterpret_cast(&check_handle_)); uv_unref(reinterpret_cast(&prepare_handle_)); - prepare_handle_.data = this; } BaseObjectPtr IterationHistogram::Create( - Environment* env, const Histogram::Options& options) { + Environment* env, + const Histogram::Options& options, + AsyncWrap::ProviderType type) { Local obj; if (!GetConstructorTemplate(env) ->InstanceTemplate() @@ -506,12 +1133,12 @@ BaseObjectPtr IterationHistogram::Create( return nullptr; } - return MakeBaseObject( - env, obj, AsyncWrap::PROVIDER_ELDHISTOGRAM, options); + return MakeBaseObject(env, obj, type, options); } void IterationHistogram::PrepareCB(uv_prepare_t* handle) { - IterationHistogram* self = static_cast(handle->data); + IterationHistogram* self = + ContainerOf(&IterationHistogram::prepare_handle_, handle); if (!self->enabled_) return; self->prepare_time_ = uv_hrtime(); self->timeout_ = uv_backend_timeout(handle->loop); @@ -568,19 +1195,11 @@ void IterationHistogram::Close(Local close_callback) { uv_close(reinterpret_cast(&prepare_handle_), nullptr); } -void IterationHistogram::Start(const FunctionCallbackInfo& args) { - StartHandleHistogram(args.This(), args[0]->IsTrue()); -} - void IterationHistogram::FastStart(Local receiver, bool reset) { TRACK_V8_FAST_API_CALL("histogram.eventLoopDelay.start"); StartHandleHistogram(receiver, reset); } -void IterationHistogram::Stop(const FunctionCallbackInfo& args) { - StopHandleHistogram(args.This()); -} - void IterationHistogram::FastStop(Local receiver) { TRACK_V8_FAST_API_CALL("histogram.eventLoopDelay.stop"); StopHandleHistogram(receiver); @@ -666,12 +1285,19 @@ void HistogramImpl::GetPercentiles(const FunctionCallbackInfo& args) { HistogramImpl* histogram = HistogramImpl::FromJSObject(args.This()); CHECK(args[0]->IsMap()); Local map = args[0].As(); - (*histogram)->Percentiles([map, env](double key, int64_t value) { - USE(map->Set( - env->context(), - Number::New(env->isolate(), key), - Number::New(env->isolate(), static_cast(value)))); + + // Collect percentile data under the histogram lock, then populate the + // V8 Map after releasing it to avoid V8 allocations under the lock. + std::vector> entries; + (*histogram)->Percentiles([&entries](double key, int64_t value) { + entries.emplace_back(key, value); }); + for (const auto& entry : entries) { + USE(map->Set( + env->context(), + Number::New(env->isolate(), entry.first), + Number::New(env->isolate(), static_cast(entry.second)))); + } } void HistogramImpl::GetPercentilesBigInt( @@ -680,12 +1306,16 @@ void HistogramImpl::GetPercentilesBigInt( HistogramImpl* histogram = HistogramImpl::FromJSObject(args.This()); CHECK(args[0]->IsMap()); Local map = args[0].As(); - (*histogram)->Percentiles([map, env](double key, int64_t value) { - USE(map->Set( - env->context(), - Number::New(env->isolate(), key), - BigInt::New(env->isolate(), value))); + + std::vector> entries; + (*histogram)->Percentiles([&entries](double key, int64_t value) { + entries.emplace_back(key, value); }); + for (const auto& entry : entries) { + USE(map->Set(env->context(), + Number::New(env->isolate(), entry.first), + BigInt::New(env->isolate(), entry.second))); + } } void HistogramImpl::DoReset(const FunctionCallbackInfo& args) { @@ -742,6 +1372,225 @@ double HistogramImpl::FastGetPercentile(Local receiver, return static_cast((*histogram)->Percentile(percentile)); } +void HistogramImpl::GetSkewness(const FunctionCallbackInfo& args) { + HistogramImpl* histogram = HistogramImpl::FromJSObject(args.This()); + args.GetReturnValue().Set((*histogram)->Skewness()); +} + +double HistogramImpl::FastGetSkewness(Local receiver) { + TRACK_V8_FAST_API_CALL("histogram.skewness"); + HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver); + return (*histogram)->Skewness(); +} + +void HistogramImpl::GetKurtosis(const FunctionCallbackInfo& args) { + HistogramImpl* histogram = HistogramImpl::FromJSObject(args.This()); + args.GetReturnValue().Set((*histogram)->Kurtosis()); +} + +double HistogramImpl::FastGetKurtosis(Local receiver) { + TRACK_V8_FAST_API_CALL("histogram.kurtosis"); + HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver); + return (*histogram)->Kurtosis(); +} + +void HistogramImpl::GetCdf(const FunctionCallbackInfo& args) { + HistogramImpl* histogram = HistogramImpl::FromJSObject(args.This()); + CHECK(args[0]->IsNumber()); + int64_t value = static_cast(args[0].As()->Value()); + args.GetReturnValue().Set((*histogram)->Cdf(value)); +} + +double HistogramImpl::FastGetCdf(Local receiver, const int64_t value) { + TRACK_V8_FAST_API_CALL("histogram.cdf"); + HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver); + return (*histogram)->Cdf(value); +} + +void HistogramImpl::GetCountAt(const FunctionCallbackInfo& args) { + HistogramImpl* histogram = HistogramImpl::FromJSObject(args.This()); + CHECK(args[0]->IsNumber()); + int64_t value = static_cast(args[0].As()->Value()); + double count = static_cast((*histogram)->CountAt(value)); + args.GetReturnValue().Set(count); +} + +double HistogramImpl::FastGetCountAt(Local receiver, + const int64_t value) { + TRACK_V8_FAST_API_CALL("histogram.countAt"); + HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver); + return static_cast((*histogram)->CountAt(value)); +} + +void HistogramImpl::GetKsTest(const FunctionCallbackInfo& args) { + HistogramImpl* histogram = HistogramImpl::FromJSObject(args.This()); + HistogramImpl* other = HistogramImpl::FromJSObject(args[0]); + args.GetReturnValue().Set((*histogram)->KsTest(*(other->histogram()))); +} + +void HistogramImpl::GetWelchTest(const FunctionCallbackInfo& args) { + Isolate* isolate = args.GetIsolate(); + HistogramImpl* histogram = HistogramImpl::FromJSObject(args.This()); + HistogramImpl* other = HistogramImpl::FromJSObject(args[0]); + CHECK(args[1]->IsNumber()); + double confidence = args[1].As()->Value(); + + auto result = (*histogram)->WelchTest(*(other->histogram()), confidence); + + Local values[] = {Number::New(isolate, result.t_statistic), + Number::New(isolate, result.degrees_of_freedom), + Number::New(isolate, result.p_value), + Number::New(isolate, result.ci_lower), + Number::New(isolate, result.ci_upper)}; + Local arr = Array::New(isolate, &values[0], arraysize(values)); + args.GetReturnValue().Set(arr); +} + +void HistogramImpl::GetMannWhitneyTest( + const FunctionCallbackInfo& args) { + Isolate* isolate = args.GetIsolate(); + HistogramImpl* histogram = HistogramImpl::FromJSObject(args.This()); + HistogramImpl* other = HistogramImpl::FromJSObject(args[0]); + + auto result = (*histogram)->MannWhitneyTest(*(other->histogram())); + + Local values[] = {Number::New(isolate, result.u_statistic), + Number::New(isolate, result.z_score), + Number::New(isolate, result.p_value)}; + Local arr = Array::New(isolate, &values[0], arraysize(values)); + args.GetReturnValue().Set(arr); +} + +void HistogramImpl::GetCohensD(const FunctionCallbackInfo& args) { + HistogramImpl* histogram = HistogramImpl::FromJSObject(args.This()); + HistogramImpl* other = HistogramImpl::FromJSObject(args[0]); + args.GetReturnValue().Set((*histogram)->CohensD(*(other->histogram()))); +} + +void HistogramImpl::GetCliffsD(const FunctionCallbackInfo& args) { + HistogramImpl* histogram = HistogramImpl::FromJSObject(args.This()); + HistogramImpl* other = HistogramImpl::FromJSObject(args[0]); + args.GetReturnValue().Set((*histogram)->CliffsD(*(other->histogram()))); +} + +void HistogramImpl::GetPercentileCI(const FunctionCallbackInfo& args) { + Isolate* isolate = args.GetIsolate(); + HistogramImpl* histogram = HistogramImpl::FromJSObject(args.This()); + CHECK(args[0]->IsNumber()); + CHECK(args[1]->IsNumber()); + double percentile = args[0].As()->Value(); + double confidence = args[1].As()->Value(); + + auto result = (*histogram)->PercentileCI(percentile, confidence); + + Local values[] = { + Number::New(isolate, static_cast(result.value)), + Number::New(isolate, static_cast(result.lower)), + Number::New(isolate, static_cast(result.upper))}; + Local arr = Array::New(isolate, &values[0], arraysize(values)); + args.GetReturnValue().Set(arr); +} + +void HistogramImpl::GetEwmaMean(const FunctionCallbackInfo& args) { + HistogramImpl* histogram = HistogramImpl::FromJSObject(args.This()); + args.GetReturnValue().Set((*histogram)->EwmaMean()); +} + +double HistogramImpl::FastGetEwmaMean(Local receiver) { + TRACK_V8_FAST_API_CALL("histogram.ewmaMean"); + HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver); + return (*histogram)->EwmaMean(); +} + +void HistogramImpl::GetEwmaStddev(const FunctionCallbackInfo& args) { + HistogramImpl* histogram = HistogramImpl::FromJSObject(args.This()); + args.GetReturnValue().Set((*histogram)->EwmaStddev()); +} + +double HistogramImpl::FastGetEwmaStddev(Local receiver) { + TRACK_V8_FAST_API_CALL("histogram.ewmaStddev"); + HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver); + return (*histogram)->EwmaStddev(); +} + +void HistogramImpl::GetEwmaErrorRate(const FunctionCallbackInfo& args) { + HistogramImpl* histogram = HistogramImpl::FromJSObject(args.This()); + args.GetReturnValue().Set((*histogram)->EwmaErrorRate()); +} + +double HistogramImpl::FastGetEwmaErrorRate(Local receiver) { + TRACK_V8_FAST_API_CALL("histogram.ewmaErrorRate"); + HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver); + return (*histogram)->EwmaErrorRate(); +} + +void HistogramImpl::GetPercentilesAt(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + HistogramImpl* histogram = HistogramImpl::FromJSObject(args.This()); + CHECK(args[0]->IsMap()); + Local map = args[0].As(); + CHECK(args[1]->IsFloat64Array()); + Local input = args[1].As(); + size_t length = input->Length(); + auto backing = input->Buffer()->GetBackingStore(); + double* percentiles = reinterpret_cast( + static_cast(backing->Data()) + input->ByteOffset()); + + std::vector values(length); + (*histogram)->PercentilesAt(percentiles, values.data(), length); + + for (size_t i = 0; i < length; i++) { + USE(map->Set(env->context(), + Number::New(env->isolate(), percentiles[i]), + Number::New(env->isolate(), static_cast(values[i])))); + } +} + +void HistogramImpl::GetLinearBuckets(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + HistogramImpl* histogram = HistogramImpl::FromJSObject(args.This()); + CHECK(args[0]->IsNumber()); + CHECK(args[1]->IsMap()); + int64_t step_size = static_cast(args[0].As()->Value()); + Local map = args[1].As(); + + std::vector> entries; + (*histogram) + ->LinearBuckets(step_size, [&entries](int64_t value, int64_t count) { + entries.emplace_back(value, count); + }); + for (const auto& entry : entries) { + USE(map->Set( + env->context(), + Number::New(env->isolate(), static_cast(entry.first)), + Number::New(env->isolate(), static_cast(entry.second)))); + } +} + +void HistogramImpl::GetLogBuckets(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + HistogramImpl* histogram = HistogramImpl::FromJSObject(args.This()); + CHECK(args[0]->IsNumber()); + CHECK(args[1]->IsNumber()); + CHECK(args[2]->IsMap()); + int64_t first_bucket = static_cast(args[0].As()->Value()); + double log_base = args[1].As()->Value(); + Local map = args[2].As(); + + std::vector> entries; + (*histogram) + ->LogBuckets( + first_bucket, log_base, [&entries](int64_t value, int64_t count) { + entries.emplace_back(value, count); + }); + for (const auto& entry : entries) { + USE(map->Set( + env->context(), + Number::New(env->isolate(), static_cast(entry.first)), + Number::New(env->isolate(), static_cast(entry.second)))); + } +} + HistogramImpl* HistogramImpl::FromJSObject(Local value) { auto obj = value.As(); DCHECK_GE(obj->InternalFieldCount(), HistogramImpl::kInternalFieldCount); diff --git a/src/histogram.h b/src/histogram.h index b9f968e8347c..31a2e9833d3e 100644 --- a/src/histogram.h +++ b/src/histogram.h @@ -11,10 +11,7 @@ #include "uv.h" #include "v8.h" -#include #include -#include -#include namespace node { @@ -33,6 +30,10 @@ class Histogram : public MemoryRetainer { int64_t lowest = 1; int64_t highest = std::numeric_limits::max(); int figures = kDefaultHistogramFigures; + double half_life = 0; // EWMA half-life in number of samples (0 = off) + int64_t threshold = 0; // SLO threshold (0 = off). When set with + // half_life, tracks EWMA error rate for values + // exceeding this threshold. }; explicit Histogram(const Options& options); @@ -44,8 +45,11 @@ class Histogram : public MemoryRetainer { inline int64_t Max() const; inline double Mean() const; inline double Stddev() const; + inline double EwmaMean() const; + inline double EwmaStddev() const; + inline double EwmaErrorRate() const; inline int64_t Percentile(double percentile) const; - inline size_t Exceeds() const { return exceeds_; } + inline size_t Exceeds() const; inline size_t Count() const; inline uint64_t RecordDelta(); @@ -55,21 +59,83 @@ class Histogram : public MemoryRetainer { // Iterator is a function type that takes two doubles as argument, one for // percentile and one for the value at that percentile. template - inline void Percentiles(Iterator&& fn); + inline void Percentiles(Iterator&& fn) const; inline size_t GetMemorySize() const; + // Analysis methods + inline int64_t CountAt(int64_t value) const; + double Cdf(int64_t value) const; + double Skewness() const; + double Kurtosis() const; + double KsTest(const Histogram& other) const; + double Subtract(const Histogram& other); + void PercentilesAt(const double* percentiles, + int64_t* values, + size_t length) const; + + // Statistical hypothesis testing + struct WelchTestResult { + double t_statistic; + double degrees_of_freedom; + double p_value; + double ci_lower; + double ci_upper; + }; + + struct MannWhitneyResult { + double u_statistic; + double z_score; + double p_value; + }; + + struct PercentileCIResult { + int64_t value; + int64_t lower; + int64_t upper; + }; + + WelchTestResult WelchTest(const Histogram& other, + double confidence = 0.95) const; + MannWhitneyResult MannWhitneyTest(const Histogram& other) const; + double CohensD(const Histogram& other) const; + double CliffsD(const Histogram& other) const; + PercentileCIResult PercentileCI(double percentile, + double confidence = 0.95) const; + + inline bool RecordCorrected(int64_t value, int64_t expected_interval); + + template + void LinearBuckets(int64_t step_size, Iterator&& fn) const; + + template + void LogBuckets(int64_t first_bucket, double log_base, Iterator&& fn) const; + + bool IsCompatible(const Histogram& other) const; + void MemoryInfo(MemoryTracker* tracker) const override; SET_MEMORY_INFO_NAME(Histogram) SET_SELF_SIZE(Histogram) private: + inline void UpdateEwma(double value); + using HistogramPointer = DeleteFnPtr; HistogramPointer histogram_; uint64_t prev_ = 0; size_t exceeds_ = 0; - size_t count_ = 0; - Mutex mutex_; + + // EWMA state (active when ewma_alpha_ > 0) + double ewma_alpha_ = 0; + double ewma_mean_ = 0; + double ewma_variance_ = 0; + bool ewma_initialized_ = false; + + // SLO error rate EWMA (active when threshold_ > 0 and ewma_alpha_ > 0) + int64_t threshold_ = 0; + double ewma_error_rate_ = 0; + + RwLock mutex_; }; class HistogramImpl { @@ -106,6 +172,24 @@ class HistogramImpl { static void GetPercentilesBigInt( const v8::FunctionCallbackInfo& args); + static void GetSkewness(const v8::FunctionCallbackInfo& args); + static void GetKurtosis(const v8::FunctionCallbackInfo& args); + static void GetCdf(const v8::FunctionCallbackInfo& args); + static void GetCountAt(const v8::FunctionCallbackInfo& args); + static void GetKsTest(const v8::FunctionCallbackInfo& args); + static void GetPercentilesAt(const v8::FunctionCallbackInfo& args); + static void GetLinearBuckets(const v8::FunctionCallbackInfo& args); + static void GetLogBuckets(const v8::FunctionCallbackInfo& args); + static void GetWelchTest(const v8::FunctionCallbackInfo& args); + static void GetMannWhitneyTest( + const v8::FunctionCallbackInfo& args); + static void GetCohensD(const v8::FunctionCallbackInfo& args); + static void GetCliffsD(const v8::FunctionCallbackInfo& args); + static void GetPercentileCI(const v8::FunctionCallbackInfo& args); + static void GetEwmaMean(const v8::FunctionCallbackInfo& args); + static void GetEwmaStddev(const v8::FunctionCallbackInfo& args); + static void GetEwmaErrorRate(const v8::FunctionCallbackInfo& args); + static void FastReset(v8::Local receiver); static double FastGetCount(v8::Local receiver); static double FastGetMin(v8::Local receiver); @@ -115,6 +199,14 @@ class HistogramImpl { static double FastGetStddev(v8::Local receiver); static double FastGetPercentile(v8::Local receiver, const double percentile); + static double FastGetSkewness(v8::Local receiver); + static double FastGetKurtosis(v8::Local receiver); + static double FastGetCdf(v8::Local receiver, const int64_t value); + static double FastGetCountAt(v8::Local receiver, + const int64_t value); + static double FastGetEwmaMean(v8::Local receiver); + static double FastGetEwmaStddev(v8::Local receiver); + static double FastGetEwmaErrorRate(v8::Local receiver); static void AddMethods(v8::Isolate* isolate, v8::Local tmpl); @@ -134,6 +226,13 @@ class HistogramImpl { static v8::CFunction fast_get_exceeds_; static v8::CFunction fast_get_stddev_; static v8::CFunction fast_get_percentile_; + static v8::CFunction fast_get_skewness_; + static v8::CFunction fast_get_kurtosis_; + static v8::CFunction fast_get_cdf_; + static v8::CFunction fast_get_count_at_; + static v8::CFunction fast_get_ewma_mean_; + static v8::CFunction fast_get_ewma_stddev_; + static v8::CFunction fast_get_ewma_error_rate_; }; class HistogramBase final : public BaseObject, public HistogramImpl { @@ -165,7 +264,9 @@ class HistogramBase final : public BaseObject, public HistogramImpl { static void Record(const v8::FunctionCallbackInfo& args); static void RecordDelta(const v8::FunctionCallbackInfo& args); + static void RecordCorrected(const v8::FunctionCallbackInfo& args); static void Add(const v8::FunctionCallbackInfo& args); + static void Subtract(const v8::FunctionCallbackInfo& args); static void FastRecord(v8::Local receiver, const int64_t value); static void FastRecordDelta(v8::Local receiver); @@ -211,17 +312,48 @@ class HistogramBase final : public BaseObject, public HistogramImpl { static v8::CFunction fast_record_delta_; }; -class IntervalHistogram final : public HandleWrap, public HistogramImpl { +// CRTP mixin for HandleWrap-based histograms with start/stop support. +// Provides: StartFlags enum, Start/Stop slow-path handlers, enabled_ flag, +// and InitTemplate (shared GetConstructorTemplate body). +// Derived must provide: fast_start_, fast_stop_ (static CFunction), +// FastStart, FastStop, OnStart, OnStop. +template +class HandleHistogramMixin { + public: + enum class StartFlags { NONE, RESET }; + + static void Start(const v8::FunctionCallbackInfo& args) { + StartHandleHistogram(args.This(), args[0]->IsTrue()); + } + + static void Stop(const v8::FunctionCallbackInfo& args) { + StopHandleHistogram(args.This()); + } + + protected: + static void InitTemplate(v8::Isolate* isolate, + v8::Local tmpl, + uint32_t internal_field_count) { + auto instance = tmpl->InstanceTemplate(); + instance->SetInternalFieldCount(internal_field_count); + HistogramImpl::AddMethods(isolate, tmpl); + SetFastMethod(isolate, instance, "start", Start, &Derived::fast_start_); + SetFastMethod(isolate, instance, "stop", Stop, &Derived::fast_stop_); + } + + bool enabled_ = false; +}; + +class IntervalHistogram final : public HandleWrap, + public HistogramImpl, + public HandleHistogramMixin { public: enum InternalFields { kInternalFieldCount = std::max( HandleWrap::kInternalFieldCount, HistogramImpl::kInternalFieldCount), }; - enum class StartFlags { - NONE, - RESET - }; + using OnInterval = void (*)(Histogram&); static void RegisterExternalReferences(ExternalReferenceRegistry* registry); @@ -231,19 +363,16 @@ class IntervalHistogram final : public HandleWrap, public HistogramImpl { static BaseObjectPtr Create( Environment* env, int32_t interval, - std::function on_interval, - const Histogram::Options& options); + OnInterval on_interval, + const Histogram::Options& options, + AsyncWrap::ProviderType type = AsyncWrap::PROVIDER_ELDHISTOGRAM); - IntervalHistogram( - Environment* env, - v8::Local wrap, - AsyncWrap::ProviderType type, - int32_t interval, - std::function on_interval, - const Histogram::Options& options = Histogram::Options {}); - - static void Start(const v8::FunctionCallbackInfo& args); - static void Stop(const v8::FunctionCallbackInfo& args); + IntervalHistogram(Environment* env, + v8::Local wrap, + AsyncWrap::ProviderType type, + int32_t interval, + OnInterval on_interval, + const Histogram::Options& options = Histogram::Options{}); static void FastStart(v8::Local receiver, bool reset); static void FastStop(v8::Local receiver); @@ -262,45 +391,45 @@ class IntervalHistogram final : public HandleWrap, public HistogramImpl { void OnStart(StartFlags flags = StartFlags::RESET); void OnStop(); + friend class HandleHistogramMixin; template friend void StartHandleHistogram(v8::Local, bool); template friend void StopHandleHistogram(v8::Local); - bool enabled_ = false; int32_t interval_ = 0; - std::function on_interval_; + OnInterval on_interval_ = nullptr; uv_timer_t timer_; static v8::CFunction fast_start_; static v8::CFunction fast_stop_; }; -class IterationHistogram final : public HandleWrap, public HistogramImpl { +class IterationHistogram final + : public HandleWrap, + public HistogramImpl, + public HandleHistogramMixin { public: enum InternalFields { kInternalFieldCount = std::max( HandleWrap::kInternalFieldCount, HistogramImpl::kInternalFieldCount), }; - enum class StartFlags { NONE, RESET }; - static void RegisterExternalReferences(ExternalReferenceRegistry* registry); static v8::Local GetConstructorTemplate( Environment* env); static BaseObjectPtr Create( - Environment* env, const Histogram::Options& options); + Environment* env, + const Histogram::Options& options, + AsyncWrap::ProviderType type = AsyncWrap::PROVIDER_ELDHISTOGRAM); IterationHistogram(Environment* env, v8::Local wrap, AsyncWrap::ProviderType type, const Histogram::Options& options = Histogram::Options{}); - static void Start(const v8::FunctionCallbackInfo& args); - static void Stop(const v8::FunctionCallbackInfo& args); - static void FastStart(v8::Local receiver, bool reset); static void FastStop(v8::Local receiver); @@ -322,12 +451,12 @@ class IterationHistogram final : public HandleWrap, public HistogramImpl { void OnStart(StartFlags flags = StartFlags::RESET); void OnStop(); + friend class HandleHistogramMixin; template friend void StartHandleHistogram(v8::Local, bool); template friend void StopHandleHistogram(v8::Local); - bool enabled_ = false; uv_prepare_t prepare_handle_; uv_check_t check_handle_; uint64_t prepare_time_ = 0; diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc index 5e1d9149dc75..1f86e4bfc265 100644 --- a/src/inspector_agent.cc +++ b/src/inspector_agent.cc @@ -547,11 +547,7 @@ class NodeInspectorClient : public V8InspectorClient { return; } if (auto agent = env_->inspector_agent()) { - if (depth == 0) { - agent->DisableAsyncHook(); - } else { - agent->EnableAsyncHook(); - } + agent->SetAsyncHookTrackingEnabled(depth != 0); } } @@ -647,6 +643,7 @@ class NodeInspectorClient : public V8InspectorClient { void installAdditionalCommandLineAPI(Local context, Local target) override { + if (!env_->can_call_into_js()) return; Local installer = env_->inspector_console_extension_installer(); if (!installer.IsEmpty()) { Local argv[] = {target}; @@ -1068,58 +1065,69 @@ void Agent::RegisterAsyncHook(Isolate* isolate, Local disable_function) { parent_env_->set_inspector_enable_async_hooks(enable_function); parent_env_->set_inspector_disable_async_hooks(disable_function); - if (pending_enable_async_hook_) { - CHECK(!pending_disable_async_hook_); - pending_enable_async_hook_ = false; - EnableAsyncHook(); - } else if (pending_disable_async_hook_) { - CHECK(!pending_enable_async_hook_); - pending_disable_async_hook_ = false; - DisableAsyncHook(); - } + SyncAsyncHookState(); } -void Agent::EnableAsyncHook() { - HandleScope scope(parent_env_->isolate()); - Local enable = parent_env_->inspector_enable_async_hooks(); - if (!enable.IsEmpty()) { - ToggleAsyncHook(parent_env_->isolate(), enable); - } else if (pending_disable_async_hook_) { - CHECK(!pending_enable_async_hook_); - pending_disable_async_hook_ = false; - } else { - pending_enable_async_hook_ = true; - } +void Agent::SetAsyncHookTrackingEnabled(bool enabled) { + async_hook_wanted_ = enabled; + SyncAsyncHookState(); } -void Agent::DisableAsyncHook() { - HandleScope scope(parent_env_->isolate()); - Local disable = parent_env_->inspector_disable_async_hooks(); - if (!disable.IsEmpty()) { - ToggleAsyncHook(parent_env_->isolate(), disable); - } else if (pending_enable_async_hook_) { - CHECK(!pending_disable_async_hook_); - pending_enable_async_hook_ = false; - } else { - pending_disable_async_hook_ = true; - } -} +// Reconcile the state of the async hook used for async stack traces with the +// state last requested by the protocol. The hook is set up in JS land, +// (see inspector_async_hooks.js), which isn't safe to do when: +// 1. We are in early bootstrap and the setup functions aren't registered in +// C++ yet. +// 2. We are in a V8 interrupt requested by inspector protocol message +// dispatch e.g. from maxAsyncCallStackDepthChanged() notifications. +// When it's not safe to call into JS, this is a no-op and we'll try again in +// RegisterAsyncHook() (for 1) or from a scheduled immediate (for 2). +void Agent::SyncAsyncHookState() { + // The debugger can request an interrupt within the toggle JS function itself, + // A nested call only records the new requested state, the outermost call sees + // it when re-checking the loop condition after each toggle. + if (syncing_async_hook_state_) return; + syncing_async_hook_state_ = true; + auto on_exit = OnScopeLeave([this]() { syncing_async_hook_state_ = false; }); + + Isolate* isolate = parent_env_->isolate(); + HandleScope scope(isolate); + while (async_hook_wanted_ != async_hook_enabled_) { + // Guard against running this during cleanup -- no async events will be + // emitted anyway at that point anymore, and calling into JS is not + // possible. This should probably not be something we're attempting in the + // first place, + // Refs: https://github.com/nodejs/node/pull/34362#discussion_r456006039 + if (!parent_env_->can_call_into_js()) return; + + bool enable = async_hook_wanted_; + Local fn = enable ? parent_env_->inspector_enable_async_hooks() + : parent_env_->inspector_disable_async_hooks(); + if (fn.IsEmpty()) return; + + if (parent_env_->is_processing_v8_interrupt()) { + parent_env_->SetImmediate( + [](Environment* env) { + Agent* agent = env->inspector_agent(); + if (agent != nullptr) agent->SyncAsyncHookState(); + }, + CallbackFlags::kUnrefed); + return; + } -void Agent::ToggleAsyncHook(Isolate* isolate, Local fn) { - // Guard against running this during cleanup -- no async events will be - // emitted anyway at that point anymore, and calling into JS is not possible. - // This should probably not be something we're attempting in the first place, - // Refs: https://github.com/nodejs/node/pull/34362#discussion_r456006039 - if (!parent_env_->can_call_into_js()) return; - CHECK(parent_env_->has_run_bootstrapping_code()); - HandleScope handle_scope(isolate); - CHECK(!fn.IsEmpty()); - auto context = parent_env_->context(); - v8::TryCatch try_catch(isolate); - USE(fn->Call(context, Undefined(isolate), 0, nullptr)); - if (try_catch.HasCaught() && !try_catch.HasTerminated()) { - PrintCaughtException(isolate, context, try_catch); - UNREACHABLE("Cannot toggle Inspector's AsyncHook, please report this."); + CHECK(parent_env_->has_run_bootstrapping_code()); + Local context = parent_env_->context(); + v8::TryCatch try_catch(isolate); + USE(fn->Call(context, Undefined(isolate), 0, nullptr)); + if (try_catch.HasCaught()) { + // Termination may abort the toggle invocation, retrying now would just + // be terminated again. Instead of recording the toggle that may not have + // taken effect, leave the states as-is so that a later sync retries. + if (try_catch.HasTerminated()) return; + PrintCaughtException(isolate, context, try_catch); + UNREACHABLE("Cannot toggle Inspector's AsyncHook, please report this."); + } + async_hook_enabled_ = enable; } } diff --git a/src/inspector_agent.h b/src/inspector_agent.h index 5ace72a64012..932e4e8dce89 100644 --- a/src/inspector_agent.h +++ b/src/inspector_agent.h @@ -90,8 +90,7 @@ class Agent { void RegisterAsyncHook(v8::Isolate* isolate, v8::Local enable_function, v8::Local disable_function); - void EnableAsyncHook(); - void DisableAsyncHook(); + void SetAsyncHookTrackingEnabled(bool enabled); void SetParentHandle(std::unique_ptr parent_handle); std::unique_ptr GetParentHandle(uint64_t thread_id, @@ -132,7 +131,7 @@ class Agent { std::shared_ptr GetNetworkResourceManager(); private: - void ToggleAsyncHook(v8::Isolate* isolate, v8::Local fn); + void SyncAsyncHookState(); void ToggleNetworkTracking(v8::Isolate* isolate, v8::Local fn); node::Environment* parent_env_; @@ -150,8 +149,12 @@ class Agent { DebugOptions debug_options_; std::shared_ptr> host_port_; - bool pending_enable_async_hook_ = false; - bool pending_disable_async_hook_ = false; + // The state of the async hook used for async stack traces that the protocol + // last requested, and the state JS currently has. SyncAsyncHookState() + // reconciles the two when it is possible and safe to call into JS. + bool async_hook_wanted_ = false; + bool async_hook_enabled_ = false; + bool syncing_async_hook_state_ = false; bool network_tracking_enabled_ = false; bool pending_enable_network_tracking = false; diff --git a/src/node.cc b/src/node.cc index f03a4447e57d..838106acff8f 100644 --- a/src/node.cc +++ b/src/node.cc @@ -1179,6 +1179,7 @@ InitializeOncePerProcessInternal(const std::vector& args, if (!(flags & ProcessInitializationFlags::kNoInitOpenSSL)) { #if HAVE_OPENSSL #ifndef OPENSSL_IS_BORINGSSL +#if OPENSSL_VERSION_MAJOR >= 3 auto GetOpenSSLErrorString = []() -> std::string { std::string ret; ERR_print_errors_cb( @@ -1194,7 +1195,6 @@ InitializeOncePerProcessInternal(const std::vector& args, // In the case of FIPS builds we should make sure // the random source is properly initialized first. -#if OPENSSL_VERSION_MAJOR >= 3 // Call OPENSSL_init_crypto to initialize OPENSSL_INIT_LOAD_CONFIG to // avoid the default behavior where errors raised during the parsing of the // OpenSSL configuration file are not propagated and cannot be detected. @@ -1255,12 +1255,10 @@ InitializeOncePerProcessInternal(const std::vector& args, OPENSSL_init(); } #endif - if (!crypto::ProcessFipsOptions()) { + if (auto fips_error = crypto::ProcessFipsOptions()) { result->exit_code_ = ExitCode::kGenericUserError; result->early_return_ = true; - result->errors_.emplace_back( - "OpenSSL error when trying to enable FIPS:\n" + - GetOpenSSLErrorString()); + result->errors_.emplace_back(std::move(*fips_error)); return result; } diff --git a/src/node.h b/src/node.h index c654078904aa..d922352b1941 100644 --- a/src/node.h +++ b/src/node.h @@ -898,6 +898,16 @@ NODE_EXTERN void SetProcessExitHandler( std::function&& handler); NODE_EXTERN void DefaultProcessExitHandler(Environment* env, int exit_code); +// Sets a process-global handler invoked when Node.js programmatically aborts. +// Nullable strings representing the location and reason for the abort may or +// may not be passed as a parameter to the handler. The handler should not +// return, but node will ensure that the process exits after the handler is +// called regardless of whether or not it returns. Passing nullptr restores the +// default handler. This is process-global and may be invoked before any Isolate +// or Environment exists. +using AbortHandler = void (*)(const char* location, const char* message); +NODE_EXTERN void SetAbortHandler(AbortHandler handler); + // This may return nullptr if context is not associated with a Node instance. NODE_EXTERN Environment* GetCurrentEnvironment(v8::Local context); NODE_EXTERN IsolateData* GetEnvironmentIsolateData(Environment* env); diff --git a/src/node_binding.cc b/src/node_binding.cc index fa11b58725cf..9f34534d2fa8 100644 --- a/src/node_binding.cc +++ b/src/node_binding.cc @@ -670,6 +670,9 @@ void GetLinkedBinding(const FunctionCallbackInfo& args) { node::Utf8Value module_name_v(env->isolate(), module_name); const char* name = *module_name_v; + THROW_IF_INSUFFICIENT_PERMISSIONS( + env, permission::PermissionScope::kAddon, module_name_v.ToStringView()); + node_module* mod = nullptr; // Iterate from here to the nearest non-Worker Environment to see if there's diff --git a/src/node_buffer.cc b/src/node_buffer.cc index ebf5dd917500..bc0f03fdc8f3 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -1302,31 +1302,17 @@ void FastSwap64(Local receiver, static CFunction fast_swap64(CFunction::Make(FastSwap64)); -struct ValidationResult { - bool is_valid; - bool was_detached; -}; - -static ValidationResult ValidateUtf8(Local value) { +static bool ValidateUtf8(Local value) { ArrayBufferViewContents abv(value); - bool was_detached = abv.WasDetached(); - return {!was_detached && simdutf::validate_utf8(abv.data(), abv.length()), - was_detached}; + return abv.length() == 0 || simdutf::validate_utf8(abv.data(), abv.length()); } static void IsUtf8(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); CHECK_EQ(args.Length(), 1); CHECK(args[0]->IsTypedArray() || args[0]->IsArrayBuffer() || args[0]->IsSharedArrayBuffer()); - const ValidationResult result = ValidateUtf8(args[0]); - if (result.was_detached) { - return node::THROW_ERR_INVALID_STATE( - env, "Cannot validate on a detached buffer"); - } - - args.GetReturnValue().Set(result.is_valid); + args.GetReturnValue().Set(ValidateUtf8(args[0])); } static bool FastIsUtf8(Local receiver, @@ -1335,40 +1321,23 @@ static bool FastIsUtf8(Local receiver, FastApiCallbackOptions& options) { TRACK_V8_FAST_API_CALL("buffer.isUtf8"); HandleScope scope(options.isolate); - - const ValidationResult result = ValidateUtf8(value); - if (result.was_detached) { - node::THROW_ERR_INVALID_STATE(options.isolate, - "Cannot validate on a detached buffer"); - return false; - } - return result.is_valid; + return ValidateUtf8(value); } static CFunction fast_is_utf8(CFunction::Make(FastIsUtf8)); -static ValidationResult ValidateAscii(Local value) { +static bool ValidateAscii(Local value) { ArrayBufferViewContents abv(value); - bool was_detached = abv.WasDetached(); - return { - !was_detached && - !simdutf::validate_ascii_with_errors(abv.data(), abv.length()).error, - was_detached}; + return abv.length() == 0 || + !simdutf::validate_ascii_with_errors(abv.data(), abv.length()).error; } static void IsAscii(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); CHECK_EQ(args.Length(), 1); CHECK(args[0]->IsTypedArray() || args[0]->IsArrayBuffer() || args[0]->IsSharedArrayBuffer()); - const ValidationResult result = ValidateAscii(args[0]); - if (result.was_detached) { - return node::THROW_ERR_INVALID_STATE( - env, "Cannot validate on a detached buffer"); - } - - args.GetReturnValue().Set(result.is_valid); + args.GetReturnValue().Set(ValidateAscii(args[0])); } static bool FastIsAscii(Local receiver, @@ -1377,14 +1346,7 @@ static bool FastIsAscii(Local receiver, FastApiCallbackOptions& options) { TRACK_V8_FAST_API_CALL("buffer.isAscii"); HandleScope scope(options.isolate); - - const ValidationResult result = ValidateAscii(value); - if (result.was_detached) { - node::THROW_ERR_INVALID_STATE(options.isolate, - "Cannot validate on a detached buffer"); - return false; - } - return result.is_valid; + return ValidateAscii(value); } static CFunction fast_is_ascii(CFunction::Make(FastIsAscii)); @@ -1669,6 +1631,11 @@ void SlowWriteString(const FunctionCallbackInfo& args) { size_t max_length = 0; THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[2], 0, &offset)); + if (offset > ts_obj_length) { + return node::THROW_ERR_BUFFER_OUT_OF_BOUNDS( + env, "\"offset\" is outside of buffer bounds"); + } + THROW_AND_RETURN_IF_OOB( ParseArrayIndex(env, args[3], ts_obj_length - offset, &max_length)); diff --git a/src/node_constants.cc b/src/node_constants.cc index 6a1100194314..9abb643cc955 100644 --- a/src/node_constants.cc +++ b/src/node_constants.cc @@ -1137,7 +1137,12 @@ void DefineFsConstants(Local target) { NODE_DEFINE_CONSTANT(target, O_EXCL); #endif -NODE_DEFINE_CONSTANT(target, UV_FS_O_FILEMAP); + // Windows-only open flags honored by libuv. They are 0 on other platforms. + NODE_DEFINE_CONSTANT(target, UV_FS_O_FILEMAP); + NODE_DEFINE_CONSTANT(target, UV_FS_O_TEMPORARY); + NODE_DEFINE_CONSTANT(target, UV_FS_O_SHORT_LIVED); + NODE_DEFINE_CONSTANT(target, UV_FS_O_SEQUENTIAL); + NODE_DEFINE_CONSTANT(target, UV_FS_O_RANDOM); #ifdef O_NOCTTY NODE_DEFINE_CONSTANT(target, O_NOCTTY); @@ -1377,11 +1382,7 @@ void CreatePerContextProperties(Local target, FIXED_ONE_BYTE_STRING(isolate, "dlopen"), dlopen_constants) .Check(); - os_constants - ->Set(env->context(), - FIXED_ONE_BYTE_STRING(isolate, "errno"), - err_constants) - .Check(); + os_constants->Set(env->context(), env->errno_string(), err_constants).Check(); os_constants ->Set(env->context(), FIXED_ONE_BYTE_STRING(isolate, "signals"), diff --git a/src/node_diagnostics_channel.cc b/src/node_diagnostics_channel.cc index cfae019da62f..ab67e6d7c5fa 100644 --- a/src/node_diagnostics_channel.cc +++ b/src/node_diagnostics_channel.cc @@ -178,11 +178,11 @@ void Channel::Unlink() { publish_fn_.Reset(); } -Channel* Channel::Get(Environment* env, const char* name) { +BaseObjectPtr Channel::Get(Environment* env, std::string_view name) { Realm* realm = env->principal_realm(); BindingData* binding = realm->GetBindingData(); if (binding == nullptr) { - return nullptr; + return {}; } uint32_t index = binding->GetOrCreateChannelIndex(std::string(name)); @@ -208,22 +208,24 @@ Channel* Channel::Get(Environment* env, const char* name) { .ToLocalChecked() ->NewInstance(context) .ToLocal(&wrap)) { - return nullptr; + return {}; } binding->channels_[index] = MakeDetachedBaseObject( env, wrap, binding, index, std::string(name)); } - Channel* channel = binding->channels_[index].get(); + auto& channel = binding->channels_[index]; // Late-bind: link to the JS channel when the callback is available. if (!binding->link_callback_.IsEmpty() && !channel->IsLinked()) { Isolate* isolate = env->isolate(); HandleScope handle_scope(isolate); Local context = env->context(); - Local js_name = String::NewFromUtf8(isolate, name).ToLocalChecked(); - Local argv[] = {js_name, Integer::NewFromUnsigned(isolate, index)}; + Local argv[] = { + ToV8Value(context, name).ToLocalChecked(), + Integer::NewFromUnsigned(isolate, index), + }; Local result; if (binding->link_callback_.Get(isolate) ->Call(context, v8::Undefined(isolate), arraysize(argv), argv) diff --git a/src/node_diagnostics_channel.h b/src/node_diagnostics_channel.h index 073e4e4f273b..ca68e75a4361 100644 --- a/src/node_diagnostics_channel.h +++ b/src/node_diagnostics_channel.h @@ -73,8 +73,7 @@ class Channel : public BaseObject { uint32_t index, std::string name); - // Returns a non-owning pointer. Lifetime is managed by BindingData. - static Channel* Get(Environment* env, const char* name); + static BaseObjectPtr Get(Environment* env, std::string_view name); inline bool HasSubscribers() const { return binding_data_ != nullptr && binding_data_->subscribers_[index_] > 0; diff --git a/src/node_errors.cc b/src/node_errors.cc index 34fa4758bfa5..d79d8d0a1ed6 100644 --- a/src/node_errors.cc +++ b/src/node_errors.cc @@ -393,6 +393,30 @@ void AppendExceptionLine(Environment* env, .FromMaybe(false)); } +namespace { +// Default handler: Dumps native + JS backtraces to stderr and exits. This +// indirectly calls backtrace so it can not be marked as [[noreturn]] (see the +// comment on node::Assert() below). `message` and `location` are ignored +// because the assertion/fatal-error message, if any, is already printed to +// stderr by the caller (Assert()/OnFatalError()) before this handler runs. +void DefaultAbortHandler(const char* /*location*/, const char* /*message*/) { + DumpNativeBacktrace(stderr); + DumpJavaScriptBacktrace(stderr); + fflush(stderr); + ABORT_NO_BACKTRACE(); +} +// Constant-initialized, so this is valid from load time, safe even for a +// CHECK() during early startup, before any SetAbortHandler call. +AbortHandler g_abort_handler = DefaultAbortHandler; +} // namespace + +void SetAbortHandler(AbortHandler handler) { + g_abort_handler = handler ? handler : DefaultAbortHandler; +} +AbortHandler GetAbortHandler() { + return g_abort_handler; +} + void Assert(const AssertionInfo& info) { std::string name = GetHumanReadableProcessName(); @@ -406,7 +430,7 @@ void Assert(const AssertionInfo& info) { info.message); fflush(stderr); - ABORT(); + ABORT_WITH_DETAILS(info.file_line, info.message); } enum class EnhanceFatalException { kEnhance, kDontEnhance }; @@ -584,7 +608,7 @@ static void ReportFatalException(Environment* env, } fflush(stderr); - ABORT(); + ABORT_WITH_DETAILS(location, message); } void OOMErrorHandler(const char* location, const v8::OOMDetails& details) { @@ -620,7 +644,7 @@ void OOMErrorHandler(const char* location, const v8::OOMDetails& details) { } fflush(stderr); - ABORT(); + ABORT_WITH_DETAILS(location, message); } v8::ModifyCodeGenerationFromStringsResult ModifyCodeGenerationFromStrings( diff --git a/src/node_file-inl.h b/src/node_file-inl.h index e0fc86bedc74..ebd97c1c8c52 100644 --- a/src/node_file-inl.h +++ b/src/node_file-inl.h @@ -209,13 +209,7 @@ FSReqPromise::FSReqPromise(BindingData* binding_data, v8::Local obj, bool use_bigint) : FSReqBase( - binding_data, obj, AsyncWrap::PROVIDER_FSREQPROMISE, use_bigint), - stats_field_array_( - env()->isolate(), - static_cast(FsStatsOffset::kFsStatsFieldsNumber)), - statfs_field_array_( - env()->isolate(), - static_cast(FsStatFsOffset::kFsStatFsFieldsNumber)) {} + binding_data, obj, AsyncWrap::PROVIDER_FSREQPROMISE, use_bigint) {} template void FSReqPromise::Reject(v8::Local reject) { @@ -253,14 +247,24 @@ void FSReqPromise::Resolve(v8::Local value) { template void FSReqPromise::ResolveStat(const uv_stat_t* stat) { - FillStatsArray(&stats_field_array_, stat); - Resolve(stats_field_array_.GetJSArray()); + if (!stats_field_array_.has_value()) { + stats_field_array_.emplace( + env()->isolate(), + static_cast(FsStatsOffset::kFsStatsFieldsNumber)); + } + FillStatsArray(&stats_field_array_.value(), stat); + Resolve(stats_field_array_->GetJSArray()); } template void FSReqPromise::ResolveStatFs(const uv_statfs_t* stat) { - FillStatFsArray(&statfs_field_array_, stat); - Resolve(statfs_field_array_.GetJSArray()); + if (!statfs_field_array_.has_value()) { + statfs_field_array_.emplace( + env()->isolate(), + static_cast(FsStatFsOffset::kFsStatFsFieldsNumber)); + } + FillStatFsArray(&statfs_field_array_.value(), stat); + Resolve(statfs_field_array_->GetJSArray()); } template @@ -280,8 +284,12 @@ void FSReqPromise::SetReturnValue( template void FSReqPromise::MemoryInfo(MemoryTracker* tracker) const { FSReqBase::MemoryInfo(tracker); - tracker->TrackField("stats_field_array", stats_field_array_); - tracker->TrackField("statfs_field_array", statfs_field_array_); + if (stats_field_array_.has_value()) { + tracker->TrackField("stats_field_array", stats_field_array_.value()); + } + if (statfs_field_array_.has_value()) { + tracker->TrackField("statfs_field_array", statfs_field_array_.value()); + } } FSReqBase* GetReqWrap(const v8::FunctionCallbackInfo& args, diff --git a/src/node_file.cc b/src/node_file.cc index 126913185e0c..a576b4a9d4eb 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -1785,6 +1785,9 @@ static void RmSync(const FunctionCallbackInfo& args) { error == std::errc::too_many_files_open || error == std::errc::too_many_files_open_in_system || error == std::errc::directory_not_empty || +#ifdef _WIN32 + error == std::errc::permission_denied || +#endif error == std::errc::operation_not_permitted); }; @@ -1805,8 +1808,10 @@ static void RmSync(const FunctionCallbackInfo& args) { if (retryDelay > 0) { #ifdef _WIN32 - Sleep(i * retryDelay / 1000); + // No conversion needed: Sleep() takes milliseconds. + Sleep(i * retryDelay); #else + // sleep() takes seconds, so convert the millisecond delay. sleep(i * retryDelay / 1000); #endif } @@ -2918,10 +2923,20 @@ static void ReadFileUtf8(const FunctionCallbackInfo& args) { uv_fs_req_cleanup(&req); }); + // Past the first 8 KiB, read into one heap buffer sized from fstat(); the + // size is only a hint, reading continues until read() reports EOF. std::string result{}; char buffer[8192]; uv_buf_t buf = uv_buf_init(buffer, sizeof(buffer)); + char* big = nullptr; + size_t big_len = 0; + size_t big_cap = 0; + bool sized = false; + auto free_big = OnScopeLeave([&big]() { free(big); }); + constexpr size_t kMinChunk = 64 * 1024; + constexpr size_t kMaxChunk = 8 * 1024 * 1024; + FS_SYNC_TRACE_BEGIN(read); while (true) { auto r = uv_fs_read(nullptr, &req, file, &buf, 1, -1, nullptr); @@ -2934,12 +2949,62 @@ static void ReadFileUtf8(const FunctionCallbackInfo& args) { if (r <= 0) { break; } - result.append(buf.base, r); + if (big == nullptr) { + result.append(buf.base, r); + if (static_cast(r) < sizeof(buffer)) { + continue; + } + // Switch to the heap buffer. + uv_fs_req_cleanup(&req); + big_cap = kMinChunk; + big = UncheckedMalloc(big_cap); + if (big == nullptr) { + FS_SYNC_TRACE_END(read); + return THROW_ERR_MEMORY_ALLOCATION_FAILED(env); + } + memcpy(big, result.data(), result.size()); + big_len = result.size(); + result = std::string(); + } else { + big_len += static_cast(r); + } + if (big_len == big_cap) { + // +1 leaves room for the read() that reports EOF. + size_t new_cap = + big_cap + std::min(kMaxChunk, std::max(kMinChunk, big_cap)); + if (!sized) { + sized = true; + uv_fs_req_cleanup(&req); + uv_fs_t stat_req; + if (uv_fs_fstat(nullptr, &stat_req, file, nullptr) == 0) { + const uv_stat_t* const st = + static_cast(stat_req.ptr); + if ((st->st_mode & S_IFMT) == S_IFREG && + static_cast(st->st_size) > big_len && + static_cast(st->st_size) < + static_cast(v8::String::kMaxLength)) { + new_cap = static_cast(st->st_size) + 1; + } + } + uv_fs_req_cleanup(&stat_req); + } + char* const grown = UncheckedRealloc(big, new_cap); + if (grown == nullptr) { + FS_SYNC_TRACE_END(read); + return THROW_ERR_MEMORY_ALLOCATION_FAILED(env); + } + big = grown; + big_cap = new_cap; + } + buf = uv_buf_init(big + big_len, std::min(kMaxChunk, big_cap - big_len)); } FS_SYNC_TRACE_END(read); Local val; - if (!ToV8Value(env->context(), result, isolate).ToLocal(&val)) { + const std::string_view content = big != nullptr + ? std::string_view(big, big_len) + : std::string_view(result); + if (!ToV8Value(env->context(), content, isolate).ToLocal(&val)) { return; } @@ -3358,10 +3423,11 @@ static void Mkdtemp(const FunctionCallbackInfo& args) { CHECK_GE(argc, 2); BufferValue tmpl(isolate, args[0]); - static constexpr const char* const suffix = "XXXXXX"; - const auto length = tmpl.length(); - tmpl.AllocateSufficientStorage(length + strlen(suffix)); - snprintf(tmpl.out() + length, tmpl.length(), "%s", suffix); + const auto prefix_length = tmpl.length(); + static constexpr std::string_view suffix = "XXXXXX"; + tmpl.AllocateSufficientStorage(prefix_length + suffix.size() + 1); + memcpy(tmpl.out() + prefix_length, suffix.data(), suffix.size()); + tmpl.SetLengthAndZeroTerminate(prefix_length + suffix.size()); CHECK_NOT_NULL(*tmpl); @@ -4144,6 +4210,33 @@ InternalFieldInfoBase* BindingData::Serialize(int index) { return info; } +#ifdef _WIN32 +static void HandleToFd(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + CHECK_GE(args.Length(), 1); + CHECK(args[0]->IsBigInt()); + + int flags = 0; + if (args[1]->IsNumber()) { + flags = args[1].As()->Value(); + } + + bool lossless; + int64_t handle = args[0].As()->Int64Value(&lossless); + if (!lossless) { + return THROW_ERR_OUT_OF_RANGE(env, + "windowsHandle does not fit into 64 bits"); + } + intptr_t value = static_cast(handle); + + int fd = _open_osfhandle(value, flags); + if (fd == -1) { + return env->ThrowErrnoException(errno, "_open_osfhandle"); + } + args.GetReturnValue().Set(fd); +} +#endif // _WIN32 + void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data, Local target) { Isolate* isolate = isolate_data->isolate(); @@ -4210,6 +4303,10 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data, SetMethod(isolate, target, "mkdtemp", Mkdtemp); +#ifdef _WIN32 + SetMethod(isolate, target, "handleToFd", HandleToFd); +#endif + SetMethod(isolate, target, "cpSyncCheckPaths", CpSyncCheckPaths); SetMethod(isolate, target, "cpSyncOverrideFile", CpSyncOverrideFile); SetMethod(isolate, target, "cpSyncCopyDir", CpSyncCopyDir); @@ -4337,6 +4434,9 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(LUTimes); registry->Register(Mkdtemp); +#ifdef _WIN32 + registry->Register(HandleToFd); +#endif registry->Register(NewFSReqCallback); registry->Register(FileHandle::New); diff --git a/src/node_file.h b/src/node_file.h index 17f3b4203c8e..fab01a4c17b8 100644 --- a/src/node_file.h +++ b/src/node_file.h @@ -266,8 +266,11 @@ class FSReqPromise final : public FSReqBase { bool use_bigint); bool finished_ = false; - AliasedBufferT stats_field_array_; - AliasedBufferT statfs_field_array_; + // Constructed lazily in ResolveStat()/ResolveStatFs(): most operations + // never resolve with stats, and eagerly allocating the backing stores + // for every request is a significant per-request cost. + std::optional stats_field_array_; + std::optional statfs_field_array_; }; class FSReqAfterScope final { diff --git a/src/node_http2.cc b/src/node_http2.cc index 5dfc425230e6..b6bbb1a4edc3 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -815,6 +815,21 @@ void Http2Session::Close(uint32_t code, bool socket_closed) { return; set_closing(); + // Do not flush GOAWAY from inside nghttp2_session_mem_recv() callbacks. + // ConsumeHTTP2Data() finishes the close once mem_recv returns. + if (is_receiving()) { + set_close_pending(); + pending_close_code_ = code; + pending_close_socket_closed_ = socket_closed; + return; + } + + FinishClose(code, socket_closed); +} + +void Http2Session::FinishClose(uint32_t code, bool socket_closed) { + CHECK(is_closing()); + // Stop reading on the i/o stream if (stream_ != nullptr) { set_reading_stopped(); @@ -864,6 +879,12 @@ void Http2Session::Close(uint32_t code, bool socket_closed) { EmitStatistics(); } +void Http2Session::MaybeFinishPendingClose() { + if (!is_close_pending() || is_destroyed()) return; + set_close_pending(false); + FinishClose(pending_close_code_, pending_close_socket_closed_); +} + // Locates an existing known stream by ID. nghttp2 has a similar method // but this is faster and does not fail if the stream is not found. BaseObjectPtr Http2Session::FindStream(int32_t id) { @@ -958,11 +979,13 @@ void Http2Session::ConsumeHTTP2Data() { nghttp2_session_want_read(session_.get())); set_receive_paused(false); custom_recv_error_code_ = nullptr; + set_receiving(); ssize_t ret = nghttp2_session_mem_recv(session_.get(), reinterpret_cast(stream_buf_.base) + stream_buf_offset_, read_len); + set_receiving(false); CHECK_NE(ret, NGHTTP2_ERR_NOMEM); CHECK_IMPLIES(custom_recv_error_code_ != nullptr, ret < 0); @@ -976,6 +999,10 @@ void Http2Session::ConsumeHTTP2Data() { // Even if all bytes were received, a paused stream may delay the // nghttp2_on_frame_recv_callback which may have an END_STREAM flag. stream_buf_offset_ += ret; + // Still complete a Close() deferred during mem_recv; do not fall through + // to SendPendingData() here (paused receives historically skip that flush + // because a write may already be in progress). + MaybeFinishPendingClose(); goto done; } @@ -986,12 +1013,23 @@ void Http2Session::ConsumeHTTP2Data() { stream_buf_allocation_.reset(); stream_buf_ = uv_buf_init(nullptr, 0); + // Finish a Close() deferred during mem_recv before flushing, so GOAWAY is + // not written after pending RST_STREAM frames. + MaybeFinishPendingClose(); + +done: + // Finish a Close() deferred above before flushing, so GOAWAY is not written + // after pending RST_STREAM frames. + if (is_close_pending() && !is_destroyed()) { + set_close_pending(false); + FinishClose(pending_close_code_, pending_close_socket_closed_); + } + // Send any data that was queued up while processing the received data. if (ret >= 0 && !is_destroyed()) { SendPendingData(); } -done: if (ret < 0) [[unlikely]] { Isolate* isolate = env()->isolate(); Debug(this, @@ -1036,6 +1074,11 @@ int Http2Session::OnBeginHeadersCallback(nghttp2_session* handle, int32_t id = GetFrameID(frame); Debug(session, "beginning headers for stream %d", id); + // Close() can be called by JavaScript from an earlier receive callback. + // Do not create streams that can no longer be exposed to JavaScript. + if (session->is_close_pending()) + return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; + BaseObjectPtr stream = session->FindStream(id); // The common case is that we're creating a new stream. The less likely // case is that we're receiving a set of trailers @@ -1101,6 +1144,12 @@ int Http2Session::OnFrameReceive(nghttp2_session* handle, session->statistics_.frame_count++; Debug(session, "complete frame received: type: %d", frame->hd.type); + + // JavaScript may have closed the session from an earlier receive callback. + // FinishClose() runs after nghttp2_session_mem_recv() returns. + if (session->is_close_pending()) + return 0; + switch (frame->hd.type) { case NGHTTP2_DATA: return session->HandleDataFrame(frame); @@ -1367,6 +1416,12 @@ int Http2Session::OnDataChunkReceived(nghttp2_session* handle, if (len == 0) return 0; + // Close() can be called by JavaScript from an earlier receive callback. + // Ignore the rest of the buffered DATA because its stream may never have + // been exposed to JavaScript and therefore has no onread callback. + if (session->is_close_pending()) + return 0; + // Notify nghttp2 that we've consumed a chunk of data on the connection // so that it can send a WINDOW_UPDATE frame. This is a critical part of // the flow control process in http2 @@ -1405,6 +1460,9 @@ int Http2Session::OnDataChunkReceived(nghttp2_session* handle, len -= avail; stream->EmitRead(avail, buf); + // JS may have destroyed the stream from inside onread; stop delivering. + if (stream->is_destroyed()) break; + // If the stream owner (e.g. the JS Http2Stream) wants more data, just // tell nghttp2 that all data has been consumed. Otherwise, defer until // more data is being requested. @@ -1962,6 +2020,12 @@ uint8_t Http2Session::SendPendingData() { // SendPendingData should not be called recursively. if (is_sending()) return 1; + + // Do not call `nghttp2_session_mem_send()` while nghttp2 is processing + // incoming data. Sending may close the stream and free nghttp2 state + // that is still in use by `nghttp2_session_mem_recv()`. + if (is_receiving()) return 1; + // This is cleared by ClearOutgoing(). set_sending(); @@ -2372,10 +2436,48 @@ void Http2Stream::Destroy() { // Do nothing if this stream instance is already destroyed if (is_destroyed()) return; - if (session_->has_pending_rststream(id_)) - FlushRstStream(); + + // Session may already be gone if destroy was deferred across a session + // teardown. + if (!session_) { + set_destroyed(); + Detach(); + return; + } + + // Mark destroyed immediately so OnDataChunkReceived stops EmitRead into an + // already-destroyed JS stream (which would treat the byte count as errno). set_destroyed(); + // While mem_recv is active, do not FlushRstStream or RemoveStream yet: + // - FlushRstStream would close the nghttp2 stream before queued response + // DATA can be mem_send'd after receive returns. + // - RemoveStream would make OnSendData/Provider::OnRead fail to FindStream. + // Pending RSTs stay in pending_rst_streams_ and are flushed from + // ClearOutgoing after the post-receive SendPendingData. + if (session_->is_receiving()) { + BaseObjectPtr strong_ref{this}; + env()->SetImmediate( + [this, strong_ref](Environment*) { CompleteDestroyCleanup(); }); + return; + } + + if (session_->has_pending_rststream(id_)) FlushRstStream(); + + CompleteDestroyCleanup(); +} + +void Http2Stream::CompleteDestroyCleanup() { + if (!session_) { + Detach(); + return; + } + + // Destroy() always set_destroyed() before scheduling or calling this. + CHECK(is_destroyed()); + + if (session_->has_pending_rststream(id_)) FlushRstStream(); + Debug(this, "destroying stream"); // Wait until the start of the next loop to delete because there @@ -2412,7 +2514,6 @@ void Http2Stream::Destroy() { EmitStatistics(); } - // Initiates a response on the Http2Stream using data provided via the // StreamBase Streams API. int Http2Stream::SubmitResponse(const Http2Headers& headers, int options) { @@ -2521,6 +2622,23 @@ void Http2Stream::SubmitRstStream(const uint32_t code) { return code == NGHTTP2_CANCEL; }; + // Do not call `nghttp2_session_mem_send()` while nghttp2 is processing + // incoming data. Sending may close the stream and free nghttp2 state + // that is still in use by `nghttp2_session_mem_recv()`. + if (session_->is_receiving()) { + // These resets must be submitted before the current callback returns. + // In particular, nghttp2 otherwise replaces ENHANCE_YOUR_CALM with + // INTERNAL_ERROR when OnHeaderCallback returns a temporal failure. + if (code == NGHTTP2_ENHANCE_YOUR_CALM || + code == NGHTTP2_REFUSED_STREAM) { + FlushRstStream(); + } else { + // Let queued DATA, including END_STREAM, be serialized before the reset. + session_->AddPendingRstStream(id_); + } + return; + } + // If RST_STREAM frame is received with error code NGHTTP2_CANCEL, // add it to the pending list and don't force purge the data. It is // to avoids the double free error due to unwanted behavior of nghttp2. @@ -2556,8 +2674,8 @@ void Http2Stream::SubmitRstStream(const uint32_t code) { } void Http2Stream::FlushRstStream() { - if (is_destroyed()) - return; + if (!session_) return; + session_->RemovePendingRstStream(id_); Http2Scope h2scope(this); CHECK_EQ(nghttp2_submit_rst_stream( session_->session(), @@ -2773,7 +2891,9 @@ ssize_t Http2Stream::Provider::Stream::OnRead(nghttp2_session* handle, if (stream->available_outbound_length_ == 0 && !stream->is_writable()) { Debug(session, "no more data for stream %d", id); *flags |= NGHTTP2_DATA_FLAG_EOF; - if (stream->has_trailers()) { + // A deferred Destroy() cannot call back into JavaScript for trailers. + // Let the DATA frame end the stream instead. + if (stream->has_trailers() && !stream->is_destroyed()) { *flags |= NGHTTP2_DATA_FLAG_NO_END_STREAM; stream->OnTrailers(); } diff --git a/src/node_http2.h b/src/node_http2.h index 0bb2b0cb2891..f321bf0c1601 100644 --- a/src/node_http2.h +++ b/src/node_http2.h @@ -76,6 +76,8 @@ constexpr int kSessionStateSending = 0x10; constexpr int kSessionStateWriteInProgress = 0x20; constexpr int kSessionStateReadingStopped = 0x40; constexpr int kSessionStateReceivePaused = 0x80; +constexpr int kSessionStateReceiving = 0x100; +constexpr int kSessionStateClosePending = 0x200; // The Padding Strategy determines the method by which extra padding is // selected for HEADERS and DATA frames. These are configurable via the @@ -331,6 +333,10 @@ class Http2Stream : public AsyncWrap, // Destroy this stream instance and free all held memory. void Destroy(); + // Completes Destroy() after set_destroyed(); may run deferred until after + // nghttp2_session_mem_recv() returns. + void CompleteDestroyCleanup(); + bool is_destroyed() const { return flags_ & kStreamStateDestroyed; } @@ -659,6 +665,8 @@ class Http2Session : public AsyncWrap, IS_FLAG(write_in_progress, kSessionStateWriteInProgress) IS_FLAG(reading_stopped, kSessionStateReadingStopped) IS_FLAG(receive_paused, kSessionStateReceivePaused) + IS_FLAG(receiving, kSessionStateReceiving) + IS_FLAG(close_pending, kSessionStateClosePending) #undef IS_FLAG @@ -702,6 +710,10 @@ class Http2Session : public AsyncWrap, std::ranges::find(pending_rst_streams_, stream_id); } + void RemovePendingRstStream(int32_t stream_id) { + std::erase(pending_rst_streams_, stream_id); + } + // Handle reads/writes from the underlying network transport. uv_buf_t OnStreamAlloc(size_t suggested_size) override; void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override; @@ -951,6 +963,10 @@ class Http2Session : public AsyncWrap, std::vector outgoing_storage_; size_t outgoing_length_ = 0; std::vector pending_rst_streams_; + // Saved arguments for Close() deferred while nghttp2_session_mem_recv() + // callbacks are active. + uint32_t pending_close_code_ = NGHTTP2_NO_ERROR; + bool pending_close_socket_closed_ = false; // Count streams that have been rejected while being opened. Exceeding a fixed // limit will result in the session being destroyed, as an indication of a // misbehaving peer. This counter is reset once new streams are being @@ -965,6 +981,8 @@ class Http2Session : public AsyncWrap, void CopyDataIntoOutgoing(const uint8_t* src, size_t src_length); void ClearOutgoing(int status); + void FinishClose(uint32_t code, bool socket_closed); + void MaybeFinishPendingClose(); void MaybeNotifyGracefulCloseComplete(); diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index f0f3795100e1..50e1fff07193 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -322,6 +322,7 @@ class Parser : public AsyncWrap, public StreamListener { allocator_.Reset(); url_.Reset(); status_message_.Reset(); + max_header_pairs_ = -1; if (connectionsList_ != nullptr) { connectionsList_->Push(this); @@ -464,6 +465,7 @@ class Parser : public AsyncWrap, public StreamListener { num_fields_ = 0; num_values_ = 0; header_pairs_ = 0; + max_header_pairs_ = -1; // METHOD if (parser_.type == HTTP_REQUEST) { @@ -1032,6 +1034,7 @@ class Parser : public AsyncWrap, public StreamListener { headers_completed_ = false; max_http_header_size_ = max_http_header_size; header_pairs_ = 0; + max_header_pairs_ = -1; } @@ -1051,21 +1054,23 @@ class Parser : public AsyncWrap, public StreamListener { header_pairs_ += 2; - Local max_header_pairs_v; - if (!object() - ->Get(env()->context(), - FIXED_ONE_BYTE_STRING(env()->isolate(), "maxHeaderPairs")) - .ToLocal(&max_header_pairs_v)) { - got_exception_ = true; - return -1; - } + if (max_header_pairs_ < 0) { + Local max_header_pairs_v; + if (!object() + ->Get(env()->context(), + FIXED_ONE_BYTE_STRING(env()->isolate(), "maxHeaderPairs")) + .ToLocal(&max_header_pairs_v)) { + got_exception_ = true; + return -1; + } - if (!max_header_pairs_v->IsNumber()) { - return 0; + const double value = max_header_pairs_v->IsNumber() + ? max_header_pairs_v.As()->Value() + : 0; + max_header_pairs_ = value > 0 ? value : 0; } - const double max_header_pairs = max_header_pairs_v.As()->Value(); - if (max_header_pairs > 0 && header_pairs_ > max_header_pairs) { + if (max_header_pairs_ > 0 && header_pairs_ > max_header_pairs_) { llhttp_set_error_reason(&parser_, "HPE_HEADER_OVERFLOW:Header overflow"); return HPE_USER; } @@ -1107,6 +1112,7 @@ class Parser : public AsyncWrap, public StreamListener { const char* current_buffer_data_; bool headers_completed_ = false; size_t header_pairs_ = 0; + double max_header_pairs_ = -1; bool pending_pause_ = false; uint64_t header_nread_ = 0; uint64_t chunk_extensions_nread_ = 0; diff --git a/src/node_i18n.cc b/src/node_i18n.cc index 3c4f419aa294..259e6eeda3e4 100644 --- a/src/node_i18n.cc +++ b/src/node_i18n.cc @@ -123,10 +123,13 @@ MaybeLocal ToBufferEndian(Environment* env, MaybeStackBuffer* buf) { void CopySourceBuffer(MaybeStackBuffer* dest, const char* data, - const size_t length, const size_t length_in_chars) { dest->AllocateSufficientStorage(length_in_chars); char* dst = reinterpret_cast(**dest); + // The destination holds length_in_chars UChar units. Copy that many whole + // units and ignore a trailing odd byte; copying the raw byte length would + // write one byte past the buffer when the source length is not even. + const size_t length = length_in_chars * sizeof(UChar); memcpy(dst, data, length); if constexpr (IsBigEndian()) { CHECK(nbytes::SwapBytes16(dst, length)); @@ -199,7 +202,7 @@ MaybeLocal TranscodeFromUcs2(Environment* env, to.set_subst_chars(sub.c_str()); const size_t length_in_chars = source_length / sizeof(UChar); - CopySourceBuffer(&sourcebuf, source, source_length, length_in_chars); + CopySourceBuffer(&sourcebuf, source, length_in_chars); MaybeStackBuffer destbuf(length_in_chars); const uint32_t len = ucnv_fromUChars(to.conv(), *destbuf, length_in_chars, *sourcebuf, length_in_chars, status); diff --git a/src/node_locks.cc b/src/node_locks.cc index 9c871569c4d4..26fac6b62c4c 100644 --- a/src/node_locks.cc +++ b/src/node_locks.cc @@ -817,10 +817,10 @@ void CreatePerIsolateProperties(IsolateData* isolate_data, PropertyAttribute read_only = static_cast( PropertyAttribute::ReadOnly | PropertyAttribute::DontDelete); target->Set(FIXED_ONE_BYTE_STRING(isolate, "LOCK_MODE_SHARED"), - FIXED_ONE_BYTE_STRING(isolate, "shared"), + isolate_data->shared_string(), read_only); target->Set(FIXED_ONE_BYTE_STRING(isolate, "LOCK_MODE_EXCLUSIVE"), - FIXED_ONE_BYTE_STRING(isolate, "exclusive"), + isolate_data->exclusive_string(), read_only); target->Set(FIXED_ONE_BYTE_STRING(isolate, "LOCK_STOLEN_ERROR"), FIXED_ONE_BYTE_STRING(isolate, "LOCK_STOLEN"), diff --git a/src/node_modules.cc b/src/node_modules.cc index 5000ab66381c..f45d7ba91d98 100644 --- a/src/node_modules.cc +++ b/src/node_modules.cc @@ -112,7 +112,23 @@ const BindingData::PackageConfig* BindingData::GetPackageJSON( PackageConfig package_config{}; package_config.file_path = path; // No need to exclude BOM since simdjson will skip it. - if (ReadFileSync(&package_config.raw_json, path.data()) < 0) { + int read_error = ReadFileSync(&package_config.raw_json, path.data()); + if (read_error < 0) { + // No file at this path, a path component that is not a directory, or a + // "package.json" that is itself a directory all mean there is no package + // config here. Any other failure means a package.json is present but + // could not be read. Treating that as absent silently drops fields such + // as "exports" and "type", which can resolve a specifier to a different + // file, so surface the read error instead of continuing. + if (read_error != UV_ENOENT && read_error != UV_ENOTDIR && + read_error != UV_EISDIR) { + THROW_ERR_INVALID_PACKAGE_CONFIG(realm->isolate(), + "Cannot read package config %s: %s.", + path.data(), + uv_strerror(read_error)); + return nullptr; + } + // Add `nullopt` to the package config cache so that we don't // need to open and attempt to read this path again binding_data->package_configs_.insert({std::string(path), std::nullopt}); diff --git a/src/node_options.cc b/src/node_options.cc index 9435a20299b8..5cbb2e7c593f 100644 --- a/src/node_options.cc +++ b/src/node_options.cc @@ -684,6 +684,12 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { kAllowedInEnvvar, false, OptionNamespaces::kPermissionNamespace); + AddOption("--allow-openssl-store", + "allow use of OpenSSL STORE loaders when any permissions are set", + &EnvironmentOptions::allow_openssl_store, + kAllowedInEnvvar, + false, + OptionNamespaces::kPermissionNamespace); AddOption("--experimental-repl-await", "experimental await keyword support in REPL", &EnvironmentOptions::experimental_repl_await, diff --git a/src/node_options.h b/src/node_options.h index 579860f7a3f0..870a6babc770 100644 --- a/src/node_options.h +++ b/src/node_options.h @@ -150,6 +150,7 @@ class EnvironmentOptions : public Options { bool allow_inspector = false; bool allow_child_process = false; bool allow_wasi = false; + bool allow_openssl_store = false; bool allow_worker_threads = false; bool experimental_repl_await = true; bool experimental_vm_modules = EXPERIMENTALS_DEFAULT_VALUE; diff --git a/src/node_process_methods.cc b/src/node_process_methods.cc index 4a258e5f1409..a33748d360c9 100644 --- a/src/node_process_methods.cc +++ b/src/node_process_methods.cc @@ -107,6 +107,7 @@ inline Local get_fields_array_buffer( CHECK(args[index]->IsFloat64Array()); Local arr = args[index].As(); CHECK_EQ(arr->Length(), array_length); + CHECK_EQ(arr->ByteOffset(), 0); return arr->Buffer(); } diff --git a/src/node_root_certs.h b/src/node_root_certs.h index 48d2fc5cb7d1..1d3af4841611 100644 --- a/src/node_root_certs.h +++ b/src/node_root_certs.h @@ -17,38 +17,6 @@ "V9mSOdY=\n" "-----END CERTIFICATE-----", -/* ePKI Root Certification Authority */ -"-----BEGIN CERTIFICATE-----\n" -"MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYD\n" -"VQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsM\n" -"IWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0z\n" -"NDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29t\n" -"IENvLiwgTHRkLjEqMCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5\n" -"MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U\n" -"82N0ywEhajfqhFAHSyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrB\n" -"p0xtInAhijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X\n" -"DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZr\n" -"xQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ad\n" -"o4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffAsgRFelQArr5T9rXn4fg8ozHS\n" -"qf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ETOxQvdibBjWzwloPn9s9h6PYq2l\n" -"Y9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUa\n" -"dCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+Xk\n" -"wY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3\n" -"pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF\n" -"MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLHClZ87lt4\n" -"DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B01GqZ\n" -"NF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq\n" -"KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnV\n" -"vwdVxrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltab\n" -"rNMdjmEPNXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc\n" -"7b3jajWvY9+rGNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8\n" -"GrBQAuUBo2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS\n" -"/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C\n" -"6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yI\n" -"VMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4\n" -"EZw=\n" -"-----END CERTIFICATE-----", - /* NetLock Arany (Class Gold) Főtanúsítvány */ "-----BEGIN CERTIFICATE-----\n" "MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTER\n" @@ -118,6 +86,39 @@ "WD9f\n" "-----END CERTIFICATE-----", +/* Izenpe.com */ +"-----BEGIN CERTIFICATE-----\n" +"MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYD\n" +"VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcN\n" +"MDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwL\n" +"SVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4IC\n" +"DwAwggIKAoICAQDJ03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5Tz\n" +"cqQsRNiekpsUOqHnJJAKClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpz\n" +"bm3benhB6QiIEn6HLmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJ\n" +"GjMxCrFXuaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD\n" +"yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8\n" +"hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG7\n" +"0t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyNBjNaooXlkDWgYlwWTvDjovoD\n" +"GrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+0rnq49qlw0dpEuDb8PYZi+17cNcC\n" +"1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQD\n" +"fo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNV\n" +"HREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4g\n" +"LSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB\n" +"BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAxMCBWaXRv\n" +"cmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE\n" +"FB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l\n" +"Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9\n" +"fbgakEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJO\n" +"ubv5vr8qhT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m\n" +"5hzkQiCeR7Csg1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Py\n" +"e6kfLqCTVyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk\n" +"LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqt\n" +"ujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZ\n" +"pR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6i\n" +"SNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE4\n" +"1V4tC5h9Pmzb/CaIxw==\n" +"-----END CERTIFICATE-----", + /* Go Daddy Root Certificate Authority - G2 */ "-----BEGIN CERTIFICATE-----\n" "MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNV\n" @@ -536,27 +537,6 @@ "gwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg==\n" "-----END CERTIFICATE-----", -/* Atos TrustedRoot 2011 */ -"-----BEGIN CERTIFICATE-----\n" -"MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRv\n" -"cyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3\n" -"MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3Qg\n" -"MjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n" -"DwAwggEKAoIBAQCVhTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI41\n" -"9KkM/IL9bcFyYie96mvr54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+\n" -"yj5vdHLqqjAqc2K+SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFs\n" -"Q/H3NYkQ4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L\n" -"cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMB\n" -"AAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/\n" -"MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgGA1UdIAQRMA8wDQYLKwYBBAGw\n" -"LQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4G\n" -"kGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0\n" -"BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQP\n" -"OLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYV\n" -"qL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv\n" -"KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed\n" -"-----END CERTIFICATE-----", - /* QuoVadis Root CA 1 G3 */ "-----BEGIN CERTIFICATE-----\n" "MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDEL\n" @@ -2862,4 +2842,96 @@ "hBC9xdIoaDQCQTV2WnXzkoYI9bIeCvZlC9p2x1L/Cx6AcCIwwzPbGO2E14vs7dOoY4G1VnxH\n" "x1YwlGhza9IuqbnZLBwpvQy6uWWL\n" "-----END CERTIFICATE-----", + +/* SECOM TLS RSA Root CA 2024 */ +"-----BEGIN CERTIFICATE-----\n" +"MIIFmjCCA4KgAwIBAgIJAO6JNNDLgOCyMA0GCSqGSIb3DQEBDAUAMFoxCzAJBgNVBAYTAkpQ\n" +"MSYwJAYDVQQKEx1TRUNPTSBUcnVzdCBTeXN0ZW1zIENvLiwgTHRkLjEjMCEGA1UEAxMaU0VD\n" +"T00gVExTIFJTQSBSb290IENBIDIwMjQwHhcNMjQwMTMxMDUxMTU1WhcNNDkwMTE0MDUxMTU1\n" +"WjBaMQswCQYDVQQGEwJKUDEmMCQGA1UEChMdU0VDT00gVHJ1c3QgU3lzdGVtcyBDby4sIEx0\n" +"ZC4xIzAhBgNVBAMTGlNFQ09NIFRMUyBSU0EgUm9vdCBDQSAyMDI0MIICIjANBgkqhkiG9w0B\n" +"AQEFAAOCAg8AMIICCgKCAgEA4TjizUwzxbInq8Tx11gaFYNk5fO+34y7TyM4neh0UgL5JIZb\n" +"JNLTz2x//L/B71+5m6X6nGIr7d4lFJBGtjO677hXOz93zkcWaUTm3VbOAjBlt4YWxlcccBHX\n" +"uZ7o3Q+4R+ormrBdHeJ1CTUEG8ttQbKIl3G7OZYbnH8/pP8cjPub/0kDVNuMzp7xsVRROOis\n" +"Qt53fMoJLlYgoebbuMphOqMCtjkJ7R6efEMfLp8UAVi9ZaLRn76ET/CJkk925nduuufC4Bat\n" +"S4mnXFmxN0vUXb0ij9B8O/D8gixQEsVSD4GK8FWRPh3bVd/6bzdkHGJjy21XI0yejVomZUbR\n" +"rOfNuz0boPGV1pt18fFC39IHQEth3OFqb5NDO3L+A9bNqTgAyUgRmIn4ucgDc/Ri/Km3V51u\n" +"eZjy1/yk0qwJVadAVVrCt56iNeXOyEvzJADGgDQ8E1Pdaqct8Cynz/47ReQM62vFYO08wcQk\n" +"rjmX/tesiko1V1yyaf6EfPzUFzmaGy9xvkCwdbm15EdTolOjE0H2Vb5/APDOyCFEokiYGmXT\n" +"LdAUl0wKZ4IyjkHGzy0jhpaXEXE/GJcEvI6VzEchjaBL03EJ0h9pG4OqeIOycKvAo3A+Tbet\n" +"yfsrgYyHzU0a7/qUjGat1AAq1nVljMpKqpinPTsf/d9H39FTUeJL7TpzzjUCAwEAAaNjMGEw\n" +"HQYDVR0OBBYEFCzrchKOWHdkNRVWNQFXB6l9DTbmMB8GA1UdIwQYMBaAFCzrchKOWHdkNRVW\n" +"NQFXB6l9DTbmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB\n" +"DAUAA4ICAQAVwsvluSafaez5tFPR/hRTBzRxEyMMQF3XJXCVi3yegZyKoec7hmE6jx2ZM8Kg\n" +"M1kn2yJRwFXHX8zUW9nBLEDWc4wuE8LrlZqhGZM9pJQXGmGzResDJV6JgRBna+j4sA1M7yId\n" +"lvL0sAfFXFCTRaWTD4E1V99RLrFzWfTcC+e180hDuNMpqOEo46+lMeW/Wvh7ifOQs+kiK0O2\n" +"gHxQDNxslSavnCs4V7l8HRDJ2La10o70Bo7VLzf1W8MBvv0VTnxB+NjT5qTAbhGFh9Gvp4Ba\n" +"JpmdUf0C5CEP6dbQlfgxWfzYr69yVT6dPQB+GFEaY03IMY+AcBCs+om1fNxrQXt9zoofMBNF\n" +"bLhvpNH/JsXWdGUzfNbO12uswTa5wah8LB18FTQN2/zPHYmvBEoLuyUgZ09VNLJo5YA0kXIt\n" +"VYkLjMe2SixzK4scUHv81IK99I91DWx7FwMVKw2xgFp+ZLYB2dnpQQrqwlW64glHUcK2N9BD\n" +"snjLSxeZ+UPECh9RxH4WAcKiZW+cqaKMmhP2WBfR4IcR7NOL32ml11ds87hhV1CZWWFCJAcC\n" +"idYZz6CZa8exzHojP9SB5RH0/v1KdHAisqhSjtJl/UIAHIQ48elOn8wrTdFap4Yb5aHglmMe\n" +"Nx+fAIhDluWVfxTO7H4dTPU+SFVRMLAh+wwKZfqb94nMeQ==\n" +"-----END CERTIFICATE-----", + +/* SECOM TLS ECC Root CA 2024 */ +"-----BEGIN CERTIFICATE-----\n" +"MIICTDCCAdGgAwIBAgIJAIF6LO+PI3pEMAoGCCqGSM49BAMDMFoxCzAJBgNVBAYTAkpQMSYw\n" +"JAYDVQQKEx1TRUNPTSBUcnVzdCBTeXN0ZW1zIENvLiwgTHRkLjEjMCEGA1UEAxMaU0VDT00g\n" +"VExTIEVDQyBSb290IENBIDIwMjQwHhcNMjQwMTMxMDU1MjM0WhcNNDkwMTE0MDU1MjM0WjBa\n" +"MQswCQYDVQQGEwJKUDEmMCQGA1UEChMdU0VDT00gVHJ1c3QgU3lzdGVtcyBDby4sIEx0ZC4x\n" +"IzAhBgNVBAMTGlNFQ09NIFRMUyBFQ0MgUm9vdCBDQSAyMDI0MHYwEAYHKoZIzj0CAQYFK4EE\n" +"ACIDYgAE7NzFMtu9dzQXSNC12fabk0+GlC5finB3R7XaZonRUd20aFiWObtuNBCLUZSfk6QX\n" +"AE55BjEXsXQ/NG8yUqicXjsu9ksDK3JZBgCwLOVh6+nwJXTvso/dEj/GUYH5mBdoo2MwYTAd\n" +"BgNVHQ4EFgQUO3YReyl04k4GTFaCQNAhL3qzydUwHwYDVR0jBBgwFoAUO3YReyl04k4GTFaC\n" +"QNAhL3qzydUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwMD\n" +"aQAwZgIxAN3ib8fi1pMYtAPjMilB5e5/H+t5CL0xPL+cZ5oTTZuSCjpAn1v7F/VAr8bFxQXA\n" +"owIxAKsBVO1ACFp7skwzPvdv1EUY5a897WGLT4lb+bjxFAWyl8wDcZJdwGZ/pAHxt1AJ1g==\n" +"-----END CERTIFICATE-----", + +/* Telia EC TLS Root CA v3 */ +"-----BEGIN CERTIFICATE-----\n" +"MIICMjCCAbegAwIBAgIPAYvSIlRjTQSLbOVHH9K1MAoGCCqGSM49BAMDMEoxCzAJBgNVBAYT\n" +"AlNFMRkwFwYDVQQKDBBUZWxpYSBDb21wYW55IEFCMSAwHgYDVQQDDBdUZWxpYSBFQyBUTFMg\n" +"Um9vdCBDQSB2MzAeFw0yMzExMTUwODU1MjZaFw00ODA1MjMxMTAwMDBaMEoxCzAJBgNVBAYT\n" +"AlNFMRkwFwYDVQQKDBBUZWxpYSBDb21wYW55IEFCMSAwHgYDVQQDDBdUZWxpYSBFQyBUTFMg\n" +"Um9vdCBDQSB2MzB2MBAGByqGSM49AgEGBSuBBAAiA2IABMHIlhVDLbmFKUpW0iK4dpryT6em\n" +"YOeS31JPwWnWPmkWRrAkTbPX40sQfHI9mpR7Rbktu3ngg6W+BBSXSechtMCnBmWXj/EaVlmV\n" +"5cY1jD2HoTfhBQ3AacpCNMLJK4NpZaNjMGEwHwYDVR0jBBgwFoAU1GToQ4g6cy/QGnGCNgte\n" +"hd7H3kMwHQYDVR0OBBYEFNRk6EOIOnMv0BpxgjYLXoXex95DMA4GA1UdDwEB/wQEAwIBBjAP\n" +"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2kAMGYCMQCXAUdS/9bbJ8A1JYaGf/bWt/s7\n" +"Ta0ot5Ulno8OjSNYRWQIlS4tVWldvTAVA7heOFgCMQCvKr8+Z2Rn+OBr5UHzlgBObpad1Luw\n" +"NTRcdNgUJxIWadcki+UBLEi1/AURKV5md2M=\n" +"-----END CERTIFICATE-----", + +/* Telia RSA TLS Root CA v3 */ +"-----BEGIN CERTIFICATE-----\n" +"MIIFgjCCA2qgAwIBAgIPAYvSUKtCVSxHWr2h3BrFMA0GCSqGSIb3DQEBDAUAMEsxCzAJBgNV\n" +"BAYTAlNFMRkwFwYDVQQKDBBUZWxpYSBDb21wYW55IEFCMSEwHwYDVQQDDBhUZWxpYSBSU0Eg\n" +"VExTIFJvb3QgQ0EgdjMwHhcNMjMxMTE1MDk0NzQyWhcNNDgwNTIzMTEwMDAwWjBLMQswCQYD\n" +"VQQGEwJTRTEZMBcGA1UECgwQVGVsaWEgQ29tcGFueSBBQjEhMB8GA1UEAwwYVGVsaWEgUlNB\n" +"IFRMUyBSb290IENBIHYzMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsV89KG19\n" +"hCf4S1Fvk8D3TyDERhmcvx8F7Kmb4WATx3ije1id3KHxRE0TKmcNCbAQ57bvHFEYa4hR2l20\n" +"VjVadExqOW+2ld99MbEiO+jRVOz+BbxLxJnmGwCqI+BfuTjjVReDxsxjQvjgBsClaO/sm5i7\n" +"0nlZcWGRtIkvWDK3NNkT5RtwXc/O8NTFVpbUqT6cRjIj3olAblR+lRf4Ffy5o+Q9fabjYn9Z\n" +"9S4itruElcEFf9Ljk7fwdTycT/rvJW9w/B3G2a3r0f/zXNOVruIBcqE6pkSospACU2bG42fY\n" +"KrbM/GWnp7u+p9Frz4jaNwpb4YHuEeS8BratNcP8X62jXIvvKHxlsMDJCnb4U8JzFOLsU6mo\n" +"hVY58BdZrvi0Gk9UOuqmgoG6dskHoksjZTlK61D/InzmEoA1yAYJFDVysjRxDUOu9cAwANbq\n" +"mq77WIFL6BpnZgVqPtMfG6wN8BrTKdapvilVsYR59BFgIsAVBMxrGh+W+QcvmJafUpASvlAr\n" +"KvVG2FI4i6PiLjSBT0+6F6EQLrYqefOQF/fBNEXb+njUQ0SUVrAqtH4Y+OjCI/a4/JJQppxe\n" +"emZcQ0SUShgiI5AM5xHO5iyaUrTjYH4zxUz9j+1FEbDH/xpstr1gXBykspup+hRTaJcbA+Ub\n" +"pJqtWZndAPddJmt6YJQ+dU3pDu8CAwEAAaNjMGEwHwYDVR0jBBgwFoAUsMep0t2yKFZzBJSM\n" +"FFxIbzdSkqgwHQYDVR0OBBYEFLDHqdLdsihWcwSUjBRcSG83UpKoMA4GA1UdDwEB/wQEAwIB\n" +"BjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDAUAA4ICAQBdYzFsNGDRk7bR/AgRKq+5\n" +"637YuOW+w6uhpoS0VnKMUpyHCwku86hEvqivakPtfmlm4bFwt++sb/8OXsWBqtfbXMaBNDTZ\n" +"l8XRMJuLWOW2JrbKkRzgG0eBUcvsadG1rrhbmZqYvFXaAZO7o4TdOZzxhBB5GOAWWXB3Iera\n" +"NP4J63zyo9n8Gqw3sJBG44em5hoYjBffP+npibyslnslRi4L6xHsCYj/Pab+OlqbMCB6v+sT\n" +"CLeEIukRVzoR9aQ45pEK7Z1QBnSsbAKQtss0JKD9d/mX143H1xePjPhTXlv5JCkhrcj+SShz\n" +"0P9+EHoWe6m9lyUEOIVn0rp+yVJWNbmyDv3VkwFxHC1ApSQsgSimjGQ4wtr6cSmordYxkV+R\n" +"o8lOIIhRksXPyDk27gW6IjUXCkZKpxFjkL3jiBSc8SkxnwCWtXg8xwNwdFVNBGLCCuJnsneY\n" +"XjJNqzRqUcoGwzsvF3Qi/ZnHUNvISdevlgIAXL4Wvrxaqvoa01wB+GCfs57RTGE4TvAGhKNK\n" +"us8K3hRT1BSpigzMIRzSxtAOrqPN6j//QSmW9f8Jcncri4j2ihSpVrFU0NdNkMhZeAKidTFP\n" +"sxCVFuW4Aniz7jqiw5sWtjbQrlW035izIEU4sYwQoC1Nx0Svy+mMTRai50LqFQ+A1/Hq6xHH\n" +"DNx7CI83d23Erw==\n" +"-----END CERTIFICATE-----", #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS diff --git a/src/node_sea.cc b/src/node_sea.cc index f387813aa65a..ece9c1306eac 100644 --- a/src/node_sea.cc +++ b/src/node_sea.cc @@ -308,10 +308,11 @@ std::tuple FixupArgsForSEA(int argc, char** argv) { cli_extension_args.size() + 2); new_argv.emplace_back(argv[0]); + exec_argv_storage.reserve(sea_resource.exec_argv.size() + + cli_extension_args.size()); + // Insert exec argv from SEA config if (!sea_resource.exec_argv.empty()) { - exec_argv_storage.reserve(sea_resource.exec_argv.size() + - cli_extension_args.size()); for (const auto& arg : sea_resource.exec_argv) { exec_argv_storage.emplace_back(arg); new_argv.emplace_back(exec_argv_storage.back().data()); @@ -508,6 +509,14 @@ std::optional ParseSingleExecutableConfig( } } + if (!document.at_end()) { + FPrintF(stderr, + "Cannot parse JSON from %s: %s\n", + config_path, + simdjson::error_message(simdjson::TRAILING_CONTENT)); + return std::nullopt; + } + if (static_cast(result.flags & SeaFlags::kUseSnapshot) && static_cast(result.flags & SeaFlags::kUseCodeCache)) { // TODO(joyeecheung): code cache in snapshot should be configured by @@ -754,7 +763,7 @@ void GetAsset(const FunctionCallbackInfo& args) { if (sea_resource.assets.empty()) { return; } - auto it = sea_resource.assets.find(*key); + auto it = sea_resource.assets.find(std::string_view(*key, key.length())); if (it == sea_resource.assets.end()) { return; } diff --git a/src/node_sockaddr.cc b/src/node_sockaddr.cc index 9348f0ac8e4d..e12fb86a3a95 100644 --- a/src/node_sockaddr.cc +++ b/src/node_sockaddr.cc @@ -3,6 +3,7 @@ #include "env-inl.h" #include "memory_tracker-inl.h" #include "nbytes.h" +#include "node_debug.h" #include "node_errors.h" #include "node_hash.h" #include "node_sockaddr-inl.h" // NOLINT(build/include_inline) @@ -15,6 +16,7 @@ namespace node { using v8::Array; +using v8::CFunction; using v8::Context; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; @@ -399,106 +401,321 @@ SocketAddressBlockList::SocketAddressBlockList( std::shared_ptr parent) : parent_(parent) {} -void SocketAddressBlockList::AddSocketAddress( - const std::shared_ptr& address) { - Mutex::ScopedLock lock(mutex_); - std::unique_ptr rule = std::make_unique(address); - rules_.emplace_front(std::move(rule)); - address_rules_[*address.get()] = rules_.begin(); +// --- SubnetTrie implementation --- + +namespace { +inline int GetBit(const uint8_t* bytes, int bit_index) { + return (bytes[bit_index >> 3] >> (7 - (bit_index & 7))) & 1; +} + +inline const uint8_t* GetAddressBytes(const SocketAddress& addr, int* bits) { + if (addr.family() == AF_INET) { + const auto* in = reinterpret_cast(addr.data()); + *bits = 32; + return reinterpret_cast(&in->sin_addr); + } + const auto* in6 = reinterpret_cast(addr.data()); + *bits = 128; + return reinterpret_cast(&in6->sin6_addr); +} +} // namespace + +void SocketAddressBlockList::SubnetTrie::Insert(const uint8_t* address_bytes, + int prefix_length) { + if (root_ == nullptr) { + root_ = std::make_unique(); + } + + Node* node = root_.get(); + for (int i = 0; i < prefix_length; i++) { + if (node->terminal) { + // A broader prefix already covers this subnet. No-op. + return; + } + int bit = GetBit(address_bytes, i); + if (node->children[bit] == nullptr) { + node->children[bit] = std::make_unique(); + } + node = node->children[bit].get(); + } + + if (!node->terminal) { + node->terminal = true; + count_++; + // Prune children — this prefix subsumes all longer prefixes below it. + node->children[0].reset(); + node->children[1].reset(); + } } -void SocketAddressBlockList::RemoveSocketAddress( - const std::shared_ptr& address) { - Mutex::ScopedLock lock(mutex_); - auto it = address_rules_.find(*address.get()); - if (it != std::end(address_rules_)) { - rules_.erase(it->second); - address_rules_.erase(it); +bool SocketAddressBlockList::SubnetTrie::Lookup(const uint8_t* address_bytes, + int address_bits) const { + if (root_ == nullptr) return false; + + const Node* node = root_.get(); + // A terminal root means prefix /0 — matches everything. + if (node->terminal) return true; + + for (int i = 0; i < address_bits; i++) { + int bit = GetBit(address_bytes, i); + node = node->children[bit].get(); + if (node == nullptr) return false; + if (node->terminal) return true; + } + return false; +} + +void SocketAddressBlockList::SubnetTrie::Clear() { + root_.reset(); + count_ = 0; +} + +void SocketAddressBlockList::AddSocketAddressImpl( + const SocketAddress& address) { + if (address_rules_.count(address) == 0) { + address_count_++; + } + address_rules_[address] = address; + // Insert the cross-family counterpart so that both IPv4 and + // IPv4-mapped IPv6 lookups resolve in O(1). + if (address.family() == AF_INET) { + // Map 1.2.3.4 -> ::ffff:1.2.3.4 + std::string mapped = "::ffff:" + address.address(); + SocketAddress ipv6; + if (SocketAddress::New(AF_INET6, mapped.c_str(), address.port(), &ipv6)) { + address_rules_[ipv6] = address; + } + } else if (address.family() == AF_INET6) { + // Check if this is an IPv4-mapped IPv6 address (::ffff:x.x.x.x) + // and insert the IPv4 counterpart if so. + const sockaddr_in6* in6 = + reinterpret_cast(address.data()); + const uint8_t* bytes = reinterpret_cast(&in6->sin6_addr); + constexpr uint8_t ipv4_mapped_prefix[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}; + if (memcmp(bytes, ipv4_mapped_prefix, sizeof(ipv4_mapped_prefix)) == 0) { + sockaddr_in ipv4_addr{}; + ipv4_addr.sin_family = AF_INET; + ipv4_addr.sin_port = in6->sin6_port; + memcpy(&ipv4_addr.sin_addr, bytes + sizeof(ipv4_mapped_prefix), 4); + SocketAddress ipv4(reinterpret_cast(&ipv4_addr)); + address_rules_[ipv4] = address; + } + } +} + +void SocketAddressBlockList::AddSocketAddress(const SocketAddress& address) { + RwLock::ScopedLock lock(mutex_); + AddSocketAddressImpl(address); +} + +void SocketAddressBlockList::AddSocketAddresses(const SocketAddress* addresses, + size_t count) { + RwLock::ScopedLock lock(mutex_); + for (size_t i = 0; i < count; i++) { + AddSocketAddressImpl(addresses[i]); + } +} + +void SocketAddressBlockList::RemoveSocketAddress(const SocketAddress& address) { + RwLock::ScopedLock lock(mutex_); + if (address_rules_.erase(address)) { + address_count_--; + } + // Also remove the cross-family counterpart. + if (address.family() == AF_INET) { + std::string mapped = "::ffff:" + address.address(); + SocketAddress ipv6; + if (SocketAddress::New(AF_INET6, mapped.c_str(), address.port(), &ipv6)) { + address_rules_.erase(ipv6); + } + } else if (address.family() == AF_INET6) { + const sockaddr_in6* in6 = + reinterpret_cast(address.data()); + const uint8_t* bytes = reinterpret_cast(&in6->sin6_addr); + constexpr uint8_t ipv4_mapped_prefix[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}; + if (memcmp(bytes, ipv4_mapped_prefix, sizeof(ipv4_mapped_prefix)) == 0) { + sockaddr_in ipv4_addr{}; + ipv4_addr.sin_family = AF_INET; + ipv4_addr.sin_port = in6->sin6_port; + memcpy(&ipv4_addr.sin_addr, bytes + sizeof(ipv4_mapped_prefix), 4); + SocketAddress ipv4(reinterpret_cast(&ipv4_addr)); + address_rules_.erase(ipv4); + } } } -void SocketAddressBlockList::AddSocketAddressRange( - const std::shared_ptr& start, - const std::shared_ptr& end) { - Mutex::ScopedLock lock(mutex_); +void SocketAddressBlockList::AddSocketAddressRange(const SocketAddress& start, + const SocketAddress& end) { + DCHECK(!(start > end)); + RwLock::ScopedLock lock(mutex_); std::unique_ptr rule = std::make_unique(start, end); rules_.emplace_front(std::move(rule)); } -void SocketAddressBlockList::AddSocketAddressMask( - const std::shared_ptr& network, int prefix) { - Mutex::ScopedLock lock(mutex_); - std::unique_ptr rule = - std::make_unique(network, prefix); - rules_.emplace_front(std::move(rule)); +void SocketAddressBlockList::AddSocketAddressMask(const SocketAddress& network, + int prefix) { + RwLock::ScopedLock lock(mutex_); + int bits; + const uint8_t* bytes = GetAddressBytes(network, &bits); + + if (network.family() == AF_INET) { + ipv4_subnets_.Insert(bytes, prefix); + // Also insert into IPv6 trie as ::ffff:x.x.x.x with prefix+96. + uint8_t mapped[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}; + memcpy(mapped + 12, bytes, 4); + ipv6_subnets_.Insert(mapped, prefix + 96); + } else { + ipv6_subnets_.Insert(bytes, prefix); + // Check if this is a ::ffff:x.x.x.x/N subnet — if so, also insert + // the IPv4 portion into the IPv4 trie. + constexpr uint8_t v4mapped[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}; + if (prefix >= 96 && memcmp(bytes, v4mapped, 12) == 0) { + ipv4_subnets_.Insert(bytes + 12, prefix - 96); + } + } + + // Keep metadata for ListRules serialization. + subnet_rules_.emplace_front( + std::make_unique(network, prefix)); +} + +void SocketAddressBlockList::RemoveSocketAddressRange( + const SocketAddress& start, const SocketAddress& end) { + RwLock::ScopedLock lock(mutex_); + // rules_ contains only SocketAddressRangeRule instances (subnet rules + // are stored separately in subnet_rules_). + for (auto it = rules_.begin(); it != rules_.end(); ++it) { + auto* range = static_cast(it->get()); + if (range->start == start && range->end == end) { + rules_.erase(it); + return; + } + } +} + +void SocketAddressBlockList::RemoveSocketAddressMask( + const SocketAddress& network, int prefix) { + RwLock::ScopedLock lock(mutex_); + + // Remove from subnet_rules_ metadata list. + bool found = false; + for (auto it = subnet_rules_.begin(); it != subnet_rules_.end(); ++it) { + if ((*it)->network == network && (*it)->prefix == prefix) { + subnet_rules_.erase(it); + found = true; + break; + } + } + if (!found) return; + + // Rebuild both tries from the remaining subnet_rules_. This handles the + // case where a broader prefix had subsumed narrower ones in the trie -- + // simply removing the broader prefix from the trie would not restore the + // narrower entries that were pruned on insert. Rebuilding is O(n) in the + // number of subnet rules but removal is not a hot path. + ipv4_subnets_.Clear(); + ipv6_subnets_.Clear(); + for (const auto& rule : subnet_rules_) { + int bits; + const uint8_t* b = GetAddressBytes(rule->network, &bits); + if (rule->network.family() == AF_INET) { + ipv4_subnets_.Insert(b, rule->prefix); + uint8_t mapped[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}; + memcpy(mapped + 12, b, 4); + ipv6_subnets_.Insert(mapped, rule->prefix + 96); + } else { + ipv6_subnets_.Insert(b, rule->prefix); + constexpr uint8_t v4mapped[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}; + if (rule->prefix >= 96 && memcmp(b, v4mapped, 12) == 0) { + ipv4_subnets_.Insert(b + 12, rule->prefix - 96); + } + } + } } bool SocketAddressBlockList::Apply(const SocketAddress& address) { - Mutex::ScopedLock lock(mutex_); + RwLock::ScopedReadLock lock(mutex_); + // O(1) lookup for exact address matches. The address_rules_ map + // uses IpHash/IpEqual (port-insensitive, family-sensitive). + if (address_rules_.count(address)) return true; + + // O(prefix_length) lookup for subnet/mask rules via radix trie. + int bits; + const uint8_t* bytes = GetAddressBytes(address, &bits); + if (address.family() == AF_INET) { + if (ipv4_subnets_.Lookup(bytes, bits)) return true; + // Also check IPv6 trie for ::ffff:x.x.x.x subnets. + uint8_t mapped[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}; + memcpy(mapped + 12, bytes, 4); + if (ipv6_subnets_.Lookup(mapped, 128)) return true; + } else { + if (ipv6_subnets_.Lookup(bytes, bits)) return true; + // Check if this is ::ffff:x.x.x.x — also check IPv4 trie. + constexpr uint8_t v4mapped[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}; + if (memcmp(bytes, v4mapped, 12) == 0) { + if (ipv4_subnets_.Lookup(bytes + 12, 32)) return true; + } + } + + // Linear scan for range rules only. Subnet rules are in the trie. for (const auto& rule : rules_) { if (rule->Apply(address)) return true; } return parent_ ? parent_->Apply(address) : false; } -SocketAddressBlockList::SocketAddressRule::SocketAddressRule( - const std::shared_ptr& address_) - : address(address_) {} +void SocketAddressBlockList::Clear() { + RwLock::ScopedLock lock(mutex_); + rules_.clear(); + address_rules_.clear(); + address_count_ = 0; + ipv4_subnets_.Clear(); + ipv6_subnets_.Clear(); + subnet_rules_.clear(); +} SocketAddressBlockList::SocketAddressRangeRule::SocketAddressRangeRule( - const std::shared_ptr& start_, - const std::shared_ptr& end_) + const SocketAddress& start_, const SocketAddress& end_) : start(start_), end(end_) {} SocketAddressBlockList::SocketAddressMaskRule::SocketAddressMaskRule( - const std::shared_ptr& network_, int prefix_) + const SocketAddress& network_, int prefix_) : network(network_), prefix(prefix_) {} -bool SocketAddressBlockList::SocketAddressRule::Apply( - const SocketAddress& address) { - return this->address->is_match(address); -} - -std::string SocketAddressBlockList::SocketAddressRule::ToString() { - std::string ret = "Address: "; - ret += address->family() == AF_INET ? "IPv4" : "IPv6"; - ret += " "; - ret += address->address(); - return ret; -} - bool SocketAddressBlockList::SocketAddressRangeRule::Apply( const SocketAddress& address) { - return address >= *start.get() && address <= *end.get(); + return address >= start && address <= end; } std::string SocketAddressBlockList::SocketAddressRangeRule::ToString() { std::string ret = "Range: "; - ret += start->family() == AF_INET ? "IPv4" : "IPv6"; + ret += start.family() == AF_INET ? "IPv4" : "IPv6"; ret += " "; - ret += start->address(); + ret += start.address(); ret += "-"; - ret += end->address(); + ret += end.address(); return ret; } bool SocketAddressBlockList::SocketAddressMaskRule::Apply( const SocketAddress& address) { - return address.is_in_network(*network.get(), prefix); + return address.is_in_network(network, prefix); } std::string SocketAddressBlockList::SocketAddressMaskRule::ToString() { std::string ret = "Subnet: "; - ret += network->family() == AF_INET ? "IPv4" : "IPv6"; + ret += network.family() == AF_INET ? "IPv4" : "IPv6"; ret += " "; - ret += network->address(); + ret += network.address(); ret += "/" + std::to_string(prefix); return ret; } MaybeLocal SocketAddressBlockList::ListRules(Environment* env) { - Mutex::ScopedLock lock(mutex_); + RwLock::ScopedReadLock lock(mutex_); LocalVector rules(env->isolate()); if (!ListRules(env, &rules)) return MaybeLocal(); return Array::New(env->isolate(), rules.data(), rules.size()); @@ -506,22 +723,42 @@ MaybeLocal SocketAddressBlockList::ListRules(Environment* env) { bool SocketAddressBlockList::ListRules(Environment* env, LocalVector* rules) { - if (parent_ && !parent_->ListRules(env, rules)) return false; + // List local rules first, then parent rules, matching the + // evaluation order in Apply(). + // + // address_rules_ may contain cross-family duplicates (e.g. both + // 1.1.1.1 and ::ffff:1.1.1.1 map to the same original address). + // Track which originals have been listed to avoid duplicates. + SocketAddress::Map seen; + for (const auto& [_, address] : address_rules_) { + if (seen.count(address)) continue; + seen[address] = true; + std::string str = "Address: "; + str += address.family() == AF_INET ? "IPv4" : "IPv6"; + str += " "; + str += address.address(); + Local v; + if (!ToV8Value(env->context(), str).ToLocal(&v)) return false; + rules->push_back(v); + } + for (const auto& rule : subnet_rules_) { + Local str; + if (!rule->ToV8String(env).ToLocal(&str)) return false; + rules->push_back(str); + } for (const auto& rule : rules_) { Local str; if (!rule->ToV8String(env).ToLocal(&str)) return false; rules->push_back(str); } - return true; + return !parent_ || parent_->ListRules(env, rules); } void SocketAddressBlockList::MemoryInfo(node::MemoryTracker* tracker) const { tracker->TrackField("rules", rules_); -} - -void SocketAddressBlockList::SocketAddressRule::MemoryInfo( - node::MemoryTracker* tracker) const { - tracker->TrackField("address", address); + tracker->TrackFieldWithSize("address_rules", + address_rules_.size() * sizeof(SocketAddress)); + tracker->TrackField("subnet_rules", subnet_rules_); } void SocketAddressBlockList::SocketAddressRangeRule::MemoryInfo( @@ -590,8 +827,34 @@ void SocketAddressBlockListWrap::AddAddress( SocketAddressBase* addr; ASSIGN_OR_RETURN_UNWRAP(&addr, args[0]); - wrap->blocklist_->AddSocketAddress(addr->address()); + wrap->blocklist_->AddSocketAddress(*addr->address()); + + args.GetReturnValue().Set(true); +} + +void SocketAddressBlockListWrap::AddAddresses( + const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + SocketAddressBlockListWrap* wrap; + ASSIGN_OR_RETURN_UNWRAP(&wrap, args.This()); + + CHECK(args[0]->IsArray()); + Local arr = args[0].As(); + uint32_t len = arr->Length(); + std::vector addresses; + addresses.reserve(len); + + for (uint32_t i = 0; i < len; i++) { + Local item; + if (!arr->Get(env->context(), i).ToLocal(&item)) return; + CHECK(SocketAddressBase::HasInstance(env, item)); + SocketAddressBase* addr; + ASSIGN_OR_RETURN_UNWRAP(&addr, item.As()); + addresses.push_back(*addr->address()); + } + + wrap->blocklist_->AddSocketAddresses(addresses.data(), addresses.size()); args.GetReturnValue().Set(true); } @@ -610,11 +873,11 @@ void SocketAddressBlockListWrap::AddRange( ASSIGN_OR_RETURN_UNWRAP(&end_addr, args[1]); // Starting address must come before the end address - if (*start_addr->address().get() > *end_addr->address().get()) + if (*start_addr->address() > *end_addr->address()) return args.GetReturnValue().Set(false); - wrap->blocklist_->AddSocketAddressRange(start_addr->address(), - end_addr->address()); + wrap->blocklist_->AddSocketAddressRange(*start_addr->address(), + *end_addr->address()); args.GetReturnValue().Set(true); } @@ -640,11 +903,62 @@ void SocketAddressBlockListWrap::AddSubnet( CHECK_IMPLIES(addr->address()->family() == AF_INET6, prefix <= 128); CHECK_GE(prefix, 0); - wrap->blocklist_->AddSocketAddressMask(addr->address(), prefix); + wrap->blocklist_->AddSocketAddressMask(*addr->address(), prefix); args.GetReturnValue().Set(true); } +void SocketAddressBlockListWrap::RemoveAddress( + const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + SocketAddressBlockListWrap* wrap; + ASSIGN_OR_RETURN_UNWRAP(&wrap, args.This()); + + CHECK(SocketAddressBase::HasInstance(env, args[0])); + SocketAddressBase* addr; + ASSIGN_OR_RETURN_UNWRAP(&addr, args[0]); + + wrap->blocklist_->RemoveSocketAddress(*addr->address()); +} + +void SocketAddressBlockListWrap::RemoveRange( + const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + SocketAddressBlockListWrap* wrap; + ASSIGN_OR_RETURN_UNWRAP(&wrap, args.This()); + + CHECK(SocketAddressBase::HasInstance(env, args[0])); + CHECK(SocketAddressBase::HasInstance(env, args[1])); + + SocketAddressBase* start_addr; + SocketAddressBase* end_addr; + ASSIGN_OR_RETURN_UNWRAP(&start_addr, args[0]); + ASSIGN_OR_RETURN_UNWRAP(&end_addr, args[1]); + + wrap->blocklist_->RemoveSocketAddressRange(*start_addr->address(), + *end_addr->address()); +} + +void SocketAddressBlockListWrap::RemoveSubnet( + const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + SocketAddressBlockListWrap* wrap; + ASSIGN_OR_RETURN_UNWRAP(&wrap, args.This()); + + CHECK(SocketAddressBase::HasInstance(env, args[0])); + CHECK(args[1]->IsInt32()); + + SocketAddressBase* addr; + ASSIGN_OR_RETURN_UNWRAP(&addr, args[0]); + + int32_t prefix; + if (!args[1]->Int32Value(env->context()).To(&prefix)) { + return; + } + + wrap->blocklist_->RemoveSocketAddressMask(*addr->address(), prefix); +} + void SocketAddressBlockListWrap::Check( const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); @@ -658,6 +972,39 @@ void SocketAddressBlockListWrap::Check( args.GetReturnValue().Set(wrap->blocklist_->Apply(*addr->address())); } +bool SocketAddressBlockListWrap::FastCheck(Local receiver, + Local addr_obj) { + TRACK_V8_FAST_API_CALL("blocklist.check"); + SocketAddressBlockListWrap* wrap = + FromJSObject(receiver); + SocketAddressBase* addr = FromJSObject(addr_obj); + return wrap->blocklist_->Apply(*addr->address()); +} + +CFunction SocketAddressBlockListWrap::fast_check_( + CFunction::Make(&SocketAddressBlockListWrap::FastCheck)); + +void SocketAddressBlockListWrap::CheckString( + const FunctionCallbackInfo& args) { + SocketAddressBlockListWrap* wrap; + ASSIGN_OR_RETURN_UNWRAP(&wrap, args.This()); + + CHECK(args[0]->IsString()); + CHECK(args[1]->IsInt32()); + + Utf8Value address(args.GetIsolate(), args[0]); + int32_t family = args[1].As()->Value(); + + SocketAddress addr; + if (!SocketAddress::New(family, *address, 0, &addr)) { + // Invalid address string — return false (not blocked). + args.GetReturnValue().Set(false); + return; + } + + args.GetReturnValue().Set(wrap->blocklist_->Apply(addr)); +} + void SocketAddressBlockListWrap::GetRules( const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); @@ -668,6 +1015,20 @@ void SocketAddressBlockListWrap::GetRules( args.GetReturnValue().Set(rules); } +void SocketAddressBlockListWrap::GetSize( + const FunctionCallbackInfo& args) { + SocketAddressBlockListWrap* wrap; + ASSIGN_OR_RETURN_UNWRAP(&wrap, args.This()); + args.GetReturnValue().Set(static_cast(wrap->blocklist_->size())); +} + +void SocketAddressBlockListWrap::Clear( + const FunctionCallbackInfo& args) { + SocketAddressBlockListWrap* wrap; + ASSIGN_OR_RETURN_UNWRAP(&wrap, args.This()); + wrap->blocklist_->Clear(); +} + void SocketAddressBlockListWrap::MemoryInfo(MemoryTracker* tracker) const { blocklist_->MemoryInfo(tracker); } @@ -691,10 +1052,18 @@ Local SocketAddressBlockListWrap::GetConstructorTemplate( tmpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "BlockList")); tmpl->InstanceTemplate()->SetInternalFieldCount(kInternalFieldCount); SetProtoMethod(isolate, tmpl, "addAddress", AddAddress); + SetProtoMethod(isolate, tmpl, "addAddresses", AddAddresses); SetProtoMethod(isolate, tmpl, "addRange", AddRange); SetProtoMethod(isolate, tmpl, "addSubnet", AddSubnet); - SetProtoMethod(isolate, tmpl, "check", Check); + SetProtoMethod(isolate, tmpl, "removeAddress", RemoveAddress); + SetProtoMethod(isolate, tmpl, "removeRange", RemoveRange); + SetProtoMethod(isolate, tmpl, "removeSubnet", RemoveSubnet); + SetFastMethod( + isolate, tmpl->PrototypeTemplate(), "check", Check, &fast_check_); + SetProtoMethod(isolate, tmpl, "checkString", CheckString); SetProtoMethod(isolate, tmpl, "getRules", GetRules); + SetProtoMethodNoSideEffect(isolate, tmpl, "getSize", GetSize); + SetProtoMethod(isolate, tmpl, "clear", Clear); env->set_blocklist_constructor_template(tmpl); } return tmpl; diff --git a/src/node_sockaddr.h b/src/node_sockaddr.h index 05bb127b012f..55354138fa84 100644 --- a/src/node_sockaddr.h +++ b/src/node_sockaddr.h @@ -248,19 +248,29 @@ class SocketAddressBlockList : public MemoryRetainer { std::shared_ptr parent = {}); ~SocketAddressBlockList() = default; - void AddSocketAddress(const std::shared_ptr& address); + void AddSocketAddress(const SocketAddress& address); - void RemoveSocketAddress(const std::shared_ptr& address); + void AddSocketAddresses(const SocketAddress* addresses, size_t count); - void AddSocketAddressRange(const std::shared_ptr& start, - const std::shared_ptr& end); + void RemoveSocketAddress(const SocketAddress& address); - void AddSocketAddressMask(const std::shared_ptr& address, - int prefix); + void AddSocketAddressRange(const SocketAddress& start, + const SocketAddress& end); + + void RemoveSocketAddressRange(const SocketAddress& start, + const SocketAddress& end); + + void AddSocketAddressMask(const SocketAddress& address, int prefix); + + void RemoveSocketAddressMask(const SocketAddress& address, int prefix); bool Apply(const SocketAddress& address); - size_t size() const { return rules_.size(); } + void Clear(); + + size_t size() const { + return address_count_ + rules_.size() + subnet_rules_.size(); + } v8::MaybeLocal ListRules(Environment* env); @@ -270,25 +280,12 @@ class SocketAddressBlockList : public MemoryRetainer { virtual std::string ToString() = 0; }; - struct SocketAddressRule final : Rule { - std::shared_ptr address; - - explicit SocketAddressRule(const std::shared_ptr& address); - - bool Apply(const SocketAddress& address) override; - std::string ToString() override; - - void MemoryInfo(node::MemoryTracker* tracker) const override; - SET_MEMORY_INFO_NAME(SocketAddressRule) - SET_SELF_SIZE(SocketAddressRule) - }; - struct SocketAddressRangeRule final : Rule { - std::shared_ptr start; - std::shared_ptr end; + SocketAddress start; + SocketAddress end; - SocketAddressRangeRule(const std::shared_ptr& start, - const std::shared_ptr& end); + SocketAddressRangeRule(const SocketAddress& start, + const SocketAddress& end); bool Apply(const SocketAddress& address) override; std::string ToString() override; @@ -299,11 +296,10 @@ class SocketAddressBlockList : public MemoryRetainer { }; struct SocketAddressMaskRule final : Rule { - std::shared_ptr network; + SocketAddress network; int prefix; - SocketAddressMaskRule(const std::shared_ptr& address, - int prefix); + SocketAddressMaskRule(const SocketAddress& address, int prefix); bool Apply(const SocketAddress& address) override; std::string ToString() override; @@ -317,14 +313,68 @@ class SocketAddressBlockList : public MemoryRetainer { SET_MEMORY_INFO_NAME(SocketAddressBlockList) SET_SELF_SIZE(SocketAddressBlockList) + // A compressed radix trie for O(prefix_length) subnet lookups. + // Each node has two children (bit 0, bit 1). A node marked + // terminal means all addresses matching the prefix up to that + // depth are blocked. On insert, if a new prefix is shorter than + // or equal to an existing one, the subtree is pruned (the shorter + // prefix subsumes all longer ones). On lookup, we walk the bits + // of the address and return true as soon as we hit a terminal node. + class SubnetTrie { + public: + SubnetTrie() = default; + ~SubnetTrie() = default; + + // Insert a subnet (network address bytes, prefix length in bits). + // If a broader prefix already exists, the insert is a no-op. + // If this prefix is broader than existing children, they are pruned. + void Insert(const uint8_t* address_bytes, int prefix_length); + + // Returns true if the given address falls within any inserted subnet. + bool Lookup(const uint8_t* address_bytes, int address_bits) const; + + // Remove all entries. + void Clear(); + + bool empty() const { return root_ == nullptr; } + + size_t size() const { return count_; } + + private: + struct Node { + std::unique_ptr children[2]; + bool terminal = false; + }; + + std::unique_ptr root_; + size_t count_ = 0; + }; + private: + // Lock-free implementation used by both AddSocketAddress and + // AddSocketAddresses. Caller must hold the write lock. + void AddSocketAddressImpl(const SocketAddress& address); bool ListRules(Environment* env, v8::LocalVector* vec); std::shared_ptr parent_; + // Range rules only. Scanned linearly by Apply(). std::list> rules_; - SocketAddress::Map>::iterator> address_rules_; - - Mutex mutex_; + // Exact address rules. Keyed by IP only (port-insensitive) so that + // Apply() can perform O(1) lookups regardless of the port on the + // checked address. Not included in rules_ to avoid redundant scanning. + SocketAddress::IpMap address_rules_; + // User-visible address count (not inflated by cross-family dual-insert). + size_t address_count_ = 0; + // Subnet/mask rules stored in radix tries for O(prefix_length) lookup. + // Separate tries for IPv4 (max 32-bit depth) and IPv6 (max 128-bit). + SubnetTrie ipv4_subnets_; + SubnetTrie ipv6_subnets_; + // Subnet metadata kept for ListRules serialization only. + std::list> subnet_rules_; + + // RwLock allows concurrent Apply() calls (shared/read lock) while + // mutations (Add*/Remove*/Clear) take an exclusive/write lock. + mutable RwLock mutex_; }; class SocketAddressBlockListWrap : public BaseObject { @@ -343,10 +393,19 @@ class SocketAddressBlockListWrap : public BaseObject { static void New(const v8::FunctionCallbackInfo& args); static void AddAddress(const v8::FunctionCallbackInfo& args); + static void AddAddresses(const v8::FunctionCallbackInfo& args); static void AddRange(const v8::FunctionCallbackInfo& args); static void AddSubnet(const v8::FunctionCallbackInfo& args); + static void RemoveAddress(const v8::FunctionCallbackInfo& args); + static void RemoveRange(const v8::FunctionCallbackInfo& args); + static void RemoveSubnet(const v8::FunctionCallbackInfo& args); static void Check(const v8::FunctionCallbackInfo& args); + static bool FastCheck(v8::Local receiver, + v8::Local addr_obj); + static void CheckString(const v8::FunctionCallbackInfo& args); static void GetRules(const v8::FunctionCallbackInfo& args); + static void GetSize(const v8::FunctionCallbackInfo& args); + static void Clear(const v8::FunctionCallbackInfo& args); SocketAddressBlockListWrap(Environment* env, v8::Local wrap, @@ -390,6 +449,7 @@ class SocketAddressBlockListWrap : public BaseObject { private: std::shared_ptr blocklist_; + static v8::CFunction fast_check_; }; } // namespace node diff --git a/src/node_sqlite.cc b/src/node_sqlite.cc index cf9db75a84f9..ee6a2ece5426 100644 --- a/src/node_sqlite.cc +++ b/src/node_sqlite.cc @@ -121,6 +121,10 @@ inline MaybeLocal Utf8StringMaybeOneByte(Isolate* isolate, case SQLITE_TEXT: { \ const char* v = \ reinterpret_cast(sqlite3_##from##_text(__VA_ARGS__)); \ + if (v == nullptr) [[unlikely]] { \ + THROW_ERR_MEMORY_ALLOCATION_FAILED((isolate)); \ + break; \ + } \ const int v_len = sqlite3_##from##_bytes(__VA_ARGS__); \ (result) = \ Utf8StringMaybeOneByte((isolate), std::string_view(v, v_len)) \ @@ -138,7 +142,9 @@ inline MaybeLocal Utf8StringMaybeOneByte(Isolate* isolate, sqlite3_##from##_blob(__VA_ARGS__)); \ auto store = ArrayBuffer::NewBackingStore( \ (isolate), size, BackingStoreInitializationMode::kUninitialized); \ - memcpy(store->Data(), data, size); \ + if (data != nullptr) [[likely]] { \ + memcpy(store->Data(), data, size); \ + } \ auto ab = ArrayBuffer::New((isolate), std::move(store)); \ (result) = Uint8Array::New(ab, 0, size); \ break; \ @@ -235,7 +241,8 @@ void JSValueToSQLiteResult(Isolate* isolate, } else if (value->IsString()) { Utf8Value val(isolate, value.As()); sqlite3_result_text(ctx, *val, val.length(), SQLITE_TRANSIENT); - } else if (value->IsArrayBufferView()) { + } else if (value->IsArrayBufferView() || value->IsArrayBuffer() || + value->IsSharedArrayBuffer()) { ArrayBufferViewContents buf(value); sqlite3_result_blob(ctx, buf.data(), buf.length(), SQLITE_TRANSIENT); } else if (value->IsBigInt()) { @@ -1067,10 +1074,23 @@ void DatabaseSync::CreateTagStore(const FunctionCallbackInfo& args) { return; } int capacity = 1000; - if (args.Length() > 0 && args[0]->IsNumber()) { - capacity = args[0].As()->Value(); + if (args.Length() > 0 && !args[0]->IsUndefined()) { + if (!args[0]->IsNumber()) { + THROW_ERR_INVALID_ARG_TYPE( + env->isolate(), + "The \"maxSize\" argument must be a positive integer."); + return; + } + double val = args[0].As()->Value(); + if (std::floor(val) != val || val <= 0 || + val > std::numeric_limits::max()) { + THROW_ERR_OUT_OF_RANGE( + env->isolate(), + "The \"maxSize\" argument must be a positive integer."); + return; + } + capacity = static_cast(val); } - BaseObjectPtr session = SQLTagStore::Create(env, BaseObjectWeakPtr(db), capacity); if (!session) { @@ -1551,6 +1571,16 @@ void DatabaseSync::Prepare(const FunctionCallbackInfo& args) { int r = sqlite3_prepare_v2(db->connection_, *sql, -1, &s, nullptr); CHECK_ERROR_OR_THROW(env->isolate(), db, r, SQLITE_OK, void()); + + // sqlite3_prepare_v2() reports success without producing a statement when + // the input holds no SQL, such as a comment. Such a statement can never be + // stepped, and tracking it would leave a dangling pointer in statements_ + // because its destructor treats a null statement as already finalized. + if (s == nullptr) { + THROW_ERR_INVALID_ARG_VALUE(env, "The SQL query contains no statements."); + return; + } + BaseObjectPtr stmt = StatementSync::Create(env, BaseObjectPtr(db), s); db->statements_.insert(stmt.get()); @@ -2179,6 +2209,12 @@ void Backup(const FunctionCallbackInfo& args) { return; } rate = rate_v.As()->Value(); + if (rate <= 0) { + THROW_ERR_OUT_OF_RANGE( + env->isolate(), + "The \"options.rate\" argument must be a positive integer."); + return; + } } Local source_v; @@ -2637,7 +2673,8 @@ bool StatementSync::BindParams(const FunctionCallbackInfo& args) { int anon_idx = 1; int anon_start = 0; - if (args[0]->IsObject() && !args[0]->IsArrayBufferView()) { + if (args[0]->IsObject() && !args[0]->IsArrayBufferView() && + !args[0]->IsArrayBuffer() && !args[0]->IsSharedArrayBuffer()) { Local obj = args[0].As(); Local context = obj->GetIsolate()->GetCurrentContext(); Local keys; @@ -2734,10 +2771,11 @@ bool StatementSync::BindParams(const FunctionCallbackInfo& args) { bool StatementSync::BindValue(const Local& value, const int index) { // SQLite only supports a subset of JavaScript types. Some JS types such as - // functions don't make sense to support. Other JS types such as booleans and + // functions don't make sense to support. Other JS types such as // Dates could be supported by converting them to numbers. However, there // would not be a good way to read the values back from SQLite with the - // original type. + // original type. JS Boolean binds to 1 and 0 because SQLite maps true and + // false keywords to 1 and 0. Isolate* isolate = env()->isolate(); int r; if (value->IsNumber()) { @@ -2763,13 +2801,16 @@ bool StatementSync::BindValue(const Local& value, const int index) { } } else if (value->IsNull()) { r = sqlite3_bind_null(statement_, index); - } else if (value->IsArrayBufferView()) { + } else if (value->IsArrayBufferView() || value->IsArrayBuffer() || + value->IsSharedArrayBuffer()) { ArrayBufferViewContents buf(value); r = sqlite3_bind_blob64(statement_, index, buf.data(), static_cast(buf.length()), SQLITE_TRANSIENT); + } else if (value->IsBoolean()) { + r = sqlite3_bind_int(statement_, index, value->IsTrue() ? 1 : 0); } else if (value->IsBigInt()) { bool lossless; int64_t as_int = value.As()->Int64Value(&lossless); @@ -3381,6 +3422,35 @@ void SQLTagStore::SizeGetter(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(static_cast(store->sql_tags_.Size())); } +bool SQLTagStore::ResetAndBindStatement( + Environment* env, + StatementSync* stmt, + const FunctionCallbackInfo& args) { + Isolate* isolate = env->isolate(); + int r = stmt->ResetStatement(); + CHECK_ERROR_OR_THROW(isolate, stmt->db_.get(), r, SQLITE_OK, false); + + r = sqlite3_clear_bindings(stmt->statement_); + CHECK_ERROR_OR_THROW(isolate, stmt->db_.get(), r, SQLITE_OK, false); + + uint32_t n_params = args.Length() - 1; + int param_count = sqlite3_bind_parameter_count(stmt->statement_); + if (param_count != static_cast(n_params)) { + THROW_ERR_INVALID_ARG_VALUE( + env, + "SQLite parameters must be bound using template literal placeholders."); + return false; + } + + for (int i = 0; i < param_count; ++i) { + if (!stmt->BindValue(args[i + 1], i + 1)) { + return false; + } + } + + return true; +} + void SQLTagStore::Run(const FunctionCallbackInfo& args) { SQLTagStore* session; ASSIGN_OR_RETURN_UNWRAP(&session, args.This()); @@ -3395,15 +3465,8 @@ void SQLTagStore::Run(const FunctionCallbackInfo& args) { return; } - uint32_t n_params = args.Length() - 1; - int r = stmt->ResetStatement(); - CHECK_ERROR_OR_THROW(env->isolate(), stmt->db_.get(), r, SQLITE_OK, void()); - int param_count = sqlite3_bind_parameter_count(stmt->statement_); - for (int i = 0; i < static_cast(n_params) && i < param_count; ++i) { - Local value = args[i + 1]; - if (!stmt->BindValue(value, i + 1)) { - return; - } + if (!ResetAndBindStatement(env, stmt.get(), args)) { + return; } Local result; @@ -3428,15 +3491,8 @@ void SQLTagStore::Iterate(const FunctionCallbackInfo& args) { return; } - uint32_t n_params = args.Length() - 1; - int r = stmt->ResetStatement(); - CHECK_ERROR_OR_THROW(env->isolate(), stmt->db_.get(), r, SQLITE_OK, void()); - int param_count = sqlite3_bind_parameter_count(stmt->statement_); - for (int i = 0; i < static_cast(n_params) && i < param_count; ++i) { - Local value = args[i + 1]; - if (!stmt->BindValue(value, i + 1)) { - return; - } + if (!ResetAndBindStatement(env, stmt.get(), args)) { + return; } BaseObjectPtr iter = StatementExecutionHelper::Iterate( @@ -3463,18 +3519,8 @@ void SQLTagStore::Get(const FunctionCallbackInfo& args) { return; } - uint32_t n_params = args.Length() - 1; - Isolate* isolate = env->isolate(); - - int r = stmt->ResetStatement(); - CHECK_ERROR_OR_THROW(isolate, stmt->db_.get(), r, SQLITE_OK, void()); - - int param_count = sqlite3_bind_parameter_count(stmt->statement_); - for (int i = 0; i < static_cast(n_params) && i < param_count; ++i) { - Local value = args[i + 1]; - if (!stmt->BindValue(value, i + 1)) { - return; - } + if (!ResetAndBindStatement(env, stmt.get(), args)) { + return; } Local result; @@ -3502,18 +3548,8 @@ void SQLTagStore::All(const FunctionCallbackInfo& args) { return; } - uint32_t n_params = args.Length() - 1; - Isolate* isolate = env->isolate(); - - int r = stmt->ResetStatement(); - CHECK_ERROR_OR_THROW(isolate, stmt->db_.get(), r, SQLITE_OK, void()); - - int param_count = sqlite3_bind_parameter_count(stmt->statement_); - for (int i = 0; i < static_cast(n_params) && i < param_count; ++i) { - Local value = args[i + 1]; - if (!stmt->BindValue(value, i + 1)) { - return; - } + if (!ResetAndBindStatement(env, stmt.get(), args)) { + return; } auto reset = OnScopeLeave([&]() { sqlite3_reset(stmt->statement_); }); @@ -3593,6 +3629,13 @@ BaseObjectPtr SQLTagStore::PrepareStatement( return BaseObjectPtr(); } + // As in DatabaseSync::Prepare(), reject input that holds no SQL rather + // than caching a statement that can never be bound or stepped. + if (s == nullptr) { + THROW_ERR_INVALID_ARG_VALUE(env, "The SQL query contains no statements."); + return BaseObjectPtr(); + } + BaseObjectPtr stmt_obj = StatementSync::Create( env, BaseObjectPtr(session->database_), s); @@ -3878,6 +3921,10 @@ void Session::Changeset(const FunctionCallbackInfo& args) { THROW_AND_RETURN_ON_BAD_STATE( env, session->session_ == nullptr, "session is not open"); + session->is_generating_changeset_ = true; + auto changeset_guard = + OnScopeLeave([&] { session->is_generating_changeset_ = false; }); + int nChangeset; void* pChangeset; int r = sqliteChangesetFunc(session->session_, &nChangeset, &pChangeset); @@ -3887,7 +3934,9 @@ void Session::Changeset(const FunctionCallbackInfo& args) { auto freeChangeset = OnScopeLeave([&] { sqlite3_free(pChangeset); }); Local buffer = ArrayBuffer::New(env->isolate(), nChangeset); - std::memcpy(buffer->GetBackingStore()->Data(), pChangeset, nChangeset); + if (nChangeset > 0) { + std::memcpy(buffer->GetBackingStore()->Data(), pChangeset, nChangeset); + } Local uint8Array = Uint8Array::New(buffer, 0, nChangeset); args.GetReturnValue().Set(uint8Array); @@ -3901,6 +3950,8 @@ void Session::Close(const FunctionCallbackInfo& args) { env, !session->database_->IsOpen(), "database is not open"); THROW_AND_RETURN_ON_BAD_STATE( env, session->session_ == nullptr, "session is not open"); + THROW_AND_RETURN_ON_BAD_STATE( + env, session->is_generating_changeset_, "session is currently in use"); session->Delete(); } diff --git a/src/node_sqlite.h b/src/node_sqlite.h index 48463b215cb3..9c7a4380dcf5 100644 --- a/src/node_sqlite.h +++ b/src/node_sqlite.h @@ -361,6 +361,7 @@ class Session : public BaseObject { void Delete(); sqlite3_session* session_; BaseObjectPtr database_; // The Parent Database + bool is_generating_changeset_ = false; friend class DatabaseSync; }; @@ -396,6 +397,10 @@ class SQLTagStore : public BaseObject { private: static BaseObjectPtr PrepareStatement( const v8::FunctionCallbackInfo& args); + static bool ResetAndBindStatement( + Environment* env, + StatementSync* stmt, + const v8::FunctionCallbackInfo& args); BaseObjectWeakPtr database_; LRUCache> sql_tags_; friend class StatementExecutionHelper; diff --git a/src/node_task_runner.cc b/src/node_task_runner.cc index 22c02e83e12e..4e20279fa2e7 100644 --- a/src/node_task_runner.cc +++ b/src/node_task_runner.cc @@ -60,7 +60,11 @@ ProcessRunner::ProcessRunner(std::shared_ptr result, } #ifdef _WIN32 - if (file_.ends_with("cmd.exe")) { + static constexpr std::string_view cmd_exe = "cmd.exe"; + if (file_.size() >= cmd_exe.size() && + StringEqualNoCaseN(file_.data() + file_.size() - cmd_exe.size(), + cmd_exe.data(), + cmd_exe.size())) { // If the file is cmd.exe, use the following command line arguments: // "/c" Carries out the command and exit. // "/d" Disables execution of AutoRun commands. @@ -150,7 +154,7 @@ std::string EscapeShell(const std::string_view input) { } static constexpr std::string_view forbidden_characters = - "[\t\n\r \"#$&'()*;<>?\\\\`|~]"; + "[\t\n\r \"#$&'()*;<>%?\\\\`|~]"; // Check if input contains any forbidden characters // If it doesn't, return the input as is. @@ -170,6 +174,7 @@ std::string EscapeShell(const std::string_view input) { static const std::regex tripleSingleQuote("\\\\\"\"\""); escaped = std::regex_replace(escaped, leadingQuotePairs, ""); escaped = std::regex_replace(escaped, tripleSingleQuote, "\\\""); + escaped = std::regex_replace(escaped, std::regex("%"), "^%"); #else // Replace single quotes("'") with `'"'"'` and wrap the result // in single quotes. diff --git a/src/node_url.cc b/src/node_url.cc index 5f5241f6c674..7f32a83177f4 100644 --- a/src/node_url.cc +++ b/src/node_url.cc @@ -8,6 +8,7 @@ #include "node_metadata.h" #include "node_process-inl.h" #include "path.h" +#include "simdutf.h" #include "util-inl.h" #include "v8-fast-api-calls.h" #include "v8-local-handle.h" @@ -33,6 +34,42 @@ using v8::SnapshotCreator; using v8::String; using v8::Value; +namespace { + +// Parse a V8 string as a URL. One-byte ASCII inputs are parsed in place +// without allocating a UTF-8 copy. When `reuse_input` is non-null it is set +// if the serialized href is identical to that ASCII input so the caller can +// return the original V8 string. Omit it when the caller will not reuse the +// input, to skip the O(n) href comparison. Non-ASCII inputs are never reused: +// UTF-8 conversion may replace unpaired surrogates, so the original string +// may not match href. +ada::result ParseUrlFromV8String( + Isolate* isolate, + Local input, + const ada::url_aggregator* base_url, + bool* reuse_input = nullptr) { + { + String::ValueView view(isolate, input); + if (view.is_one_byte()) { + const char* data = reinterpret_cast(view.data8()); + const size_t length = static_cast(view.length()); + if (simdutf::validate_ascii(data, length)) [[likely]] { + const std::string_view input_view(data, length); + auto out = ada::parse(input_view, base_url); + if (reuse_input != nullptr) { + *reuse_input = out.has_value() && out->get_href() == input_view; + } + return out; + } + } + } + if (reuse_input != nullptr) *reuse_input = false; + Utf8Value utf8(isolate, input); + return ada::parse(utf8.ToStringView(), base_url); +} + +} // namespace + void BindingData::MemoryInfo(MemoryTracker* tracker) const { tracker->TrackField("url_components_buffer", url_components_buffer_); } @@ -392,32 +429,49 @@ void BindingData::Parse(const FunctionCallbackInfo& args) { Realm* realm = Realm::GetCurrent(args); BindingData* binding_data = realm->GetBindingData(); Isolate* isolate = realm->isolate(); - std::optional base_{}; + Local input_string = args[0].As(); - Utf8Value input(isolate, args[0]); ada::result base; ada::url_aggregator* base_pointer = nullptr; if (args[1]->IsString()) { - base_ = Utf8Value(isolate, args[1]).ToString(); - base = ada::parse(*base_); - if (!base && raise_exception) { - return ThrowInvalidURL(realm->env(), input.ToStringView(), base_); - } else if (!base) { + base = ParseUrlFromV8String(isolate, args[1].As(), nullptr); + if (!base) { + if (raise_exception) { + Utf8Value input(isolate, input_string); + Utf8Value base_utf8(isolate, args[1]); + return ThrowInvalidURL( + realm->env(), input.ToStringView(), base_utf8.ToString()); + } return; } base_pointer = &base.value(); } - auto out = - ada::parse(input.ToStringView(), base_pointer); - if (!out && raise_exception) { - return ThrowInvalidURL(realm->env(), input.ToStringView(), base_); - } else if (!out) { + bool reuse_input = false; + auto out = + ParseUrlFromV8String(isolate, input_string, base_pointer, &reuse_input); + if (!out) { + if (raise_exception) { + Utf8Value input(isolate, input_string); + std::optional base_error; + if (args[1]->IsString()) { + base_error = Utf8Value(isolate, args[1]).ToString(); + } + return ThrowInvalidURL( + realm->env(), input.ToStringView(), std::move(base_error)); + } return; } binding_data->UpdateComponents(out->get_components(), out->type); + // Already-serialized ASCII URLs are the common case. Reuse the input + // string instead of allocating an identical V8 string from href. + if (reuse_input) { + args.GetReturnValue().Set(args[0]); + return; + } + Local ret; if (ToV8Value(realm->context(), out->get_href(), isolate).ToLocal(&ret)) [[likely]] { @@ -439,12 +493,16 @@ void BindingData::Update(const FunctionCallbackInfo& args) { return; } enum url_update_action action = static_cast(val); - Utf8Value input(isolate, args[0].As()); Utf8Value new_value(isolate, args[2].As()); std::string_view new_value_view = new_value.ToStringView(); - auto out = ada::parse(input.ToStringView()); - CHECK(out); + // A serialized URL is not always reparsable: the IDNA encoder can emit a + // host label that the decoder rejects. Fail the update instead of crashing. + // Existing hrefs are typically already-serialized ASCII, so parse in place. + auto out = ParseUrlFromV8String(isolate, args[0].As(), nullptr); + if (!out) { + return args.GetReturnValue().Set(false); + } bool result{true}; @@ -661,6 +719,12 @@ std::optional FileURLToPath(Environment* env, return "\\\\" + ada::idna::to_unicode(hostname) + decoded_pathname; } + if (decoded_pathname.size() < 3) { + THROW_ERR_INVALID_FILE_URL_PATH(env->isolate(), + "File URL path must be absolute"); + return std::nullopt; + } + char letter = decoded_pathname[1] | 0x20; char sep = decoded_pathname[2]; diff --git a/src/node_version.h b/src/node_version.h index b6b12a0ddb4c..5683c5876b60 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -23,13 +23,13 @@ #define SRC_NODE_VERSION_H_ #define NODE_MAJOR_VERSION 24 -#define NODE_MINOR_VERSION 20 -#define NODE_PATCH_VERSION 1 +#define NODE_MINOR_VERSION 21 +#define NODE_PATCH_VERSION 0 #define NODE_VERSION_IS_LTS 1 #define NODE_VERSION_LTS_CODENAME "Krypton" -#define NODE_VERSION_IS_RELEASE 0 +#define NODE_VERSION_IS_RELEASE 1 #ifndef NODE_STRINGIFY #define NODE_STRINGIFY(n) NODE_STRINGIFY_HELPER(n) diff --git a/src/node_zlib.cc b/src/node_zlib.cc index 638982c7ede3..af82aa2ae73b 100644 --- a/src/node_zlib.cc +++ b/src/node_zlib.cc @@ -47,10 +47,11 @@ #include +#include #include #include #include -#include +#include namespace node { @@ -349,6 +350,7 @@ class ZstdCompressContext final : public ZstdContext { DeleteFnPtr cctx_; uint64_t pledged_src_size_ = ZSTD_CONTENTSIZE_UNKNOWN; + std::optional consumed_src_size_; }; class ZstdDecompressContext final : public ZstdContext { @@ -1661,6 +1663,11 @@ void ZstdCompressContext::Close() { CompressionError ZstdCompressContext::Init(uint64_t pledged_src_size, std::string_view dictionary) { pledged_src_size_ = pledged_src_size; + if (pledged_src_size == ZSTD_CONTENTSIZE_UNKNOWN) { + consumed_src_size_.reset(); + } else { + consumed_src_size_ = 0; + } #ifdef NODE_BUNDLED_ZSTD ZSTD_customMem custom_mem = { CompressionStreamMemoryOwner::AllocForBrotli, @@ -1700,12 +1707,26 @@ CompressionError ZstdCompressContext::ResetStream() { } void ZstdCompressContext::DoThreadPoolWork() { + // Zstd overrides a configured pledge when the first call uses ZSTD_e_end. + size_t const input_pos = input_.pos; size_t const remaining = ZSTD_compressStream2(cctx_.get(), &output_, &input_, flush_); + if (consumed_src_size_.has_value()) { + *consumed_src_size_ += input_.pos - input_pos; + } if (ZSTD_isError(remaining)) { error_ = ZSTD_getErrorCode(remaining); error_code_string_ = ZstdStrerror(error_); error_string_ = ZSTD_getErrorString(error_); + } else if (remaining == 0 && flush_ == ZSTD_e_end && + consumed_src_size_.has_value()) { + uint64_t const consumed_src_size = *consumed_src_size_; + consumed_src_size_.reset(); + if (consumed_src_size != pledged_src_size_) { + error_ = ZSTD_error_srcSize_wrong; + error_code_string_ = ZstdStrerror(error_); + error_string_ = ZSTD_getErrorString(error_); + } } } diff --git a/src/permission/openssl_store_permission.cc b/src/permission/openssl_store_permission.cc new file mode 100644 index 000000000000..fcae2772b3f5 --- /dev/null +++ b/src/permission/openssl_store_permission.cc @@ -0,0 +1,31 @@ +#include "permission/openssl_store_permission.h" + +#include +#include + +namespace node { + +namespace permission { + +// OpenSSLStorePermission manages a single global deny state for the use of +// OpenSSL STORE loaders. +void OpenSSLStorePermission::Apply(Environment* env, + const std::vector& allow, + PermissionScope scope) { + deny_all_ = true; +} + +void OpenSSLStorePermission::Drop(Environment* env, + PermissionScope scope, + const std::string_view& param) { + deny_all_ = true; +} + +bool OpenSSLStorePermission::is_granted(Environment* env, + PermissionScope perm, + const std::string_view& param) const { + return perm != PermissionScope::kOpenSSLStore || !deny_all_; +} + +} // namespace permission +} // namespace node diff --git a/src/permission/openssl_store_permission.h b/src/permission/openssl_store_permission.h new file mode 100644 index 000000000000..d64475228e18 --- /dev/null +++ b/src/permission/openssl_store_permission.h @@ -0,0 +1,34 @@ +#ifndef SRC_PERMISSION_OPENSSL_STORE_PERMISSION_H_ +#define SRC_PERMISSION_OPENSSL_STORE_PERMISSION_H_ + +#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#include +#include "permission/permission_base.h" + +namespace node { + +namespace permission { + +class OpenSSLStorePermission final : public PermissionBase { + public: + void Apply(Environment* env, + const std::vector& allow, + PermissionScope scope) override; + void Drop(Environment* env, + PermissionScope scope, + const std::string_view& param = "") override; + bool is_granted(Environment* env, + PermissionScope perm, + const std::string_view& param = "") const override; + + private: + bool deny_all_ = false; +}; + +} // namespace permission + +} // namespace node + +#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS +#endif // SRC_PERMISSION_OPENSSL_STORE_PERMISSION_H_ diff --git a/src/permission/permission.cc b/src/permission/permission.cc index 5ee4c7ba6950..89530df10ae9 100644 --- a/src/permission/permission.cc +++ b/src/permission/permission.cc @@ -8,6 +8,8 @@ #include "node_external_reference.h" #include "node_file.h" +#include "permission/permission_base.h" +#include "v8-template.h" #include "v8.h" #include @@ -17,11 +19,13 @@ namespace node { using v8::Context; +using v8::DictionaryTemplate; using v8::FunctionCallbackInfo; using v8::IntegrityLevel; using v8::Local; using v8::MaybeLocal; using v8::Object; +using v8::Undefined; using v8::Value; namespace permission { @@ -44,11 +48,27 @@ constexpr std::string_view GetDiagnosticsChannelName(PermissionScope scope) { return "node:permission-model:wasi"; case PermissionScope::kAddon: return "node:permission-model:addon"; + case PermissionScope::kOpenSSLStore: + return "node:permission-model:openssl-store"; default: return {}; } } +Local GetPermissionDiagnosicsTemplate(Environment* env) { + auto tmpl = env->permission_diagnostic_channel_message(); + if (tmpl.IsEmpty()) { + static constexpr std::string_view names[] = { + "permission", + "resource", + "drop", + }; + tmpl = DictionaryTemplate::New(env->isolate(), names); + env->set_permission_diagnostic_channel_message(tmpl); + } + return tmpl; +} + // permission.drop('fs.read', '/tmp/') // permission.drop('child') static void Drop(const FunctionCallbackInfo& args) { @@ -100,10 +120,11 @@ static void Has(const FunctionCallbackInfo& args) { } // namespace #define V(Name, label, _, __) \ - if (perm == PermissionScope::k##Name) return #Name; -const char* Permission::PermissionToString(const PermissionScope perm) { + if (perm == PermissionScope::k##Name) return env->Name##_permission_string(); +v8::Local Permission::PermissionToString( + Environment* env, const PermissionScope perm) { PERMISSIONS(V) - return nullptr; + UNREACHABLE(); } #undef V @@ -125,6 +146,8 @@ Permission::Permission() : enabled_(false), warning_only_(false) { std::make_shared(); std::shared_ptr wasi = std::make_shared(); std::shared_ptr addon = std::make_shared(); + std::shared_ptr openssl_store = + std::make_shared(); #define V(Name, _, __, ___) \ nodes_.insert(std::make_pair(PermissionScope::k##Name, fs)); FILESYSTEM_PERMISSIONS(V) @@ -149,6 +172,10 @@ Permission::Permission() : enabled_(false), warning_only_(false) { nodes_.insert(std::make_pair(PermissionScope::k##Name, addon)); ADDON_PERMISSIONS(V) #undef V +#define V(Name, _, __, ___) \ + nodes_.insert(std::make_pair(PermissionScope::k##Name, openssl_store)); + OPENSSL_STORE_PERMISSIONS(V) +#undef V } const char* GetErrorFlagSuggestion(node::permission::PermissionScope perm) { @@ -170,12 +197,9 @@ MaybeLocal CreateAccessDeniedError(Environment* env, Local err = ERR_ACCESS_DENIED( env->isolate(), "Access to this API has been restricted. %s", suggestion); - Local perm_string; Local resource_string; - std::string_view perm_str = Permission::PermissionToString(perm); - if (!ToV8Value(env->context(), perm_str, env->isolate()) - .ToLocal(&perm_string) || - !ToV8Value(env->context(), res, env->isolate()) + Local perm_string = Permission::PermissionToString(env, perm); + if (!ToV8Value(env->context(), res, env->isolate()) .ToLocal(&resource_string) || err->Set(env->context(), env->permission_string(), perm_string) .IsNothing() || @@ -224,6 +248,8 @@ void Permission::EnableWarningOnly() { bool Permission::is_scope_granted(Environment* env, const PermissionScope permission, const std::string_view& res) const { + CHECK(permission != PermissionScope::kPermissionsRoot && + permission != PermissionScope::kPermissionsCount); auto perm_node = nodes_.find(permission); bool result = false; if (perm_node != nodes_.end()) { @@ -231,32 +257,21 @@ bool Permission::is_scope_granted(Environment* env, } if (!result && !publishing_) { - auto channel_name = GetDiagnosticsChannelName(permission); - if (!channel_name.empty()) { - auto ch = GetOrCreateChannel(env, permission); - if (ch && ch->HasSubscribers()) { - publishing_ = true; - v8::Isolate* isolate = env->isolate(); - v8::HandleScope handle_scope(isolate); - v8::Local context = env->context(); - v8::Local msg = - v8::Object::New(isolate, v8::Null(isolate), nullptr, nullptr, 0); - const char* perm_str = PermissionToString(permission); - msg->Set(context, - FIXED_ONE_BYTE_STRING(isolate, "permission"), - v8::String::NewFromUtf8(isolate, perm_str).ToLocalChecked()) - .Check(); - msg->Set(context, - FIXED_ONE_BYTE_STRING(isolate, "resource"), - v8::String::NewFromUtf8(isolate, - res.data(), - v8::NewStringType::kNormal, - static_cast(res.size())) - .ToLocalChecked()) - .Check(); - ch->Publish(env, msg); - publishing_ = false; - } + auto ch = GetOrCreateChannel(env, permission); + if (ch && ch->HasSubscribers()) { + publishing_ = true; + v8::Isolate* isolate = env->isolate(); + v8::HandleScope handle_scope(isolate); + v8::Local context = env->context(); + v8::MaybeLocal values[] = { + PermissionToString(env, permission), + ToV8Value(context, res), + Undefined(isolate), + }; + ch->Publish( + env, + GetPermissionDiagnosicsTemplate(env)->NewInstance(context, values)); + publishing_ = false; } } @@ -265,6 +280,8 @@ bool Permission::is_scope_granted(Environment* env, BaseObjectPtr Permission::GetOrCreateChannel( Environment* env, PermissionScope scope) const { + CHECK(scope != PermissionScope::kPermissionsRoot && + scope != PermissionScope::kPermissionsCount); auto it = channels_.find(scope); if (it != channels_.end()) { // Promote weak ref to strong for the duration of this call. @@ -273,12 +290,10 @@ BaseObjectPtr Permission::GetOrCreateChannel( channels_.erase(it); } auto channel_name = GetDiagnosticsChannelName(scope); - diagnostics_channel::Channel* ch = - diagnostics_channel::Channel::Get(env, channel_name.data()); - if (ch != nullptr) { + if (auto ch = diagnostics_channel::Channel::Get(env, channel_name)) { channels_.emplace(scope, BaseObjectWeakPtr(ch)); - return BaseObjectPtr(ch); + return ch; } return {}; } @@ -295,40 +310,30 @@ void Permission::Apply(Environment* env, void Permission::Drop(Environment* env, PermissionScope scope, const std::string_view& param) { + CHECK(scope != PermissionScope::kPermissionsRoot && + scope != PermissionScope::kPermissionsCount); auto permission = nodes_.find(scope); if (permission != nodes_.end()) { permission->second->Drop(env, scope, param); } // Publish to diagnostics channel so observers can track drops - auto channel_name = GetDiagnosticsChannelName(scope); - if (!channel_name.empty() && !publishing_) { + if (!publishing_) { auto ch = GetOrCreateChannel(env, scope); if (ch && ch->HasSubscribers()) { publishing_ = true; v8::Isolate* isolate = env->isolate(); v8::HandleScope handle_scope(isolate); v8::Local context = env->context(); - v8::Local msg = - v8::Object::New(isolate, v8::Null(isolate), nullptr, nullptr, 0); - const char* perm_str = PermissionToString(scope); - msg->Set(context, - FIXED_ONE_BYTE_STRING(isolate, "permission"), - v8::String::NewFromUtf8(isolate, perm_str).ToLocalChecked()) - .Check(); - msg->Set(context, - FIXED_ONE_BYTE_STRING(isolate, "resource"), - v8::String::NewFromUtf8(isolate, - param.data(), - v8::NewStringType::kNormal, - static_cast(param.size())) - .ToLocalChecked()) - .Check(); - msg->Set(context, - FIXED_ONE_BYTE_STRING(isolate, "drop"), - v8::Boolean::New(isolate, true)) - .Check(); - ch->Publish(env, msg); + + v8::MaybeLocal values[] = { + PermissionToString(env, scope), + ToV8Value(context, param), + v8::True(isolate), + }; + ch->Publish( + env, + GetPermissionDiagnosicsTemplate(env)->NewInstance(context, values)); publishing_ = false; } } diff --git a/src/permission/permission.h b/src/permission/permission.h index 6974330c25bb..51abc9cb781d 100644 --- a/src/permission/permission.h +++ b/src/permission/permission.h @@ -10,6 +10,7 @@ #include "permission/child_process_permission.h" #include "permission/fs_permission.h" #include "permission/inspector_permission.h" +#include "permission/openssl_store_permission.h" #include "permission/permission_base.h" #include "permission/wasi_permission.h" #include "permission/worker_permission.h" @@ -110,7 +111,8 @@ class Permission { FORCE_INLINE bool warning_only() const { return warning_only_; } static PermissionScope StringToPermission(const std::string& perm); - static const char* PermissionToString(PermissionScope perm); + static v8::Local PermissionToString(Environment* env, + PermissionScope perm); static void ThrowAccessDenied(Environment* env, PermissionScope perm, const std::string_view& res); diff --git a/src/permission/permission_base.h b/src/permission/permission_base.h index 99a41511a53d..9de7aac4e677 100644 --- a/src/permission/permission_base.h +++ b/src/permission/permission_base.h @@ -33,13 +33,17 @@ namespace permission { #define ADDON_PERMISSIONS(V) \ V(Addon, "addon", PermissionsRoot, "--allow-addons") +#define OPENSSL_STORE_PERMISSIONS(V) \ + V(OpenSSLStore, "openssl.store", PermissionsRoot, "--allow-openssl-store") + #define PERMISSIONS(V) \ FILESYSTEM_PERMISSIONS(V) \ CHILD_PROCESS_PERMISSIONS(V) \ WASI_PERMISSIONS(V) \ WORKER_THREADS_PERMISSIONS(V) \ INSPECTOR_PERMISSIONS(V) \ - ADDON_PERMISSIONS(V) + ADDON_PERMISSIONS(V) \ + OPENSSL_STORE_PERMISSIONS(V) #define V(name, _, __, ___) k##name, enum class PermissionScope { diff --git a/src/process_wrap.cc b/src/process_wrap.cc index 21ccb2a9989b..4d9420757122 100644 --- a/src/process_wrap.cc +++ b/src/process_wrap.cc @@ -351,7 +351,7 @@ class ProcessWrap : public HandleWrap { } #ifdef _WIN32 if (signal != SIGKILL && signal != SIGTERM && signal != SIGINT && - signal != SIGQUIT && signal != 0) { + signal != SIGQUIT && signal != 0 && signal != SIGWINCH) { signal = SIGKILL; } #endif diff --git a/src/quic/application.cc b/src/quic/application.cc index 688a1309dea5..d3c5e2611f5f 100644 --- a/src/quic/application.cc +++ b/src/quic/application.cc @@ -280,6 +280,11 @@ class DefaultApplication final : public Session::Application { return NGTCP2_INTERNAL_ERROR; } + // Raw QUIC has no "request rejected" semantic; reuse the no-error code. + error_code GetRequestRejectedCode() const override { + return GetNoErrorCode(); + } + void EarlyDataRejected() override { // Destroy all open streams — ngtcp2 has already discarded their // internal state when it rejected the early data. Use the @@ -410,6 +415,12 @@ class DefaultApplication final : public Session::Application { void ResumeStream(stream_id id) override { ScheduleStream(id); } + void StreamWriteShut(stream_id id) override { + if (auto stream = session().FindStream(id)) [[likely]] { + stream->Unschedule(); + } + } + void BlockStream(stream_id id) override { if (auto stream = session().FindStream(id)) [[likely]] { // Remove the stream from the send queue. It will be re-scheduled @@ -425,6 +436,7 @@ class DefaultApplication final : public Session::Application { // The peer granted more flow control for this stream. Re-schedule // it so SendPendingData will resume writing. DCHECK_NOT_NULL(stream); + stream->UpdateWriteDesiredSize(); // the stream might be blocked on js side stream->Schedule(&stream_queue_); } diff --git a/src/quic/application.h b/src/quic/application.h index 619b41dd8d0b..ace6035a0ab7 100644 --- a/src/quic/application.h +++ b/src/quic/application.h @@ -77,6 +77,14 @@ class Session::Application : public MemoryRetainer { // NGTCP2_INTERNAL_ERROR (0x1). virtual error_code GetInternalErrorCode() const = 0; + // The "request rejected" code is sent on RESET_STREAM when an incoming + // request stream is rejected without any application processing (e.g. + // the session has no consumer for it), so the peer learns the request + // was not processed. For HTTP/3 this is NGHTTP3_H3_REQUEST_REJECTED + // (0x10b); other applications have no such semantic and reuse the + // "no error" code. + virtual error_code GetRequestRejectedCode() const = 0; + // Called after Session::Receive processes a packet, outside all callback // scopes. Applications can use this to handle deferred operations that // require calling into JS (e.g., HTTP/3 GOAWAY processing). @@ -210,6 +218,11 @@ class Session::Application : public MemoryRetainer { // do not support headers should return false (the default). virtual bool SupportsHeaders() const { return false; } + // True if this application dispatches the session-level stream + // callbacks (onheaders et al) for incoming streams when they are + // registered on the session. + virtual bool SupportsStreamCallbacks() const { return false; } + // Initiates application-level graceful shutdown signaling (e.g., // HTTP/3 GOAWAY). Called when Session::Close(GRACEFUL) is invoked. virtual void BeginShutdown() {} diff --git a/src/quic/defs.h b/src/quic/defs.h index 75ae915335be..5184288475b1 100644 --- a/src/quic/defs.h +++ b/src/quic/defs.h @@ -328,6 +328,12 @@ enum class HeadersSupportState : uint8_t { UNSUPPORTED, }; +enum class StreamCallbacksSupportState : uint8_t { + UNKNOWN, + SUPPORTED, + UNSUPPORTED, +}; + enum class PathValidationResult : uint8_t { SUCCESS = NGTCP2_PATH_VALIDATION_RESULT_SUCCESS, FAILURE = NGTCP2_PATH_VALIDATION_RESULT_FAILURE, diff --git a/src/quic/http3.cc b/src/quic/http3.cc index b6d876af60f6..ff54bba0354f 100644 --- a/src/quic/http3.cc +++ b/src/quic/http3.cc @@ -172,6 +172,10 @@ class Http3ApplicationImpl final : public Session::Application { return NGHTTP3_H3_INTERNAL_ERROR; } + error_code GetRequestRejectedCode() const override { + return NGHTTP3_H3_REQUEST_REJECTED; + } + void EarlyDataRejected() override { // When 0-RTT is rejected, destroy the nghttp3 connection and all // open streams — ngtcp2 has discarded their internal state. @@ -202,6 +206,8 @@ class Http3ApplicationImpl final : public Session::Application { bool SupportsHeaders() const override { return true; } + bool SupportsStreamCallbacks() const override { return true; } + bool is_started() const override { return started_; } bool Start() override { @@ -375,6 +381,7 @@ class Http3ApplicationImpl final : public Session::Application { Debug(&session(), "HTTP/3 application extending max stream data to %" PRIu64, max_data); + stream->UpdateWriteDesiredSize(); // the stream might be blocked on js side nghttp3_conn_unblock_stream(*this, stream->id()); } @@ -503,7 +510,12 @@ class Http3ApplicationImpl final : public Session::Application { code = error.code(); } - int rv = nghttp3_conn_close_stream(*this, stream->id(), code); + int rv = nghttp3_conn_close_stream2( + *this, + NGHTTP3_STREAM_CLOSE_FLAG_RX_APP_ERROR_CODE_SET, + stream->id(), + code, + 0); // If the call is successful, Http3Application::OnStreamClose callback will // be invoked when the stream is ready to be closed. We'll handle destroying // the actual Stream object there. @@ -797,16 +809,32 @@ class Http3ApplicationImpl final : public Session::Application { return Http3ConnectionPointer(conn); } - void OnStreamClose(Stream* stream, error_code app_error_code) { - if (app_error_code != NGHTTP3_H3_NO_ERROR) { + void OnStreamClose(Stream* stream, + uint32_t flags, + error_code rx_app_error_code, + error_code tx_app_error_code) { + if (flags & NGHTTP3_STREAM_CLOSE_FLAG_RX_APP_ERROR_CODE_SET) { Debug(&session(), "HTTP/3 application received stream close for stream %" PRIi64 - " with code %" PRIu64, + " with remote error code %" PRIu64, stream->id(), - app_error_code); + rx_app_error_code); + } + if (flags & NGHTTP3_STREAM_CLOSE_FLAG_TX_APP_ERROR_CODE_SET) { + Debug(&session(), + "HTTP/3 application send stream close for stream %" PRIi64 + " with error code %" PRIu64, + stream->id(), + tx_app_error_code); } auto direction = stream->direction(); - stream->Destroy(QuicError::ForApplication(app_error_code)); + if (flags & NGHTTP3_STREAM_CLOSE_FLAG_RX_APP_ERROR_CODE_SET) { + stream->Destroy(QuicError::ForApplication(rx_app_error_code)); + } else if (flags & NGHTTP3_STREAM_CLOSE_FLAG_TX_APP_ERROR_CODE_SET) { + stream->Destroy(QuicError::ForApplication(tx_app_error_code)); + } else { + stream->Destroy(); + } ExtendMaxStreams(EndpointLabel::REMOTE, direction, 1); } @@ -1168,13 +1196,16 @@ class Http3ApplicationImpl final : public Session::Application { } static int on_stream_close(nghttp3_conn* conn, + uint32_t flags, stream_id id, - error_code app_error_code, + error_code rx_app_error_code, + error_code tx_app_error_code, void* conn_user_data, void* stream_user_data) { NGHTTP3_CALLBACK_SCOPE(app); if (auto stream = app.session().FindStream(id)) { - app.OnStreamClose(stream.get(), app_error_code); + app.OnStreamClose( + stream.get(), flags, rx_app_error_code, tx_app_error_code); } return NGTCP2_SUCCESS; } @@ -1382,7 +1413,7 @@ class Http3ApplicationImpl final : public Session::Application { static constexpr nghttp3_callbacks kCallbacks = { on_acked_stream_data, - on_stream_close, + nullptr, // nghttp3_stream_close (deprecated) on_receive_data, on_deferred_consume, on_begin_headers, @@ -1400,10 +1431,7 @@ class Http3ApplicationImpl final : public Session::Application { on_end_origin, on_rand, on_receive_settings, -#ifdef NGHTTP3_CALLBACKS_V4 - nullptr, -#endif // NGHTTP3_CALLBACKS_V4 - }; + on_stream_close}; }; std::optional ParseHttp3TicketData(const uv_buf_t& data) { diff --git a/src/quic/session.cc b/src/quic/session.cc index 1bea15fbadb4..2266f74a1277 100644 --- a/src/quic/session.cc +++ b/src/quic/session.cc @@ -136,10 +136,12 @@ uint64_t MaxDatagramPayload(uint64_t max_frame_size) { V(STREAM_OPEN_ALLOWED, stream_open_allowed, uint8_t) \ V(PRIORITY_SUPPORTED, priority_supported, uint8_t) \ V(HEADERS_SUPPORTED, headers_supported, uint8_t) \ + V(STREAM_CALLBACKS_SUPPORTED, stream_callbacks_supported, uint8_t) \ V(WRAPPED, wrapped, uint8_t) \ V(APPLICATION_TYPE, application_type, uint8_t) \ V(NO_ERROR_CODE, no_error_code, error_code) \ V(INTERNAL_ERROR_CODE, internal_error_code, error_code) \ + V(REQUEST_REJECTED_CODE, request_rejected_code, error_code) \ V(MAX_DATAGRAM_SIZE, max_datagram_size, uint16_t) \ V(LAST_DATAGRAM_ID, last_datagram_id, datagram_id) \ V(MAX_PENDING_DATAGRAMS, max_pending_datagrams, uint16_t) @@ -2649,12 +2651,17 @@ void Session::SetApplication(std::unique_ptr app) { impl_->state()->headers_supported = static_cast( app->SupportsHeaders() ? HeadersSupportState::SUPPORTED : HeadersSupportState::UNSUPPORTED); + impl_->state()->stream_callbacks_supported = + static_cast(app->SupportsStreamCallbacks() + ? StreamCallbacksSupportState::SUPPORTED + : StreamCallbacksSupportState::UNSUPPORTED); // Surface the application's "no error" and "internal error" codes via // session state so that JS-side code (e.g. the stream writer's fail() // path) can resolve the right wire code for the negotiated ALPN // without duplicating the per-application table. impl_->state()->no_error_code = app->GetNoErrorCode(); impl_->state()->internal_error_code = app->GetInternalErrorCode(); + impl_->state()->request_rejected_code = app->GetRequestRejectedCode(); impl_->application_ = std::move(app); } diff --git a/src/stream_base.cc b/src/stream_base.cc index 360986c8935d..f57f75e5f275 100644 --- a/src/stream_base.cc +++ b/src/stream_base.cc @@ -696,6 +696,7 @@ void EmitToJSStreamListener::OnStreamRead(ssize_t nread, const uv_buf_t& buf_) { std::unique_ptr bs = env->release_managed_buffer(buf_); if (nread <= 0) { + env->recycle_managed_buffer(std::move(bs)); if (nread < 0) stream->CallJSOnreadMethod(nread, Local()); return; @@ -707,6 +708,7 @@ void EmitToJSStreamListener::OnStreamRead(ssize_t nread, const uv_buf_t& buf_) { bs = ArrayBuffer::NewBackingStore( isolate, nread, BackingStoreInitializationMode::kUninitialized); memcpy(bs->Data(), old_bs->Data(), nread); + env->recycle_managed_buffer(std::move(old_bs)); } stream->CallJSOnreadMethod(nread, ArrayBuffer::New(isolate, std::move(bs))); diff --git a/src/tty_wrap.cc b/src/tty_wrap.cc index 3086e859a54e..c605ab2fcc11 100644 --- a/src/tty_wrap.cc +++ b/src/tty_wrap.cc @@ -68,6 +68,9 @@ void TTYWrap::Initialize(Local target, SetProtoMethod(isolate, t, "setRawMode", SetRawMode); SetMethodNoSideEffect(context, target, "isTTY", IsTTY); + NODE_DEFINE_CONSTANT(target, UV_TTY_MODE_NORMAL); + NODE_DEFINE_CONSTANT(target, UV_TTY_MODE_IO); + NODE_DEFINE_CONSTANT(target, UV_TTY_MODE_RAW_VT); Local func; if (t->GetFunction(context).ToLocal(&func) && @@ -124,9 +127,10 @@ void TTYWrap::SetRawMode(const FunctionCallbackInfo& args) { // sequences at all on Windows, such as bracketed paste mode. // The Node.js readline implementation handles differences between // these modes. - int err = uv_tty_set_mode( - &wrap->handle_, - args[0]->IsTrue() ? UV_TTY_MODE_RAW_VT : UV_TTY_MODE_NORMAL); + Environment* env = Environment::GetCurrent(args); + int mode; + if (!args[0]->Int32Value(env->context()).To(&mode)) return; + int err = uv_tty_set_mode(&wrap->handle_, static_cast(mode)); args.GetReturnValue().Set(err); } diff --git a/src/undici_version.h b/src/undici_version.h index b6ecfd9aa4ca..9fb125bbf22e 100644 --- a/src/undici_version.h +++ b/src/undici_version.h @@ -2,5 +2,5 @@ // Refer to tools/dep_updaters/update-undici.sh #ifndef SRC_UNDICI_VERSION_H_ #define SRC_UNDICI_VERSION_H_ -#define UNDICI_VERSION "7.29.0" +#define UNDICI_VERSION "7.29.1" #endif // SRC_UNDICI_VERSION_H_ diff --git a/src/util.h b/src/util.h index c9d787f68dfd..b61d98fd7669 100644 --- a/src/util.h +++ b/src/util.h @@ -126,6 +126,9 @@ void NODE_EXTERN_PRIVATE Assert(const AssertionInfo& info); void DumpNativeBacktrace(FILE* fp); void DumpJavaScriptBacktrace(FILE* fp); +// Returns the currently installed abort handler which is never null. +AbortHandler GetAbortHandler(); + // Windows 8+ does not like abort() in Release mode #ifdef _WIN32 #define ABORT_NO_BACKTRACE() _exit(static_cast(node::ExitCode::kAbort)) @@ -138,13 +141,12 @@ void DumpJavaScriptBacktrace(FILE* fp); // when generating code for them the compiler can choose not to // maintain the frame pointers or link registers that are necessary for // correct backtracing. -// `ABORT` must be a macro and not a [[noreturn]] function to make sure the -// backtrace is correct. -#define ABORT() \ +// `ABORT` and `ABORT_WITH_DETAILS` must be a macro and not a [[noreturn]] +// function to make sure the backtrace is correct. +#define ABORT() ABORT_WITH_DETAILS(__FILE__ ":" STRINGIFY(__LINE__), nullptr) +#define ABORT_WITH_DETAILS(location, message) \ do { \ - node::DumpNativeBacktrace(stderr); \ - node::DumpJavaScriptBacktrace(stderr); \ - fflush(stderr); \ + node::GetAbortHandler()(location, message); \ ABORT_NO_BACKTRACE(); \ } while (0) diff --git a/src/zlib_version.h b/src/zlib_version.h index 302282a2027e..861b339e2bfc 100644 --- a/src/zlib_version.h +++ b/src/zlib_version.h @@ -2,5 +2,5 @@ // Refer to tools/dep_updaters/update-zlib.sh #ifndef SRC_ZLIB_VERSION_H_ #define SRC_ZLIB_VERSION_H_ -#define ZLIB_VERSION "1.3.2.1-motley-42c2f19" +#define ZLIB_VERSION "1.3.2.1-motley-8002e91" #endif // SRC_ZLIB_VERSION_H_ diff --git a/test/addons/abort-handler/binding.cc b/test/addons/abort-handler/binding.cc new file mode 100644 index 000000000000..13ceb011e57b --- /dev/null +++ b/test/addons/abort-handler/binding.cc @@ -0,0 +1,18 @@ +#include +#include +#include + +namespace { +void TestAbortHandler(const char* /*location*/, const char* /*message*/) { + fputs("CUSTOM_ABORT_HANDLER_RAN\n", stderr); + fflush(stderr); +} + +void InstallAbortHandler(const v8::FunctionCallbackInfo&) { + node::SetAbortHandler(TestAbortHandler); +} +} // namespace + +NODE_MODULE_INIT() { + NODE_SET_METHOD(exports, "installAbortHandler", InstallAbortHandler); +} diff --git a/test/addons/abort-handler/binding.gyp b/test/addons/abort-handler/binding.gyp new file mode 100644 index 000000000000..55fbe7050f18 --- /dev/null +++ b/test/addons/abort-handler/binding.gyp @@ -0,0 +1,9 @@ +{ + 'targets': [ + { + 'target_name': 'binding', + 'sources': [ 'binding.cc' ], + 'includes': ['../common.gypi'], + } + ] +} diff --git a/test/addons/abort-handler/test.js b/test/addons/abort-handler/test.js new file mode 100644 index 000000000000..4c05046c92b1 --- /dev/null +++ b/test/addons/abort-handler/test.js @@ -0,0 +1,45 @@ +'use strict'; +const common = require('../../common'); +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); +const { exec } = require('child_process'); + +const bindingPath = path.resolve( + __dirname, 'build', common.buildType, 'binding.node'); + +if (!fs.existsSync(bindingPath)) + common.skip('binding not built yet'); + +if (process.argv[2] === 'child') { + const binding = require(bindingPath); + binding.installAbortHandler(); + process.abort(); + return; +} + +const escapedArgs = + common.escapePOSIXShell`"${process.execPath}" "${__filename}" child`; +if (!common.isWindows) { + // Do not create core files, as it can take a lot of disk space on + // continuous testing and developers' machines. + escapedArgs[0] = 'ulimit -c 0 && ' + escapedArgs[0]; +} + +exec(...escapedArgs, common.mustCall((err, stdout, stderr) => { + assert.ok( + stderr.includes('CUSTOM_ABORT_HANDLER_RAN'), + `Expected custom abort handler marker in stderr, got:\n${stderr}`); + assert.ok( + !stderr.includes('Native stack trace'), + `Expected the custom handler to replace the default dump, got:\n${stderr}`); + + // The child aborts. Whether that surfaces as the SIGABRT signal or as exit + // code 134 depends on shell wrapping: the `ulimit -c 0 && ...` prefix makes + // /bin/sh wait on (rather than exec-replace itself with) the node grandchild, + // so sh reports the aborted grandchild as a normal exit with code 134. + // common.nodeProcessAborted() accepts both forms. + assert.ok( + err && common.nodeProcessAborted(err.code, err.signal), + `Expected the child to abort, got code=${err?.code} signal=${err?.signal}`); +})); diff --git a/test/addons/fs-windows-handle/binding.cc b/test/addons/fs-windows-handle/binding.cc new file mode 100644 index 000000000000..72194df15e5f --- /dev/null +++ b/test/addons/fs-windows-handle/binding.cc @@ -0,0 +1,62 @@ +#include +#include + +#ifdef _WIN32 +#include +#endif + +namespace { + +using v8::BigInt; +using v8::Context; +using v8::FunctionCallbackInfo; +using v8::Isolate; +using v8::Local; +using v8::Object; +using v8::String; +using v8::Value; + +// Creates an anonymous pipe and returns its raw Win32 read/write HANDLE values +// as JS bigints. These are NOT CRT file descriptors, so passing them as the +// `windowsHandle` stream option exercises the HANDLE -> fd conversion path on +// Windows. Returns undefined on other platforms. +void CreatePipeHandles(const FunctionCallbackInfo& args) { + Isolate* isolate = args.GetIsolate(); +#ifdef _WIN32 + Local context = isolate->GetCurrentContext(); + + HANDLE read_handle = nullptr; + HANDLE write_handle = nullptr; + if (!CreatePipe(&read_handle, &write_handle, nullptr, 0)) { + isolate->ThrowException(v8::Exception::Error( + String::NewFromUtf8(isolate, "CreatePipe failed").ToLocalChecked())); + return; + } + + Local result = Object::New(isolate); + result + ->Set(context, + String::NewFromUtf8(isolate, "readHandle").ToLocalChecked(), + BigInt::New( + isolate, + static_cast(reinterpret_cast(read_handle)))) + .Check(); + result + ->Set(context, + String::NewFromUtf8(isolate, "writeHandle").ToLocalChecked(), + BigInt::New( + isolate, + static_cast(reinterpret_cast(write_handle)))) + .Check(); + args.GetReturnValue().Set(result); +#else + args.GetReturnValue().SetUndefined(); +#endif +} + +} // anonymous namespace + +extern "C" NODE_MODULE_EXPORT void NODE_MODULE_INITIALIZER( + Local exports, Local module, Local context) { + NODE_SET_METHOD(exports, "createPipeHandles", CreatePipeHandles); +} diff --git a/test/addons/fs-windows-handle/binding.gyp b/test/addons/fs-windows-handle/binding.gyp new file mode 100644 index 000000000000..7e0f38c27d57 --- /dev/null +++ b/test/addons/fs-windows-handle/binding.gyp @@ -0,0 +1,9 @@ +{ + 'targets': [ + { + 'target_name': 'binding', + 'sources': [ 'binding.cc' ], + 'includes': ['../common.gypi'], + }, + ] +} diff --git a/test/addons/fs-windows-handle/test.js b/test/addons/fs-windows-handle/test.js new file mode 100644 index 000000000000..122440ee4677 --- /dev/null +++ b/test/addons/fs-windows-handle/test.js @@ -0,0 +1,35 @@ +'use strict'; +// Verifies that fs.createReadStream()/createWriteStream() accept a raw Win32 +// HANDLE through the `windowsHandle` option, as happens when a parent process +// passes an inherited anonymous pipe handle. The addon produces such handles +// via CreatePipe(); Node must wrap them in CRT file descriptors instead of +// failing with EBADF. + +const common = require('../../common'); + +if (!common.isWindows) { + common.skip('windowsHandle is Windows-only'); +} + +const assert = require('assert'); +const fs = require('fs'); + +const binding = require(`./build/${common.buildType}/binding`); + +const { readHandle, writeHandle } = binding.createPipeHandles(); +assert.strictEqual(typeof readHandle, 'bigint'); +assert.strictEqual(typeof writeHandle, 'bigint'); + +const payload = 'payload'; + +const chunks = []; +const rs = fs.createReadStream(null, { windowsHandle: readHandle }); +rs.on('error', (err) => assert.fail(err)); +rs.on('data', (chunk) => chunks.push(chunk)); +rs.on('end', common.mustCall(() => { + assert.strictEqual(Buffer.concat(chunks).toString(), payload); +})); + +const ws = fs.createWriteStream(null, { windowsHandle: writeHandle }); +ws.on('error', (err) => assert.fail(err)); +ws.end(payload); diff --git a/test/benchmark/test-benchmark-fetch.js b/test/benchmark/test-benchmark-fetch.js new file mode 100644 index 000000000000..e9c686003a01 --- /dev/null +++ b/test/benchmark/test-benchmark-fetch.js @@ -0,0 +1,7 @@ +'use strict'; + +require('../common'); + +const runBenchmark = require('../common/benchmark'); + +runBenchmark('fetch', { NODEJS_BENCHMARK_ZERO_ALLOWED: 1 }); diff --git a/test/benchmark/test-benchmark-repl.js b/test/benchmark/test-benchmark-repl.js new file mode 100644 index 000000000000..045813039589 --- /dev/null +++ b/test/benchmark/test-benchmark-repl.js @@ -0,0 +1,8 @@ +'use strict'; + +const common = require('../common'); +const runBenchmark = require('../common/benchmark'); + +common.skipIfInspectorDisabled(); + +runBenchmark('repl', { NODEJS_BENCHMARK_ZERO_ALLOWED: 1 }); diff --git a/test/cctest/test_diagnostics_channel.cc b/test/cctest/test_diagnostics_channel.cc index 30a004b59070..d4d1fd1c9fac 100644 --- a/test/cctest/test_diagnostics_channel.cc +++ b/test/cctest/test_diagnostics_channel.cc @@ -3,6 +3,7 @@ #include "gtest/gtest.h" #include "node_test_fixture.h" +using node::BaseObjectPtr; using node::diagnostics_channel::Channel; class DiagnosticsChannelTest : public EnvironmentTestFixture {}; @@ -279,15 +280,15 @@ TEST_F(DiagnosticsChannelTest, NativeChannelsGrowSubscriberStorage) { "globalThis.__dc.subscribe('test:cctest:grow:0', " " globalThis.__firstSubscriber);"); - Channel* first = Channel::Get(*env, "test:cctest:grow:0"); - ASSERT_NE(first, nullptr); + auto first = Channel::Get(*env, "test:cctest:grow:0"); + ASSERT_TRUE(first); ASSERT_TRUE(first->HasSubscribers()); - Channel* last = nullptr; + BaseObjectPtr last; for (size_t i = 1; i <= 1024; i++) { std::string name = "test:cctest:grow:" + std::to_string(i); last = Channel::Get(*env, name.c_str()); - ASSERT_NE(last, nullptr); + ASSERT_TRUE(last); } RunJS(isolate_, diff --git a/test/cctest/test_environment.cc b/test/cctest/test_environment.cc index 3e8e4a65a81b..a219d5125701 100644 --- a/test/cctest/test_environment.cc +++ b/test/cctest/test_environment.cc @@ -38,6 +38,27 @@ class EnvironmentTest : public EnvironmentTestFixture { } }; +TEST_F(EnvironmentTest, ManagedBufferCache) { + constexpr size_t kCacheSize = 64 * 1024; + constexpr size_t kOtherSize = 1024; + const v8::HandleScope handle_scope(isolate_); + Argv argv; + Env env{handle_scope, argv}; + + (*env)->recycle_managed_buffer(nullptr); + + uv_buf_t buffer = (*env)->allocate_managed_buffer(kCacheSize); + char* cached_data = buffer.base; + (*env)->recycle_managed_buffer((*env)->release_managed_buffer(buffer)); + + buffer = (*env)->allocate_managed_buffer(kOtherSize); + (*env)->recycle_managed_buffer((*env)->release_managed_buffer(buffer)); + + buffer = (*env)->allocate_managed_buffer(kCacheSize); + EXPECT_EQ(buffer.base, cached_data); + (*env)->release_managed_buffer(buffer); +} + TEST_F(EnvironmentTest, EnvironmentWithoutBrowserGlobals) { const v8::HandleScope handle_scope(isolate_); Argv argv; @@ -968,3 +989,57 @@ TEST_F(EnvironmentTest, LoadEnvironmentWithCallbackWithESModule) { printf("Frame: %s\n", *frame_str); EXPECT_EQ(frame_str.ToString(), " at embedded:esm.mjs:3:15"); } + +namespace { +void CustomAbortHandlerForContractTest(const char* location, + const char* message) {} + +bool abort_handler_dispatch_flag = false; +const char* abort_handler_received_location = nullptr; +const char* abort_handler_received_message = nullptr; +void AbortHandlerThatSetsDispatchFlag(const char* location, + const char* message) { + abort_handler_dispatch_flag = true; + abort_handler_received_location = location; + abort_handler_received_message = message; +} +} // namespace + +TEST(AbortHandlerTest, DefaultIsNonNullAndSetAbortHandlerRoundTrips) { + node::AbortHandler old = node::GetAbortHandler(); + + // There should always be a non-null default handler installed. + EXPECT_NE(node::GetAbortHandler(), nullptr); + + node::SetAbortHandler(CustomAbortHandlerForContractTest); + EXPECT_EQ(node::GetAbortHandler(), CustomAbortHandlerForContractTest); + + node::SetAbortHandler(nullptr); + EXPECT_NE(node::GetAbortHandler(), nullptr); + EXPECT_NE(node::GetAbortHandler(), CustomAbortHandlerForContractTest); + + node::SetAbortHandler(old); +} + +TEST(AbortHandlerTest, InstalledHandlerIsInvokedWhenCalled) { + node::AbortHandler old = node::GetAbortHandler(); + abort_handler_dispatch_flag = false; + abort_handler_received_location = nullptr; + abort_handler_received_message = nullptr; + + node::SetAbortHandler(AbortHandlerThatSetsDispatchFlag); + node::AbortHandler h = node::GetAbortHandler(); + // Fail cleanly (instead of crashing on a null call) if the handler wasn't + // actually installed. + ASSERT_NE(h, nullptr); + + // Dispatch through the public GetAbortHandler() accessor directly (not via + // the ABORT() macro, so nothing terminates), and verify the message is + // passed through unchanged. + node::GetAbortHandler()("some-test-location", "some-test-message"); + EXPECT_TRUE(abort_handler_dispatch_flag); + EXPECT_STREQ(abort_handler_received_location, "some-test-location"); + EXPECT_STREQ(abort_handler_received_message, "some-test-message"); + + node::SetAbortHandler(old); +} diff --git a/test/cctest/test_path.cc b/test/cctest/test_path.cc index 9e860d02cf77..1fd991340452 100644 --- a/test/cctest/test_path.cc +++ b/test/cctest/test_path.cc @@ -8,6 +8,7 @@ #include "v8.h" using node::BufferValue; +using node::NormalizeFileURLOrPath; using node::PathResolve; using node::ToNamespacedPath; @@ -93,3 +94,26 @@ TEST_F(PathTest, ToNamespacedPath) { EXPECT_EQ(data.ToStringView(), "hello world"); // Input should not be mutated #endif } + +#ifdef _WIN32 +TEST_F(PathTest, NormalizeShortFileURLPath) { + const v8::HandleScope handle_scope(isolate_); + Argv argv; + Env env{handle_scope, argv, node::EnvironmentFlags::kNoBrowserGlobals}; + v8::TryCatch try_catch(isolate_); + + EXPECT_EQ(NormalizeFileURLOrPath(*env, "file:///"), ""); + ASSERT_TRUE(try_catch.HasCaught()); + + v8::Local exception = try_catch.Exception(); + ASSERT_TRUE(exception->IsObject()); + v8::Local code; + ASSERT_TRUE(exception.As() + ->Get((*env)->context(), + v8::String::NewFromUtf8Literal(isolate_, "code")) + .ToLocal(&code)); + ASSERT_TRUE(code->IsString()); + node::Utf8Value code_value(isolate_, code); + EXPECT_EQ(code_value.ToStringView(), "ERR_INVALID_FILE_URL_PATH"); +} +#endif diff --git a/test/cctest/test_sockaddr.cc b/test/cctest/test_sockaddr.cc index 727a5ec021dd..42ffed08edc4 100644 --- a/test/cctest/test_sockaddr.cc +++ b/test/cctest/test_sockaddr.cc @@ -272,6 +272,127 @@ TEST(SocketAddress, Comparison) { CHECK(addr2 >= addr5); } +TEST(SocketAddress, NewAutoFamily) { + // SocketAddress::New(host, port) without explicit family. + // Tries AF_INET first, then AF_INET6. + SocketAddress addr; + + // IPv4 address should succeed. + CHECK(SocketAddress::New("192.168.1.1", 8080, &addr)); + CHECK_EQ(addr.family(), AF_INET); + CHECK_EQ(addr.address(), "192.168.1.1"); + CHECK_EQ(addr.port(), 8080); + + // IPv6 address should succeed (fails AF_INET, falls through to AF_INET6). + CHECK(SocketAddress::New("::1", 443, &addr)); + CHECK_EQ(addr.family(), AF_INET6); + CHECK_EQ(addr.address(), "::1"); + CHECK_EQ(addr.port(), 443); + + // Invalid address should fail. + CHECK(!SocketAddress::New("not_an_address", 0, &addr)); +} + +TEST(SocketAddress, HashIPv6) { + sockaddr_storage s1, s2, s3; + SocketAddress::ToSockAddr(AF_INET6, "::1", 443, &s1); + SocketAddress::ToSockAddr(AF_INET6, "::1", 443, &s2); + SocketAddress::ToSockAddr(AF_INET6, "::2", 443, &s3); + + SocketAddress a1(reinterpret_cast(&s1)); + SocketAddress a2(reinterpret_cast(&s2)); + SocketAddress a3(reinterpret_cast(&s3)); + + // Same address and port: hash must be equal. + CHECK_EQ(SocketAddress::Hash()(a1), SocketAddress::Hash()(a2)); + + // Different address: hash should (very likely) differ. + CHECK_NE(SocketAddress::Hash()(a1), SocketAddress::Hash()(a3)); +} + +TEST(SocketAddress, IsMatchCrossFamily) { + sockaddr_storage s1, s2, s3, s4; + SocketAddress::ToSockAddr(AF_INET, "10.0.0.1", 0, &s1); + SocketAddress::ToSockAddr(AF_INET6, "::ffff:10.0.0.1", 0, &s2); + SocketAddress::ToSockAddr(AF_INET6, "::1", 0, &s3); + SocketAddress::ToSockAddr(AF_INET, "10.0.0.2", 0, &s4); + + SocketAddress ipv4(reinterpret_cast(&s1)); + SocketAddress mapped(reinterpret_cast(&s2)); + SocketAddress ipv6(reinterpret_cast(&s3)); + SocketAddress other(reinterpret_cast(&s4)); + + // IPv4 matches its IPv4-mapped IPv6 counterpart. + CHECK(ipv4.is_match(mapped)); + CHECK(mapped.is_match(ipv4)); + + // IPv4 does not match a non-mapped IPv6 address. + CHECK(!ipv4.is_match(ipv6)); + CHECK(!ipv6.is_match(ipv4)); + + // Same family, different address. + CHECK(!ipv4.is_match(other)); + + // Self-match. + CHECK(ipv4.is_match(ipv4)); + CHECK(ipv6.is_match(ipv6)); +} + +TEST(SocketAddress, InNetworkIPv4) { + sockaddr_storage s1, s2, s3; + SocketAddress::ToSockAddr(AF_INET, "192.168.1.100", 0, &s1); + SocketAddress::ToSockAddr(AF_INET, "192.168.0.0", 0, &s2); + SocketAddress::ToSockAddr(AF_INET, "10.0.0.1", 0, &s3); + + SocketAddress addr(reinterpret_cast(&s1)); + SocketAddress net(reinterpret_cast(&s2)); + SocketAddress outside(reinterpret_cast(&s3)); + + CHECK(addr.is_in_network(net, 16)); + CHECK(!outside.is_in_network(net, 16)); + CHECK(!addr.is_in_network(net, 24)); // 192.168.1.x != 192.168.0.x +} + +TEST(SocketAddress, InNetworkIPv6) { + sockaddr_storage s1, s2, s3; + SocketAddress::ToSockAddr(AF_INET6, "2001:db8::1", 0, &s1); + SocketAddress::ToSockAddr(AF_INET6, "2001:db8::", 0, &s2); + SocketAddress::ToSockAddr(AF_INET6, "2001:db9::1", 0, &s3); + + SocketAddress addr(reinterpret_cast(&s1)); + SocketAddress net(reinterpret_cast(&s2)); + SocketAddress outside(reinterpret_cast(&s3)); + + CHECK(addr.is_in_network(net, 32)); + CHECK(!outside.is_in_network(net, 32)); + + // /128 prefix == exact match. + CHECK(addr.is_in_network(addr, 128)); + CHECK(!outside.is_in_network(addr, 128)); +} + +TEST(SocketAddress, InNetworkCrossFamily) { + sockaddr_storage s1, s2, s3; + SocketAddress::ToSockAddr(AF_INET, "10.0.0.1", 0, &s1); + SocketAddress::ToSockAddr(AF_INET6, "::ffff:10.0.0.0", 0, &s2); + SocketAddress::ToSockAddr(AF_INET6, "::ffff:10.0.0.1", 0, &s3); + + SocketAddress ipv4(reinterpret_cast(&s1)); + SocketAddress net6(reinterpret_cast(&s2)); + SocketAddress mapped(reinterpret_cast(&s3)); + + // IPv4 address in an IPv4-mapped IPv6 subnet. + CHECK(ipv4.is_in_network(net6, 120)); // prefix 120 = /24 on the IPv4 part + CHECK(mapped.is_in_network(net6, 120)); + + // IPv6 address in IPv4 network. + sockaddr_storage s4; + SocketAddress::ToSockAddr(AF_INET, "10.0.0.0", 0, &s4); + SocketAddress net4(reinterpret_cast(&s4)); + + CHECK(mapped.is_in_network(net4, 24)); +} + TEST(SocketAddressBlockList, Simple) { SocketAddressBlockList bl; @@ -283,14 +404,299 @@ TEST(SocketAddressBlockList, Simple) { std::shared_ptr addr2 = std::make_shared( reinterpret_cast(&storage[1])); - bl.AddSocketAddress(addr1); - bl.AddSocketAddress(addr2); + bl.AddSocketAddress(*addr1); + bl.AddSocketAddress(*addr2); CHECK(bl.Apply(*addr1)); CHECK(bl.Apply(*addr2)); - bl.RemoveSocketAddress(addr1); + bl.RemoveSocketAddress(*addr1); CHECK(!bl.Apply(*addr1)); CHECK(bl.Apply(*addr2)); } + +TEST(SocketAddressBlockList, CrossFamilyAddress) { + SocketAddressBlockList bl; + + sockaddr_storage s1, s2, s3; + SocketAddress::ToSockAddr(AF_INET, "10.0.0.1", 0, &s1); + SocketAddress::ToSockAddr(AF_INET6, "::ffff:10.0.0.1", 0, &s2); + SocketAddress::ToSockAddr(AF_INET6, "::1", 0, &s3); + + SocketAddress ipv4(reinterpret_cast(&s1)); + SocketAddress mapped(reinterpret_cast(&s2)); + SocketAddress other(reinterpret_cast(&s3)); + + // Adding IPv4 should also match the IPv4-mapped IPv6 form. + bl.AddSocketAddress(ipv4); + CHECK(bl.Apply(ipv4)); + CHECK(bl.Apply(mapped)); + CHECK(!bl.Apply(other)); + + // Remove should clean up cross-family counterpart. + bl.RemoveSocketAddress(ipv4); + CHECK(!bl.Apply(ipv4)); + CHECK(!bl.Apply(mapped)); +} + +TEST(SocketAddressBlockList, CrossFamilyAddressIPv6) { + SocketAddressBlockList bl; + + sockaddr_storage s1, s2; + SocketAddress::ToSockAddr(AF_INET6, "::ffff:192.168.1.1", 0, &s1); + SocketAddress::ToSockAddr(AF_INET, "192.168.1.1", 0, &s2); + + SocketAddress mapped(reinterpret_cast(&s1)); + SocketAddress ipv4(reinterpret_cast(&s2)); + + // Adding an IPv4-mapped IPv6 address should also match the IPv4 form. + bl.AddSocketAddress(mapped); + CHECK(bl.Apply(mapped)); + CHECK(bl.Apply(ipv4)); + + // Remove the IPv6 form should clean up the IPv4 counterpart. + bl.RemoveSocketAddress(mapped); + CHECK(!bl.Apply(mapped)); + CHECK(!bl.Apply(ipv4)); +} + +TEST(SocketAddressBlockList, BatchAddresses) { + SocketAddressBlockList bl; + + sockaddr_storage storage[3]; + SocketAddress::ToSockAddr(AF_INET, "1.1.1.1", 0, &storage[0]); + SocketAddress::ToSockAddr(AF_INET, "2.2.2.2", 0, &storage[1]); + SocketAddress::ToSockAddr(AF_INET, "3.3.3.3", 0, &storage[2]); + + SocketAddress addrs[3] = { + SocketAddress(reinterpret_cast(&storage[0])), + SocketAddress(reinterpret_cast(&storage[1])), + SocketAddress(reinterpret_cast(&storage[2])), + }; + + bl.AddSocketAddresses(addrs, 3); + + CHECK(bl.Apply(addrs[0])); + CHECK(bl.Apply(addrs[1])); + CHECK(bl.Apply(addrs[2])); + + sockaddr_storage s4; + SocketAddress::ToSockAddr(AF_INET, "4.4.4.4", 0, &s4); + SocketAddress addr4(reinterpret_cast(&s4)); + CHECK(!bl.Apply(addr4)); +} + +TEST(SocketAddressBlockList, Range) { + SocketAddressBlockList bl; + + sockaddr_storage s1, s2, s3, s4, s5; + SocketAddress::ToSockAddr(AF_INET, "10.0.0.1", 0, &s1); + SocketAddress::ToSockAddr(AF_INET, "10.0.0.10", 0, &s2); + SocketAddress::ToSockAddr(AF_INET, "10.0.0.5", 0, &s3); + SocketAddress::ToSockAddr(AF_INET, "10.0.0.11", 0, &s4); + SocketAddress::ToSockAddr(AF_INET, "10.0.0.0", 0, &s5); + + SocketAddress start(reinterpret_cast(&s1)); + SocketAddress end(reinterpret_cast(&s2)); + SocketAddress mid(reinterpret_cast(&s3)); + SocketAddress above(reinterpret_cast(&s4)); + SocketAddress below(reinterpret_cast(&s5)); + + bl.AddSocketAddressRange(start, end); + + CHECK(bl.Apply(start)); + CHECK(bl.Apply(end)); + CHECK(bl.Apply(mid)); + CHECK(!bl.Apply(above)); + CHECK(!bl.Apply(below)); + + // Remove range. + bl.RemoveSocketAddressRange(start, end); + CHECK(!bl.Apply(mid)); +} + +TEST(SocketAddressBlockList, Subnet) { + SocketAddressBlockList bl; + + sockaddr_storage s1, s2, s3; + SocketAddress::ToSockAddr(AF_INET, "192.168.1.0", 0, &s1); + SocketAddress::ToSockAddr(AF_INET, "192.168.1.100", 0, &s2); + SocketAddress::ToSockAddr(AF_INET, "192.168.2.1", 0, &s3); + + SocketAddress net(reinterpret_cast(&s1)); + SocketAddress inside(reinterpret_cast(&s2)); + SocketAddress outside(reinterpret_cast(&s3)); + + bl.AddSocketAddressMask(net, 24); + + CHECK(bl.Apply(inside)); + CHECK(!bl.Apply(outside)); + + // Remove subnet. + bl.RemoveSocketAddressMask(net, 24); + CHECK(!bl.Apply(inside)); +} + +TEST(SocketAddressBlockList, SubnetIPv6) { + SocketAddressBlockList bl; + + sockaddr_storage s1, s2, s3; + SocketAddress::ToSockAddr(AF_INET6, "2001:db8::", 0, &s1); + SocketAddress::ToSockAddr(AF_INET6, "2001:db8::1", 0, &s2); + SocketAddress::ToSockAddr(AF_INET6, "2001:db9::1", 0, &s3); + + SocketAddress net(reinterpret_cast(&s1)); + SocketAddress inside(reinterpret_cast(&s2)); + SocketAddress outside(reinterpret_cast(&s3)); + + bl.AddSocketAddressMask(net, 32); + + CHECK(bl.Apply(inside)); + CHECK(!bl.Apply(outside)); + + bl.RemoveSocketAddressMask(net, 32); + CHECK(!bl.Apply(inside)); +} + +TEST(SocketAddressBlockList, SubnetCrossFamily) { + SocketAddressBlockList bl; + + // Adding an IPv4 subnet should also match IPv4-mapped IPv6 addresses. + sockaddr_storage s1, s2, s3; + SocketAddress::ToSockAddr(AF_INET, "10.0.0.0", 0, &s1); + SocketAddress::ToSockAddr(AF_INET, "10.0.0.5", 0, &s2); + SocketAddress::ToSockAddr(AF_INET6, "::ffff:10.0.0.5", 0, &s3); + + SocketAddress net(reinterpret_cast(&s1)); + SocketAddress ipv4(reinterpret_cast(&s2)); + SocketAddress mapped(reinterpret_cast(&s3)); + + bl.AddSocketAddressMask(net, 24); + + CHECK(bl.Apply(ipv4)); + CHECK(bl.Apply(mapped)); +} + +TEST(SocketAddressBlockList, ClearAll) { + SocketAddressBlockList bl; + + sockaddr_storage s1, s2, s3; + SocketAddress::ToSockAddr(AF_INET, "1.1.1.1", 0, &s1); + SocketAddress::ToSockAddr(AF_INET, "10.0.0.1", 0, &s2); + SocketAddress::ToSockAddr(AF_INET, "192.168.0.0", 0, &s3); + + SocketAddress addr(reinterpret_cast(&s1)); + SocketAddress rangeStart(reinterpret_cast(&s2)); + SocketAddress subnet(reinterpret_cast(&s3)); + + sockaddr_storage s4; + SocketAddress::ToSockAddr(AF_INET, "10.0.0.10", 0, &s4); + SocketAddress rangeEnd(reinterpret_cast(&s4)); + + bl.AddSocketAddress(addr); + bl.AddSocketAddressRange(rangeStart, rangeEnd); + bl.AddSocketAddressMask(subnet, 16); + + CHECK(bl.Apply(addr)); + CHECK(bl.Apply(rangeStart)); + + sockaddr_storage s5; + SocketAddress::ToSockAddr(AF_INET, "192.168.1.1", 0, &s5); + SocketAddress subnetAddr(reinterpret_cast(&s5)); + CHECK(bl.Apply(subnetAddr)); + + bl.Clear(); + + CHECK(!bl.Apply(addr)); + CHECK(!bl.Apply(rangeStart)); + CHECK(!bl.Apply(subnetAddr)); +} + +TEST(SocketAddressBlockList, ParentBlockList) { + auto parent = std::make_shared(); + SocketAddressBlockList child(parent); + + sockaddr_storage s1, s2; + SocketAddress::ToSockAddr(AF_INET, "1.1.1.1", 0, &s1); + SocketAddress::ToSockAddr(AF_INET, "2.2.2.2", 0, &s2); + + SocketAddress addr1(reinterpret_cast(&s1)); + SocketAddress addr2(reinterpret_cast(&s2)); + + parent->AddSocketAddress(addr1); + child.AddSocketAddress(addr2); + + // Child should match both its own rules and parent's. + CHECK(child.Apply(addr1)); + CHECK(child.Apply(addr2)); + + // Parent should only match its own rules. + CHECK(parent->Apply(addr1)); + CHECK(!parent->Apply(addr2)); +} + +TEST(SocketAddressBlockList, SubnetOverlapRemoval) { + // Removing a broader subnet must restore narrower subnets that were + // subsumed by the broader prefix in the trie. + SocketAddressBlockList bl; + + sockaddr_storage s1, s2, s3; + SocketAddress::ToSockAddr(AF_INET, "10.0.0.0", 0, &s1); + SocketAddress::ToSockAddr(AF_INET, "10.1.0.0", 0, &s2); + SocketAddress::ToSockAddr(AF_INET, "10.1.2.3", 0, &s3); + + SocketAddress broad(reinterpret_cast(&s1)); + SocketAddress narrow(reinterpret_cast(&s2)); + SocketAddress target(reinterpret_cast(&s3)); + + bl.AddSocketAddressMask(broad, 8); // 10.0.0.0/8 + bl.AddSocketAddressMask(narrow, 16); // 10.1.0.0/16 (subsumed by /8) + + CHECK(bl.Apply(target)); // Covered by /8. + + bl.RemoveSocketAddressMask(broad, 8); + + // After removing /8, the /16 must still work. + CHECK(bl.Apply(target)); + + // Address outside /16 but inside old /8 should no longer match. + sockaddr_storage s4; + SocketAddress::ToSockAddr(AF_INET, "10.2.0.1", 0, &s4); + SocketAddress outside(reinterpret_cast(&s4)); + CHECK(!bl.Apply(outside)); +} + +TEST(SocketAddressBlockList, SubnetRemoveMixedFamily) { + // Removing one family's subnet must correctly rebuild the remaining + // rules, including those from the other family. + SocketAddressBlockList bl; + + sockaddr_storage s1, s2, s3, s4; + SocketAddress::ToSockAddr(AF_INET, "192.168.0.0", 0, &s1); + SocketAddress::ToSockAddr(AF_INET6, "2001:db8::", 0, &s2); + SocketAddress::ToSockAddr(AF_INET, "192.168.1.1", 0, &s3); + SocketAddress::ToSockAddr(AF_INET6, "2001:db8::1", 0, &s4); + + SocketAddress ipv4Net(reinterpret_cast(&s1)); + SocketAddress ipv6Net(reinterpret_cast(&s2)); + SocketAddress ipv4Addr(reinterpret_cast(&s3)); + SocketAddress ipv6Addr(reinterpret_cast(&s4)); + + bl.AddSocketAddressMask(ipv4Net, 16); + bl.AddSocketAddressMask(ipv6Net, 32); + + CHECK(bl.Apply(ipv4Addr)); + CHECK(bl.Apply(ipv6Addr)); + + // Remove IPv4 subnet — IPv6 subnet must survive the rebuild. + bl.RemoveSocketAddressMask(ipv4Net, 16); + CHECK(!bl.Apply(ipv4Addr)); + CHECK(bl.Apply(ipv6Addr)); + + // Re-add IPv4, then remove IPv6 — IPv4 must survive. + bl.AddSocketAddressMask(ipv4Net, 16); + bl.RemoveSocketAddressMask(ipv6Net, 32); + CHECK(bl.Apply(ipv4Addr)); + CHECK(!bl.Apply(ipv6Addr)); +} diff --git a/test/client-proxy/test-https-proxy-request-invalid-char-in-url.mjs b/test/client-proxy/test-https-proxy-request-invalid-char-in-url.mjs index 80c7be4931cd..888137b9a5a6 100644 --- a/test/client-proxy/test-https-proxy-request-invalid-char-in-url.mjs +++ b/test/client-proxy/test-https-proxy-request-invalid-char-in-url.mjs @@ -82,19 +82,10 @@ for (const testCase of testCases) { proxy.close(); server.close(); assert.deepStrictEqual(requests, expectedUrls); - const logSet = new Set(logs); - for (const log of logSet) { - if (log.source === 'proxy connect' && log.error?.code === 'EPIPE') { - // There can be a race from eagerly shutting down the servers and severing - // two pipes at the same time but for the purpose of this test, we only - // care about whether the requests are initiated from the client as expected, - // not how the upstream/proxy servers behave. Ignore EPIPE errors from them.. - // Refs: https://github.com/nodejs/node/issues/59741 - console.log('Ignoring EPIPE error from proxy connect', log.error); - logSet.delete(log); - } - } - assert.deepStrictEqual(logSet, expectedProxyLogs); + const requestLogs = logs.filter((log) => !('error' in log)); + const errors = logs.filter((log) => 'error' in log); + assert.deepStrictEqual(new Set(requestLogs), expectedProxyLogs); + assert.deepStrictEqual(errors, []); })); } })); diff --git a/test/common/boringssl.js b/test/common/boringssl.js index e6e91387c304..ab7f0505b0ce 100644 --- a/test/common/boringssl.js +++ b/test/common/boringssl.js @@ -137,12 +137,9 @@ function testRenegotiationUnsupported() { } /** - * OpenSSL exposes the negotiated ephemeral key type, name, and size for TLS - * clients. With BoringSSL the same ECDHE TLS 1.2 handshake succeeds, but - * getEphemeralKeyInfo() returns null on the server side and an object whose - * fields are undefined on the client side. + * BoringSSL exposes the negotiated TLS group but not the ephemeral key size. */ -function testEphemeralKeyInfoUnsupported() { +function testEphemeralKeyInfo() { const server = tls.createServer({ key: fixtures.readKey('agent2-key.pem'), cert: fixtures.readKey('agent2-cert.pem'), @@ -161,8 +158,8 @@ function testEphemeralKeyInfoUnsupported() { maxVersion: 'TLSv1.2', }, common.mustCall(() => { assert.deepStrictEqual(client.getEphemeralKeyInfo(), { - type: undefined, - name: undefined, + type: 'TLSGroup', + name: 'prime256v1', size: undefined, }); server.close(); @@ -337,7 +334,7 @@ module.exports = { assertMultiKeyUnsupported, assertNoCipherMatch, assertOpenSSLSecurityLevelsUnsupported, - testEphemeralKeyInfoUnsupported, + testEphemeralKeyInfo, testLegacyProtocolUnsupported, testMultiPfxSelectionDifference, testPskTls13Unsupported, diff --git a/test/common/proxy-server.js b/test/common/proxy-server.js index a2f8bd12e625..723fe0ea5c6b 100644 --- a/test/common/proxy-server.js +++ b/test/common/proxy-server.js @@ -80,7 +80,14 @@ function createProxyServer(options = {}) { const normalizedHostname = hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname; - const proxyReq = net.connect(port, normalizedHostname, () => { + // A CONNECT tunnel is full-duplex. Keep the upstream socket writable after + // receiving a FIN so that the client-to-upstream pipe can finish draining. + // The reverse pipe will end `res`, and `res` will in turn end `proxyReq`. + const proxyReq = net.connect({ + port, + host: normalizedHostname, + allowHalfOpen: true, + }, () => { res.write( 'HTTP/1.1 200 Connection Established\r\n' + 'Proxy-agent: Node.js-Proxy\r\n' + diff --git a/test/common/sea.js b/test/common/sea.js index 5f3741e0117c..f0dfc8479888 100644 --- a/test/common/sea.js +++ b/test/common/sea.js @@ -20,7 +20,7 @@ function skipIfSingleExecutableIsNotSupported() { if (!['darwin', 'win32', 'linux'].includes(process.platform)) common.skip(`Unsupported platform ${process.platform}.`); - if (process.platform === 'linux' && process.config.variables.is_debug === 1) + if (process.platform === 'linux' && common.isDebug) common.skip('Running the resultant binary fails with `Couldn\'t read target executable"`.'); if (process.config.variables.node_shared) diff --git a/test/es-module/test-esm-loader-text-format.mjs b/test/es-module/test-esm-loader-text-format.mjs new file mode 100644 index 000000000000..2a35992dbcf4 --- /dev/null +++ b/test/es-module/test-esm-loader-text-format.mjs @@ -0,0 +1,23 @@ +import '../common/index.mjs'; +import assert from 'node:assert'; +import { registerHooks } from 'node:module'; + +// A user loader can use `text` with and without import attributes without the feature flag. + +registerHooks({ + load(url, context, nextLoad) { + if (url.endsWith('.txt')) { + return nextLoad(url, { ...context, format: 'text' }); + } + return nextLoad(url, context); + }, +}); + +const { default: text } = await import('../fixtures/file-to-read-without-bom.txt'); +const { default: empty } = await import( + '../fixtures/empty.txt', + { with: { type: 'text' } } +); + +assert.strictEqual(text, 'abc\ndef\nghi\n'); +assert.strictEqual(empty, ''); diff --git a/test/es-module/test-esm-long-path-win.js b/test/es-module/test-esm-long-path-win.js index d125d341f092..d8aaabcca857 100644 --- a/test/es-module/test-esm-long-path-win.js +++ b/test/es-module/test-esm-long-path-win.js @@ -47,6 +47,24 @@ describe('long path on Windows', () => { tmpdir.refresh(); }); + it('runs an extended-length path as the entry point', async () => { + // The module loader resolves argv[1] through the JavaScript realpath + // implementation before executing it. + tmpdir.refresh(); + const entry = tmpdir.resolve('extended-entry.js'); + fs.writeFileSync(entry, 'console.log("hello world");'); + + const { code, signal, stderr, stdout } = await spawnPromisified( + execPath, + [path.toNamespacedPath(entry)], + ); + + assert.strictEqual(stderr, ''); + assert.strictEqual(stdout.trim(), 'hello world'); + assert.strictEqual(code, 0); + assert.strictEqual(signal, null); + }); + it('check long path in LegacyMainResolve - 1', () => { // Module layout will be the following: // package.json diff --git a/test/fixtures/sea/assets/sea-config.json b/test/fixtures/sea/assets/sea-config.json index 78a64534b44e..979bda0dca13 100644 --- a/test/fixtures/sea/assets/sea-config.json +++ b/test/fixtures/sea/assets/sea-config.json @@ -2,6 +2,8 @@ "main": "sea.js", "output": "sea-prep.blob", "assets": { + "a": "utf8_test_text.txt", + "a\u0000b": "person.jpg", "utf8_test_text.txt": "utf8_test_text.txt", "person.jpg": "person.jpg" } diff --git a/test/fixtures/sea/assets/sea.js b/test/fixtures/sea/assets/sea.js index e1a2189aa4da..b6b775fdd159 100644 --- a/test/fixtures/sea/assets/sea.js +++ b/test/fixtures/sea/assets/sea.js @@ -54,6 +54,12 @@ assert(isSea()); const textAssetOnDisk = readFileSync(process.env.__TEST_UTF8_TEXT_PATH, 'utf8'); const binaryAssetOnDisk = readFileSync(process.env.__TEST_PERSON_JPG); +// Check asset keys containing NUL. +{ + assert.strictEqual(getAsset('a', 'utf8'), textAssetOnDisk); + assert.deepStrictEqual(Buffer.from(getAsset('a\0b')), binaryAssetOnDisk); +} + // Check getAsset() buffer copies. { // Check that the asset embedded is the same as the original. diff --git a/test/fixtures/sea/exec-argv-extension-cli/sea-config.json b/test/fixtures/sea/exec-argv-extension-cli/sea-config.json index 0ec0d706b384..cb4606558c7f 100644 --- a/test/fixtures/sea/exec-argv-extension-cli/sea-config.json +++ b/test/fixtures/sea/exec-argv-extension-cli/sea-config.json @@ -2,6 +2,5 @@ "main": "sea.js", "output": "sea-prep.blob", "disableExperimentalSEAWarning": true, - "execArgv": ["--no-warnings"], "execArgvExtension": "cli" } diff --git a/test/fixtures/sea/exec-argv-extension-cli/sea.js b/test/fixtures/sea/exec-argv-extension-cli/sea.js index e9585483fcc2..11bc7fa36560 100644 --- a/test/fixtures/sea/exec-argv-extension-cli/sea.js +++ b/test/fixtures/sea/exec-argv-extension-cli/sea.js @@ -3,7 +3,7 @@ const assert = require('assert'); console.log('process.argv:', JSON.stringify(process.argv)); console.log('process.execArgv:', JSON.stringify(process.execArgv)); -// Should have execArgv from SEA config + CLI --node-options +// Should have all options from CLI --node-options assert.deepStrictEqual(process.execArgv, ['--no-warnings', '--max-old-space-size=1024']); assert.deepStrictEqual(process.argv.slice(2), [ diff --git a/test/fixtures/source-map/get-call-sites-function-name-mapped.js b/test/fixtures/source-map/get-call-sites-function-name-mapped.js new file mode 100644 index 000000000000..d400af7f2fb8 --- /dev/null +++ b/test/fixtures/source-map/get-call-sites-function-name-mapped.js @@ -0,0 +1,2 @@ +const{getCallSites}=require('node:util');function foo(){process.stdout.write(JSON.stringify(getCallSites({sourceMap:true})[0]))}foo(); +//# sourceMappingURL=get-call-sites-function-name-mapped.map diff --git a/test/fixtures/source-map/get-call-sites-function-name-mapped.map b/test/fixtures/source-map/get-call-sites-function-name-mapped.map new file mode 100644 index 000000000000..de70e4512ffa --- /dev/null +++ b/test/fixtures/source-map/get-call-sites-function-name-mapped.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["get-call-sites-function-name-original.js"], + "sourcesContent": ["const { getCallSites } = require('node:util'); function foo() { process.stdout.write(JSON.stringify(getCallSites({ sourceMap: true })[0])); } foo();"], + "mappings": "AAAA,KAAM,CAAE,YAAa,EAAI,QAAQ,WAAW,EAAG,SAAS,KAAM,CAAE,QAAQ,OAAO,MAAM,KAAK,UAAU,aAAa,CAAE,UAAW,EAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAG,CAAE,IAAI", + "names": [] +} diff --git a/test/fixtures/syntax/bad_syntax_esm_ambiguous.js b/test/fixtures/syntax/bad_syntax_esm_ambiguous.js new file mode 100644 index 000000000000..511f42994f90 --- /dev/null +++ b/test/fixtures/syntax/bad_syntax_esm_ambiguous.js @@ -0,0 +1,2 @@ +import fs from 'node:fs'; +var = ; diff --git a/test/fixtures/test-runner/coverage-default-exclusion/test/.dotfile.cjs b/test/fixtures/test-runner/coverage-default-exclusion/test/.dotfile.cjs new file mode 100644 index 000000000000..ec0a4c24fffb --- /dev/null +++ b/test/fixtures/test-runner/coverage-default-exclusion/test/.dotfile.cjs @@ -0,0 +1,7 @@ +const test = require('node:test'); +const assert = require('node:assert'); +const { foo } = require('../logic-file.js'); + +test('foo returns 1 from a dotfile test', () => { + assert.strictEqual(foo(), 1); +}); diff --git a/test/fixtures/test-runner/mock-nm-dual-pkg.js b/test/fixtures/test-runner/mock-nm-dual-pkg.js new file mode 100644 index 000000000000..3686373c6032 --- /dev/null +++ b/test/fixtures/test-runner/mock-nm-dual-pkg.js @@ -0,0 +1,32 @@ +'use strict'; +const assert = require('node:assert'); +const { test } = require('node:test'); +const fixture = 'dual-pkg-with-exports'; + +test('mock node_modules dual package with conditional exports', async (t) => { + const mock = t.mock.module(fixture, { + namedExports: { add(x, y) { return 1 + x + y; }, flavor: 'mocked' }, + }); + + // CJS require should pick up the mock even though the package's "exports" + // field maps the "require" condition to a different file than "import". + const cjsImpl = require(fixture); + assert.strictEqual(cjsImpl.add(4, 5), 10); + assert.strictEqual(cjsImpl.flavor, 'mocked'); + + // ESM dynamic import should also pick up the mock. + const esmImpl = await import(fixture); + assert.strictEqual(esmImpl.add(4, 5), 10); + assert.strictEqual(esmImpl.flavor, 'mocked'); + + mock.restore(); + + // After restore, both module systems should see the original exports. + const restoredCjs = require(fixture); + assert.strictEqual(restoredCjs.add(4, 5), 9); + assert.strictEqual(restoredCjs.flavor, 'cjs'); + + const restoredEsm = await import(fixture); + assert.strictEqual(restoredEsm.add(4, 5), 9); + assert.strictEqual(restoredEsm.flavor, 'esm'); +}); diff --git a/test/fixtures/test-runner/node_modules/dual-pkg-with-exports/index.cjs b/test/fixtures/test-runner/node_modules/dual-pkg-with-exports/index.cjs new file mode 100644 index 000000000000..a8085de75d60 --- /dev/null +++ b/test/fixtures/test-runner/node_modules/dual-pkg-with-exports/index.cjs @@ -0,0 +1,5 @@ +'use strict'; +const add = (x, y) => x + y; +const flavor = 'cjs'; + +module.exports = { add, flavor }; diff --git a/test/fixtures/test-runner/node_modules/dual-pkg-with-exports/index.js b/test/fixtures/test-runner/node_modules/dual-pkg-with-exports/index.js new file mode 100644 index 000000000000..f9e72d7f62fb --- /dev/null +++ b/test/fixtures/test-runner/node_modules/dual-pkg-with-exports/index.js @@ -0,0 +1,2 @@ +export const add = (x, y) => x + y; +export const flavor = 'esm'; diff --git a/test/fixtures/test-runner/node_modules/dual-pkg-with-exports/package.json b/test/fixtures/test-runner/node_modules/dual-pkg-with-exports/package.json new file mode 100644 index 000000000000..e225302a770e --- /dev/null +++ b/test/fixtures/test-runner/node_modules/dual-pkg-with-exports/package.json @@ -0,0 +1,12 @@ +{ + "name": "dual-pkg-with-exports", + "type": "module", + "main": "index.js", + "exports": { + ".": { + "import": "./index.js", + "require": "./index.cjs" + } + }, + "private": true +} diff --git a/test/fixtures/test-runner/output/dot_reporter_coverage_threshold.js b/test/fixtures/test-runner/output/dot_reporter_coverage_threshold.js new file mode 100644 index 000000000000..b49dd1488151 --- /dev/null +++ b/test/fixtures/test-runner/output/dot_reporter_coverage_threshold.js @@ -0,0 +1,17 @@ +'use strict'; +require('../../../common'); +const fixtures = require('../../../common/fixtures'); +const spawn = require('node:child_process').spawn; + +spawn( + process.execPath, + [ + '--no-warnings', + '--experimental-test-coverage', + '--test-coverage-exclude=!test/**', + '--test-coverage-lines=99', + '--test-reporter', 'dot', + fixtures.path('test-runner/coverage.js'), + ], + { stdio: 'inherit' }, +); diff --git a/test/fixtures/test-runner/output/dot_reporter_coverage_threshold.snapshot b/test/fixtures/test-runner/output/dot_reporter_coverage_threshold.snapshot new file mode 100644 index 000000000000..0645329f1a84 --- /dev/null +++ b/test/fixtures/test-runner/output/dot_reporter_coverage_threshold.snapshot @@ -0,0 +1,18 @@ +invalid tap output +. +ℹ Error: 78.35% line coverage does not meet threshold of 99%. +ℹ start of coverage report +ℹ -------------------------------------------------------------------------------------------- +ℹ file | line % | branch % | funcs % | uncovered lines +ℹ -------------------------------------------------------------------------------------------- +ℹ test | | | | +ℹ fixtures | | | | +ℹ test-runner | | | | +ℹ coverage.js | 78.65 | 38.46 | 60.00 | 12-13 16-22 27 39 43-44 61-62 66-67 71-72 +ℹ invalid-tap.js | 100.00 | 100.00 | 100.00 | +ℹ v8-coverage | | | | +ℹ throw.js | 71.43 | 50.00 | 100.00 | 5-6 +ℹ -------------------------------------------------------------------------------------------- +ℹ all files | 78.35 | 43.75 | 60.00 | +ℹ -------------------------------------------------------------------------------------------- +ℹ end of coverage report diff --git a/test/fixtures/test-runner/output/junit_classname_hierarchy.js b/test/fixtures/test-runner/output/junit_classname_hierarchy.js new file mode 100644 index 000000000000..8b634be39380 --- /dev/null +++ b/test/fixtures/test-runner/output/junit_classname_hierarchy.js @@ -0,0 +1,19 @@ +'use strict'; +require('../../../common'); +const { suite, test } = require('node:test'); + +suite('Math', () => { + suite('Addition', () => { + test('adds positive numbers', () => {}); + }); + + suite('Multiplication', () => { + test('multiplies positive numbers', () => {}); + }); +}); + +suite('String', () => { + test('concatenates strings', () => {}); +}); + +test('standalone test', () => {}); diff --git a/test/fixtures/test-runner/output/junit_classname_hierarchy.snapshot b/test/fixtures/test-runner/output/junit_classname_hierarchy.snapshot new file mode 100644 index 000000000000..fd3806f531e0 --- /dev/null +++ b/test/fixtures/test-runner/output/junit_classname_hierarchy.snapshot @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/test-runner/output/junit_empty_diagnostic.js b/test/fixtures/test-runner/output/junit_empty_diagnostic.js new file mode 100644 index 000000000000..491c2f230d98 --- /dev/null +++ b/test/fixtures/test-runner/output/junit_empty_diagnostic.js @@ -0,0 +1,8 @@ +// Flags: --test --test-reporter=junit +'use strict'; +const test = require('node:test'); + +test('failing', (t) => { + t.diagnostic(''); + throw new Error('error'); +}); diff --git a/test/fixtures/test-runner/output/junit_empty_diagnostic.snapshot b/test/fixtures/test-runner/output/junit_empty_diagnostic.snapshot new file mode 100644 index 000000000000..666c5c3523a7 --- /dev/null +++ b/test/fixtures/test-runner/output/junit_empty_diagnostic.snapshot @@ -0,0 +1,23 @@ + + + + +[Error [ERR_TEST_FAILURE]: error] { + code: 'ERR_TEST_FAILURE', + failureType: 'testCodeFailure', + cause: Error: error + at TestContext.<anonymous> (/test/fixtures/test-runner/output/junit_empty_diagnostic.js:7:9) + at +} + + + + + + + + + + + + diff --git a/test/fixtures/test-runner/output/junit_reporter.snapshot b/test/fixtures/test-runner/output/junit_reporter.snapshot index cef5f0b52da1..5130996dd2fd 100644 --- a/test/fixtures/test-runner/output/junit_reporter.snapshot +++ b/test/fixtures/test-runner/output/junit_reporter.snapshot @@ -129,7 +129,7 @@ true !== false - + Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail at TestContext.<anonymous> (/test/fixtures/test-runner/output/output.js:125:11) @@ -152,15 +152,15 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail - - - - + + + + - + - + @@ -267,9 +267,9 @@ Error [ERR_TEST_FAILURE]: thrown from callback async throw - - - + + + @@ -289,7 +289,7 @@ Error [ERR_TEST_FAILURE]: thrown from callback async throw - + Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at first at TestContext.<anonymous> (/test/fixtures/test-runner/output/output.js:334:11) @@ -304,7 +304,7 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at first } - + Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at second at TestContext.<anonymous> (/test/fixtures/test-runner/output/output.js:337:11) { diff --git a/test/fixtures/test-runner/test-runner-isolation-none.mjs b/test/fixtures/test-runner/test-runner-isolation-none.mjs new file mode 100644 index 000000000000..03a32fd6ad57 --- /dev/null +++ b/test/fixtures/test-runner/test-runner-isolation-none.mjs @@ -0,0 +1,32 @@ +import { run } from 'node:test'; +import { tap } from 'node:test/reporters'; +import { parseArgs } from 'node:util'; + +const { + values, +} = parseArgs({ + args: process.argv.slice(2), + options: { + file: { type: 'string' }, + only: { type: 'boolean' }, + 'name-pattern': { type: 'string' }, + 'skip-pattern': { type: 'string' }, + }, +}); + +const opts = { + isolation: 'none', + files: [values.file], +}; + +if (values.only) { + opts.only = true; +} +if (values['name-pattern']) { + opts.testNamePatterns = [new RegExp(values['name-pattern'])]; +} +if (values['skip-pattern']) { + opts.testSkipPatterns = [new RegExp(values['skip-pattern'])]; +} + +run(opts).compose(tap).pipe(process.stdout); \ No newline at end of file diff --git a/test/fixtures/wpt/WebCryptoAPI/WEB_FEATURES.yml b/test/fixtures/wpt/WebCryptoAPI/WEB_FEATURES.yml index 6f47b86ed48f..036774d5563e 100644 --- a/test/fixtures/wpt/WebCryptoAPI/WEB_FEATURES.yml +++ b/test/fixtures/wpt/WebCryptoAPI/WEB_FEATURES.yml @@ -1,3 +1,2 @@ -features: -- name: web-cryptography - files: '**' +rules: +- "**": [web-cryptography] diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves.js new file mode 100644 index 000000000000..25113bfe04a1 --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves.js @@ -0,0 +1,128 @@ +async function defineCfrgTests(algorithmName, operation) { + const subtle = self.crypto.subtle; + const isDeriveBits = operation === "deriveBits"; + + kSmallOrderPoint[algorithmName].forEach(test => { + promise_test(async() => { + let privateKey; + let publicKey; + let derived; + let error; + + try { + privateKey = await subtle.importKey( + "pkcs8", + pkcs8[algorithmName], + {name: algorithmName}, + false, + ["deriveBits", "deriveKey"] + ); + publicKey = await subtle.importKey( + "spki", + test.vector, + {name: algorithmName}, + false, + [] + ); + derived = isDeriveBits + ? await subtle.deriveBits( + {name: algorithmName, public: publicKey}, + privateKey, + 8 * sizes[algorithmName] + ) + : await subtle.deriveKey( + {name: algorithmName, public: publicKey}, + privateKey, + {name: "HMAC", hash: "SHA-256", length: 256}, + true, + ["sign", "verify"] + ); + } catch (caught) { + error = caught; + } + + assert_not_equals(privateKey, undefined, "Private key should be valid."); + assert_not_equals(publicKey, undefined, "Public key should be valid."); + assert_not_equals(error, undefined, "Operation should fail."); + assert_equals( + error.name, + "OperationError", + "Should throw correct error, not " + error.name + ": " + error.message + "." + ); + assert_equals(derived, undefined, "Operation succeeded, but should not have."); + }, algorithmName + + (isDeriveBits ? " key derivation" : " deriveBits") + + " checks for all-zero value result with a key of order " + test.order); + }); + + if (!isDeriveBits) { + promise_test(async() => { + const key = await subtle.generateKey( + {name: algorithmName}, + true, + ["deriveKey", "deriveBits"] + ); + const derived = await subtle.deriveKey( + {name: algorithmName, public: key.publicKey}, + key.privateKey, + {name: "HMAC", hash: "SHA-256", length: 256}, + true, + ["sign", "verify"] + ); + assert_not_equals(derived, undefined, "Key derivation failed."); + }, "Key derivation using a " + algorithmName + " generated keys."); + } + + const noUsage = isDeriveBits ? ["deriveKey"] : ["deriveBits"]; + const [ + privateKey, + noUsagePrivateKey, + publicKey, + ecdhPublicKey, + ] = await Promise.all([ + subtle.importKey( + "pkcs8", + pkcs8[algorithmName], + {name: algorithmName}, + false, + ["deriveBits", "deriveKey"] + ), + subtle.importKey( + "pkcs8", + pkcs8[algorithmName], + {name: algorithmName}, + false, + noUsage + ), + subtle.importKey( + "spki", + spki[algorithmName], + {name: algorithmName}, + false, + [] + ), + subtle.importKey( + "spki", + ecSPKI, + {name: "ECDH", namedCurve: "P-256"}, + false, + [] + ), + ]); + + registerDeriveTests({ + operation, + algorithmName, + mixedCaseName: algorithmName.toLowerCase(), + size: sizes[algorithmName], + derivation: derivations[algorithmName], + privateKey, + publicKey, + noUsagePrivateKey, + invalidPublicKeys: [{ + name: algorithmName + " mismatched algorithms", + key: ecdhPublicKey, + }], + missingPublicLabel: algorithmName + " missing public property", + }); +} diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits.js index 1406e8bf0a19..c3826a295e62 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits.js @@ -1,227 +1,7 @@ function define_tests_25519() { - return define_tests("X25519"); + return defineCfrgTests("X25519", "deriveBits"); } function define_tests_448() { - return define_tests("X448"); -} - -function define_tests(algorithmName) { - // May want to test prefixed implementations. - var subtle = self.crypto.subtle; - - // Verify the derive functions perform checks against the all-zero value results, - // ensuring small-order points are rejected. - // https://www.rfc-editor.org/rfc/rfc7748#section-6.1 - { - kSmallOrderPoint[algorithmName].forEach(function(test) { - promise_test(async() => { - let derived; - let privateKey; - let publicKey; - try { - privateKey = await subtle.importKey("pkcs8", pkcs8[algorithmName], - {name: algorithmName}, - false, ["deriveBits", "deriveKey"]); - publicKey = await subtle.importKey("spki", test.vector, - {name: algorithmName}, - false, []) - derived = await subtle.deriveBits({name: algorithmName, public: publicKey}, privateKey, 8 * sizes[algorithmName]); - } catch (err) { - assert_true(privateKey !== undefined, "Private key should be valid."); - assert_true(publicKey !== undefined, "Public key should be valid."); - assert_equals(err.name, "OperationError", "Should throw correct error, not " + err.name + ": " + err.message + "."); - } - assert_equals(derived, undefined, "Operation succeeded, but should not have."); - }, algorithmName + " key derivation checks for all-zero value result with a key of order " + test.order); - }); - } - - return importKeys(pkcs8, spki, sizes) - .then(function(results) { - publicKeys = results.publicKeys; - privateKeys = results.privateKeys; - noDeriveBitsKeys = results.noDeriveBitsKeys; - ecdhKeys = results.ecdhKeys; - - { - // Basic success case - promise_test(function(test) { - return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName]) - .then(function(derivation) { - assert_true(equalBuffers(derivation, derivations[algorithmName]), "Derived correct bits"); - }, function(err) { - assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); - }); - }, algorithmName + " good parameters"); - - // Case insensitivity check - promise_test(function(test) { - return subtle.deriveBits({name: algorithmName.toLowerCase(), public: publicKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName]) - .then(function(derivation) { - assert_true(equalBuffers(derivation, derivations[algorithmName]), "Derived correct bits"); - }, function(err) { - assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); - }); - }, algorithmName + " mixed case parameters"); - - // Shorter than entire derivation per algorithm - promise_test(function(test) { - return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName] - 32) - .then(function(derivation) { - assert_true(equalBuffers(derivation, derivations[algorithmName], 8 * sizes[algorithmName] - 32), "Derived correct bits"); - }, function(err) { - assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); - }); - }, algorithmName + " short result"); - - // Non-multiple of 8 - promise_test(function(test) { - return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName] - 11) - .then(function(derivation) { - assert_true(equalBuffers(derivation, derivations[algorithmName], 8 * sizes[algorithmName] - 11), "Derived correct bits"); - }, function(err) { - assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); - }); - }, algorithmName + " non-multiple of 8 bits"); - - // Errors to test: - - // - missing public property TypeError - promise_test(function(test) { - return subtle.deriveBits({name: algorithmName}, privateKeys[algorithmName], 8 * sizes[algorithmName]) - .then(function(derivation) { - assert_unreached("deriveBits succeeded but should have failed with TypeError"); - }, function(err) { - assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, algorithmName + " missing public property"); - - // - Non CryptoKey public property TypeError - promise_test(function(test) { - return subtle.deriveBits({name: algorithmName, public: {message: "Not a CryptoKey"}}, privateKeys[algorithmName], 8 * sizes[algorithmName]) - .then(function(derivation) { - assert_unreached("deriveBits succeeded but should have failed with TypeError"); - }, function(err) { - assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, algorithmName + " public property of algorithm is not a CryptoKey"); - - // - wrong algorithm - promise_test(function(test) { - return subtle.deriveBits({name: algorithmName, public: ecdhKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName]) - .then(function(derivation) { - assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, algorithmName + " mismatched algorithms"); - - // - No deriveBits usage in baseKey InvalidAccessError - promise_test(function(test) { - return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, noDeriveBitsKeys[algorithmName], 8 * sizes[algorithmName]) - .then(function(derivation) { - assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, algorithmName + " no deriveBits usage for base key"); - - // - Use public key for baseKey InvalidAccessError - promise_test(function(test) { - return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, publicKeys[algorithmName], 8 * sizes[algorithmName]) - .then(function(derivation) { - assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, algorithmName + " base key is not a private key"); - - // - Use private key for public property InvalidAccessError - promise_test(function(test) { - return subtle.deriveBits({name: algorithmName, public: privateKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName]) - .then(function(derivation) { - assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, algorithmName + " public property value is a private key"); - - // - Use secret key for public property InvalidAccessError - promise_test(function(test) { - return subtle.generateKey({name: "AES-CBC", length: 128}, true, ["encrypt", "decrypt"]) - .then(function(secretKey) { - return subtle.deriveBits({name: algorithmName, public: secretKey}, privateKeys[algorithmName], 8 * sizes[algorithmName]) - .then(function(derivation) { - assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }); - }, algorithmName + " public property value is a secret key"); - - // - Length greater than possible for particular curves OperationError - promise_test(function(test) { - return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName] + 8) - .then(function(derivation) { - assert_unreached("deriveBits succeeded but should have failed with OperationError"); - }, function(err) { - assert_equals(err.name, "OperationError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, algorithmName + " asking for too many bits"); - } - }); - - function importKeys(pkcs8, spki, sizes) { - var privateKeys = {}; - var publicKeys = {}; - var noDeriveBitsKeys = {}; - var ecdhPublicKeys = {}; - - var promises = []; - { - var operation = subtle.importKey("pkcs8", pkcs8[algorithmName], - {name: algorithmName}, - false, ["deriveBits", "deriveKey"]) - .then(function(key) { - privateKeys[algorithmName] = key; - }, function (err) { - privateKeys[algorithmName] = null; - }); - promises.push(operation); - } - { - var operation = subtle.importKey("pkcs8", pkcs8[algorithmName], - {name: algorithmName}, - false, ["deriveKey"]) - .then(function(key) { - noDeriveBitsKeys[algorithmName] = key; - }, function (err) { - noDeriveBitsKeys[algorithmName] = null; - }); - promises.push(operation); - } - { - var operation = subtle.importKey("spki", spki[algorithmName], - {name: algorithmName}, - false, []) - .then(function(key) { - publicKeys[algorithmName] = key; - }, function (err) { - publicKeys[algorithmName] = null; - }); - promises.push(operation); - } - { - var operation = subtle.importKey("spki", ecSPKI, - {name: "ECDH", namedCurve: "P-256"}, - false, []) - .then(function(key) { - ecdhPublicKeys[algorithmName] = key; - }); - } - return Promise.all(promises) - .then(function(results) {return {privateKeys: privateKeys, publicKeys: publicKeys, noDeriveBitsKeys: noDeriveBitsKeys, ecdhKeys: ecdhPublicKeys}}); - } - + return defineCfrgTests("X448", "deriveBits"); } diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve25519.https.any.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve25519.https.any.js index 5684d7624076..b42565208874 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve25519.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve25519.https.any.js @@ -1,6 +1,8 @@ // META: title=WebCryptoAPI: deriveKey() Using ECDH with CFRG Elliptic Curves // META: script=../util/helpers.js // META: script=cfrg_curves_bits_fixtures.js +// META: script=derive.js +// META: script=cfrg_curves.js // META: script=cfrg_curves_bits.js // Define subtests from a `promise_test` to ensure the harness does not diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.tentative.https.any.js index 5e482ef0b9d8..cda5ba87fba0 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.tentative.https.any.js @@ -1,6 +1,8 @@ // META: title=WebCryptoAPI: deriveKey() Using ECDH with CFRG Elliptic Curves // META: script=../util/helpers.js // META: script=cfrg_curves_bits_fixtures.js +// META: script=derive.js +// META: script=cfrg_curves.js // META: script=cfrg_curves_bits.js // Define subtests from a `promise_test` to ensure the harness does not diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys.js index cefc45ac6929..1989c55c903f 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys.js @@ -1,224 +1,7 @@ function define_tests_25519() { - return define_tests("X25519"); + return defineCfrgTests("X25519", "deriveKey"); } function define_tests_448() { - return define_tests("X448"); -} - -function define_tests(algorithmName) { - // May want to test prefixed implementations. - var subtle = self.crypto.subtle; - - // Verify the derive functions perform checks against the all-zero value results, - // ensuring small-order points are rejected. - // https://www.rfc-editor.org/rfc/rfc7748#section-6.1 - // TODO: The spec states that the check must be done on use, but there is discussion about doing it on import. - // https://github.com/WICG/webcrypto-secure-curves/pull/13 - { - kSmallOrderPoint[algorithmName].forEach(function(test) { - promise_test(async() => { - let derived; - let privateKey; - let publicKey; - try { - privateKey = await subtle.importKey("pkcs8", pkcs8[algorithmName], - {name: algorithmName}, - false, ["deriveBits", "deriveKey"]); - publicKey = await subtle.importKey("spki", test.vector, - {name: algorithmName}, - false, []) - derived = await subtle.deriveKey({name: algorithmName, public: publicKey}, privateKey, - {name: "HMAC", hash: "SHA-256", length: 256}, true, - ["sign", "verify"]); - } catch (err) { - assert_false(privateKey === undefined, "Private key should be valid."); - assert_false(publicKey === undefined, "Public key should be valid."); - assert_equals(err.name, "OperationError", "Should throw correct error, not " + err.name + ": " + err.message + "."); - } - assert_equals(derived, undefined, "Operation succeeded, but should not have."); - }, algorithmName + " deriveBits checks for all-zero value result with a key of order " + test.order); - }); - } - - // Ensure the keys generated by each algorithm are valid for key derivation. - { - promise_test(async() => { - let derived; - try { - let key = await subtle.generateKey({name: algorithmName}, true, ["deriveKey", "deriveBits"]); - derived = await subtle.deriveKey({name: algorithmName, public: key.publicKey}, key.privateKey, {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]); - } catch (err) { - assert_unreached("Threw an unexpected error: " + err.toString() + " -"); - } - assert_false (derived === undefined, "Key derivation failed."); - }, "Key derivation using a " + algorithmName + " generated keys."); - } - - return importKeys(pkcs8, spki, sizes) - .then(function(results) { - publicKeys = results.publicKeys; - privateKeys = results.privateKeys; - noDeriveKeyKeys = results.noDeriveKeyKeys; - ecdhKeys = results.ecdhKeys; - - { - // Basic success case - promise_test(function(test) { - return subtle.deriveKey({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) - .then(function(key) {return crypto.subtle.exportKey("raw", key);}) - .then(function(exportedKey) { - assert_true(equalBuffers(exportedKey, derivations[algorithmName], 8 * exportedKey.length), "Derived correct key"); - }, function(err) { - assert_unreached("deriveKey failed with error " + err.name + ": " + err.message); - }); - }, algorithmName + " good parameters"); - - // Case insensitivity check - promise_test(function(test) { - return subtle.deriveKey({name: algorithmName.toLowerCase(), public: publicKeys[algorithmName]}, privateKeys[algorithmName], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) - .then(function(key) {return crypto.subtle.exportKey("raw", key);}) - .then(function(exportedKey) { - assert_true(equalBuffers(exportedKey, derivations[algorithmName], 8 * exportedKey.length), "Derived correct key"); - }, function(err) { - assert_unreached("deriveKey failed with error " + err.name + ": " + err.message); - }); - }, algorithmName + " mixed case parameters"); - // Errors to test: - - // - missing public property TypeError - promise_test(function(test) { - return subtle.deriveKey({name: algorithmName}, privateKeys[algorithmName], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) - .then(function(key) {return crypto.subtle.exportKey("raw", key);}) - .then(function(exportedKey) { - assert_unreached("deriveKey succeeded but should have failed with TypeError"); - }, function(err) { - assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, algorithmName + " missing public property"); - - // - Non CryptoKey public property TypeError - promise_test(function(test) { - return subtle.deriveKey({name: algorithmName, public: {message: "Not a CryptoKey"}}, privateKeys[algorithmName], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) - .then(function(key) {return crypto.subtle.exportKey("raw", key);}) - .then(function(exportedKey) { - assert_unreached("deriveKey succeeded but should have failed with TypeError"); - }, function(err) { - assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, algorithmName + " public property of algorithm is not a CryptoKey"); - - // - wrong algorithm - promise_test(function(test) { - return subtle.deriveKey({name: algorithmName, public: ecdhKeys[algorithmName]}, privateKeys[algorithmName], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) - .then(function(key) {return crypto.subtle.exportKey("raw", key);}) - .then(function(exportedKey) { - assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, algorithmName + " mismatched algorithms"); - - // - No deriveKey usage in baseKey InvalidAccessError - promise_test(function(test) { - return subtle.deriveKey({name: algorithmName, public: publicKeys[algorithmName]}, noDeriveKeyKeys[algorithmName], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) - .then(function(key) {return crypto.subtle.exportKey("raw", key);}) - .then(function(exportedKey) { - assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, algorithmName + " no deriveKey usage for base key"); - - // - Use public key for baseKey InvalidAccessError - promise_test(function(test) { - return subtle.deriveKey({name: algorithmName, public: publicKeys[algorithmName]}, publicKeys[algorithmName], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) - .then(function(key) {return crypto.subtle.exportKey("raw", key);}) - .then(function(exportedKey) { - assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, algorithmName + " base key is not a private key"); - - // - Use private key for public property InvalidAccessError - promise_test(function(test) { - return subtle.deriveKey({name: algorithmName, public: privateKeys[algorithmName]}, privateKeys[algorithmName], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) - .then(function(key) {return crypto.subtle.exportKey("raw", key);}) - .then(function(exportedKey) { - assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, algorithmName + " public property value is a private key"); - - // - Use secret key for public property InvalidAccessError - promise_test(function(test) { - return subtle.generateKey({name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) - .then(function(secretKey) { - return subtle.deriveKey({name: algorithmName, public: secretKey}, privateKeys[algorithmName], {name: "AES-CBC", length: 256}, true, ["sign", "verify"]) - .then(function(key) {return crypto.subtle.exportKey("raw", key);}) - .then(function(exportedKey) { - assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }); - }, algorithmName + " public property value is a secret key"); - } - }); - - function importKeys(pkcs8, spki, sizes) { - var privateKeys = {}; - var publicKeys = {}; - var noDeriveKeyKeys = {}; - var ecdhPublicKeys = {}; - - var promises = []; - { - var operation = subtle.importKey("pkcs8", pkcs8[algorithmName], - {name: algorithmName}, - false, ["deriveBits", "deriveKey"]) - .then(function(key) { - privateKeys[algorithmName] = key; - }, function (err) { - privateKeys[algorithmName] = null; - }); - promises.push(operation); - } - { - var operation = subtle.importKey("pkcs8", pkcs8[algorithmName], - {name: algorithmName}, - false, ["deriveBits"]) - .then(function(key) { - noDeriveKeyKeys[algorithmName] = key; - }, function (err) { - noDeriveKeyKeys[algorithmName] = null; - }); - promises.push(operation); - } - { - var operation = subtle.importKey("spki", spki[algorithmName], - {name: algorithmName}, - false, []) - .then(function(key) { - publicKeys[algorithmName] = key; - }, function (err) { - publicKeys[algorithmName] = null; - }); - promises.push(operation); - } - { - var operation = subtle.importKey("spki", ecSPKI, - {name: "ECDH", namedCurve: "P-256"}, - false, []) - .then(function(key) { - ecdhPublicKeys[algorithmName] = key; - }); - } - - return Promise.all(promises) - .then(function(results) {return {privateKeys: privateKeys, publicKeys: publicKeys, noDeriveKeyKeys: noDeriveKeyKeys, ecdhKeys: ecdhPublicKeys}}); - } - + return defineCfrgTests("X448", "deriveKey"); } diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve25519.https.any.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve25519.https.any.js index 8bcc201d4e95..683ae21bac9f 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve25519.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve25519.https.any.js @@ -1,6 +1,8 @@ // META: title=WebCryptoAPI: deriveKey() Using ECDH with CFRG Elliptic Curves // META: script=../util/helpers.js // META: script=cfrg_curves_bits_fixtures.js +// META: script=derive.js +// META: script=cfrg_curves.js // META: script=cfrg_curves_keys.js // Define subtests from a `promise_test` to ensure the harness does not diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.tentative.https.any.js index 0ed3954ac200..38a5ce1db5b2 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.tentative.https.any.js @@ -1,6 +1,8 @@ // META: title=WebCryptoAPI: deriveKey() Using ECDH with CFRG Elliptic Curves // META: script=../util/helpers.js // META: script=cfrg_curves_bits_fixtures.js +// META: script=derive.js +// META: script=cfrg_curves.js // META: script=cfrg_curves_keys.js // Define subtests from a `promise_test` to ensure the harness does not diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derive.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derive.js new file mode 100644 index 000000000000..16c9ec6407bb --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derive.js @@ -0,0 +1,169 @@ +function registerDeriveTests(options) { + const { + operation, + algorithmName, + testName = algorithmName, + mixedCaseName, + size, + derivation, + privateKey, + publicKey, + noUsagePrivateKey, + invalidPublicKeys, + missingPublicLabel, + } = options; + const subtle = self.crypto.subtle; + const isDeriveBits = operation === "deriveBits"; + const derivedKeyAlgorithm = {name: "HMAC", hash: "SHA-256", length: 256}; + const derivedKeyUsages = ["sign", "verify"]; + + function derive(name, publicKey, baseKey, length = 8 * size, keyOptions = {}) { + const algorithm = {name, public: publicKey}; + if (isDeriveBits) { + return subtle.deriveBits(algorithm, baseKey, length); + } + + return subtle.deriveKey( + algorithm, + baseKey, + keyOptions.algorithm || derivedKeyAlgorithm, + true, + keyOptions.usages || derivedKeyUsages + ).then(key => subtle.exportKey("raw", key)); + } + + function assertDerived(result, length) { + if (isDeriveBits) { + assert_true(equalBuffers(result, derivation, length), "Derived correct bits"); + } else { + assert_array_equals( + new Uint8Array(result), + derivation.slice(0, 32), + "Derived correct key" + ); + } + } + + function successTest(name, algorithm, length = 8 * size) { + promise_test(() => { + return derive(algorithm, publicKey, privateKey, length).then( + result => assertDerived(result, length), + error => assert_unreached( + operation + " failed with error " + error.name + ": " + error.message + ) + ); + }, name); + } + + function failureTest(name, expectedError, deriveOperation) { + promise_test(() => { + return Promise.resolve().then(deriveOperation).then( + () => assert_unreached( + operation + " succeeded but should have failed with " + expectedError + ), + error => assert_equals( + error.name, + expectedError, + "Should throw correct error, not " + error.name + ": " + error.message + ) + ); + }, name); + } + + successTest(testName + " good parameters", algorithmName); + successTest(testName + " mixed case parameters", mixedCaseName); + + if (isDeriveBits) { + successTest(testName + " short result", algorithmName, 8 * size - 32); + successTest( + testName + " non-multiple of 8 bits", + algorithmName, + 8 * size - 11 + ); + } + + failureTest(missingPublicLabel, "TypeError", () => { + return subtle[operation]( + {name: algorithmName}, + privateKey, + ...(isDeriveBits + ? [8 * size] + : [derivedKeyAlgorithm, true, derivedKeyUsages]) + ); + }); + + failureTest( + testName + " public property of algorithm is not a CryptoKey", + "TypeError", + () => derive(algorithmName, {message: "Not a CryptoKey"}, privateKey) + ); + + invalidPublicKeys.forEach(test => { + failureTest( + test.name, + "InvalidAccessError", + () => derive(algorithmName, test.key, privateKey) + ); + }); + + failureTest( + testName + " no " + operation + " usage for base key", + "InvalidAccessError", + () => derive(algorithmName, publicKey, noUsagePrivateKey) + ); + + failureTest( + testName + " base key is not a private key", + "InvalidAccessError", + () => derive(algorithmName, publicKey, publicKey) + ); + + failureTest( + testName + " public property value is a private key", + "InvalidAccessError", + () => derive(algorithmName, privateKey, privateKey) + ); + + promise_test(async() => { + const secretKey = isDeriveBits + ? await subtle.generateKey( + {name: "AES-CBC", length: 128}, + true, + ["encrypt", "decrypt"] + ) + : await subtle.generateKey( + derivedKeyAlgorithm, + true, + derivedKeyUsages + ); + const keyOptions = isDeriveBits ? {} : { + algorithm: {name: "AES-CBC", length: 256}, + usages: ["sign", "verify"], + }; + + return derive( + algorithmName, + secretKey, + privateKey, + 8 * size, + keyOptions + ).then( + () => assert_unreached( + operation + " succeeded but should have failed with InvalidAccessError" + ), + error => assert_equals( + error.name, + "InvalidAccessError", + "Should throw correct error, not " + error.name + ": " + error.message + ) + ); + }, testName + " public property value is a secret key"); + + if (isDeriveBits) { + failureTest( + testName + " asking for too many bits", + "OperationError", + () => derive(algorithmName, publicKey, privateKey, 8 * size + 8) + ); + } +} diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh.js new file mode 100644 index 000000000000..99039f250c2c --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh.js @@ -0,0 +1,79 @@ +async function defineEcdhTests(operation) { + const subtle = self.crypto.subtle; + const fixtures = getEcdhTestFixtures(); + const curves = Object.keys(fixtures.sizes); + const keys = {}; + + await Promise.all(curves.map(async namedCurve => { + const algorithm = {name: "ECDH", namedCurve}; + const noUsage = operation === "deriveBits" ? ["deriveKey"] : ["deriveBits"]; + const [ + privateKey, + noUsagePrivateKey, + publicKey, + ecdsaKeyPair, + ] = await Promise.all([ + subtle.importKey( + "pkcs8", + fixtures.pkcs8[namedCurve], + algorithm, + false, + ["deriveBits", "deriveKey"] + ), + subtle.importKey( + "pkcs8", + fixtures.pkcs8[namedCurve], + algorithm, + false, + noUsage + ), + subtle.importKey( + "spki", + fixtures.spki[namedCurve], + algorithm, + false, + [] + ), + subtle.generateKey( + {name: "ECDSA", namedCurve}, + false, + ["sign", "verify"] + ), + ]); + + keys[namedCurve] = { + privateKey, + noUsagePrivateKey, + publicKey, + ecdsaKeyPair, + }; + })); + + curves.forEach(namedCurve => { + const otherCurve = namedCurve === "P-256" ? "P-384" : "P-256"; + const key = keys[namedCurve]; + registerDeriveTests({ + operation, + algorithmName: "ECDH", + testName: namedCurve, + mixedCaseName: "EcDh", + size: fixtures.sizes[namedCurve], + derivation: fixtures.derivations[namedCurve], + privateKey: key.privateKey, + publicKey: key.publicKey, + noUsagePrivateKey: key.noUsagePrivateKey, + invalidPublicKeys: [ + { + name: namedCurve + " mismatched curves", + key: keys[otherCurve].publicKey, + }, + { + name: namedCurve + + " public property of algorithm is not an ECDSA public key", + key: key.ecdsaKeyPair.publicKey, + }, + ], + missingPublicLabel: namedCurve + " missing public curve", + }); + }); +} diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.https.any.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.https.any.js index 58a0cecd5efe..38058d6ce723 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.https.any.js @@ -1,5 +1,8 @@ // META: title=WebCryptoAPI: deriveBits() Using ECDH // META: script=../util/helpers.js +// META: script=ecdh_fixtures.js +// META: script=derive.js +// META: script=ecdh.js // META: script=ecdh_bits.js // Define subtests from a `promise_test` to ensure the harness does not diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.js index 8e79909020d3..bbe48b5e2859 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.js @@ -1,233 +1,3 @@ - function define_tests() { - // May want to test prefixed implementations. - var subtle = self.crypto.subtle; - - var pkcs8 = { - "P-521": new Uint8Array([48, 129, 238, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 4, 129, 214, 48, 129, 211, 2, 1, 1, 4, 66, 1, 166, 126, 211, 33, 145, 90, 100, 170, 53, 155, 125, 100, 141, 220, 38, 24, 250, 142, 141, 24, 103, 232, 247, 24, 48, 177, 13, 37, 237, 40, 145, 250, 241, 47, 60, 126, 117, 66, 26, 46, 162, 100, 249, 169, 21, 50, 13, 39, 79, 225, 71, 7, 66, 185, 132, 233, 107, 152, 145, 32, 129, 250, 205, 71, 141, 161, 129, 137, 3, 129, 134, 0, 4, 0, 32, 157, 72, 63, 40, 102, 104, 129, 198, 100, 31, 58, 18, 111, 64, 15, 81, 228, 101, 17, 112, 254, 103, 140, 117, 232, 87, 18, 226, 134, 138, 220, 133, 8, 36, 153, 123, 235, 240, 188, 130, 180, 48, 40, 166, 210, 236, 23, 119, 202, 69, 39, 159, 114, 6, 163, 234, 139, 92, 210, 7, 63, 73, 62, 69, 0, 12, 181, 76, 58, 90, 202, 162, 104, 197, 103, 16, 66, 136, 120, 217, 139, 138, 251, 246, 138, 97, 33, 83, 99, 40, 70, 216, 7, 233, 38, 114, 105, 143, 27, 156, 97, 29, 231, 211, 142, 52, 205, 108, 115, 136, 144, 146, 197, 110, 82, 214, 128, 241, 223, 208, 146, 184, 122, 200, 239, 159, 243, 200, 251, 72]), - "P-256": new Uint8Array([48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 15, 247, 79, 232, 241, 202, 175, 97, 92, 206, 241, 29, 217, 53, 114, 87, 98, 217, 216, 65, 236, 186, 185, 94, 170, 38, 68, 123, 52, 100, 245, 113, 161, 68, 3, 66, 0, 4, 140, 96, 11, 44, 102, 25, 45, 97, 158, 39, 210, 37, 107, 59, 151, 118, 178, 141, 30, 5, 246, 13, 234, 189, 98, 174, 123, 154, 211, 157, 224, 217, 59, 4, 102, 109, 199, 119, 14, 126, 207, 13, 211, 203, 203, 211, 110, 221, 107, 94, 220, 153, 81, 7, 55, 161, 237, 104, 46, 205, 112, 244, 10, 47]), - "P-384": new Uint8Array([48, 129, 182, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 4, 129, 158, 48, 129, 155, 2, 1, 1, 4, 48, 248, 113, 165, 102, 101, 137, 193, 74, 87, 71, 38, 62, 248, 91, 49, 156, 192, 35, 219, 110, 53, 103, 108, 61, 120, 30, 239, 139, 5, 95, 207, 190, 134, 250, 13, 6, 208, 86, 181, 25, 95, 177, 50, 58, 248, 222, 37, 179, 161, 100, 3, 98, 0, 4, 241, 25, 101, 223, 125, 212, 89, 77, 4, 25, 197, 8, 100, 130, 163, 184, 38, 185, 121, 127, 155, 224, 189, 13, 16, 156, 158, 30, 153, 137, 193, 185, 169, 43, 143, 38, 159, 152, 225, 122, 209, 132, 186, 115, 193, 247, 151, 98, 175, 69, 175, 129, 65, 96, 38, 66, 218, 39, 26, 107, 176, 255, 235, 12, 180, 71, 143, 207, 112, 126, 102, 26, 166, 214, 205, 245, 21, 73, 200, 140, 63, 19, 11, 233, 232, 32, 31, 111, 106, 9, 244, 24, 90, 175, 149, 196]) - }; - - var spki = { - "P-521": new Uint8Array([48, 129, 155, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 3, 129, 134, 0, 4, 0, 238, 105, 249, 71, 21, 215, 1, 233, 226, 1, 19, 51, 212, 244, 249, 108, 186, 125, 145, 248, 139, 17, 43, 175, 117, 207, 9, 204, 31, 138, 202, 151, 97, 141, 169, 56, 152, 34, 210, 155, 111, 233, 153, 106, 97, 32, 62, 247, 82, 183, 113, 232, 149, 143, 196, 103, 123, 179, 119, 133, 101, 171, 96, 214, 237, 0, 222, 171, 103, 97, 137, 91, 147, 94, 58, 211, 37, 251, 133, 73, 229, 111, 19, 120, 106, 167, 63, 136, 162, 236, 254, 64, 147, 52, 115, 216, 174, 242, 64, 196, 223, 215, 213, 6, 242, 44, 221, 14, 85, 85, 143, 63, 191, 5, 235, 247, 239, 239, 122, 114, 215, 143, 70, 70, 155, 132, 72, 242, 110, 39, 18]), - "P-256": new Uint8Array([48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 154, 116, 32, 120, 126, 95, 77, 105, 211, 232, 34, 114, 115, 1, 109, 56, 224, 71, 129, 133, 223, 127, 238, 156, 142, 103, 60, 202, 211, 79, 126, 128, 254, 49, 141, 182, 221, 107, 119, 218, 99, 32, 165, 246, 151, 89, 9, 68, 23, 177, 52, 239, 138, 139, 116, 193, 101, 4, 57, 198, 115, 0, 90, 61]), - "P-384": new Uint8Array([48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 145, 130, 45, 194, 175, 89, 193, 143, 91, 103, 248, 13, 246, 26, 38, 3, 194, 168, 240, 179, 192, 175, 130, 45, 99, 194, 121, 112, 26, 130, 69, 96, 64, 68, 1, 221, 233, 165, 110, 229, 39, 87, 234, 139, 199, 72, 212, 200, 43, 83, 55, 180, 141, 123, 101, 88, 58, 61, 87, 36, 56, 136, 0, 54, 186, 198, 115, 15, 66, 202, 82, 120, 150, 107, 213, 242, 30, 134, 226, 29, 48, 197, 166, 208, 70, 62, 197, 19, 221, 80, 159, 252, 220, 175, 31, 245]) - }; - - var sizes = { - "P-521": 66, - "P-256": 32, - "P-384": 48 - }; - - var derivations = { - "P-521": new Uint8Array([0, 156, 43, 206, 87, 190, 128, 173, 171, 59, 7, 56, 91, 142, 89, 144, 235, 125, 111, 222, 189, 176, 27, 243, 83, 113, 164, 246, 7, 94, 157, 40, 138, 193, 42, 109, 254, 3, 170, 87, 67, 188, 129, 112, 157, 73, 168, 34, 148, 2, 25, 182, 75, 118, 138, 205, 82, 15, 161, 54, 142, 160, 175, 141, 71, 93]), - "P-256": new Uint8Array([14, 143, 60, 77, 177, 178, 162, 131, 115, 90, 0, 220, 87, 31, 26, 232, 151, 28, 227, 35, 250, 17, 131, 137, 203, 95, 65, 196, 59, 61, 181, 161]), - "P-384": new Uint8Array([224, 189, 107, 206, 10, 239, 140, 164, 136, 56, 166, 226, 252, 197, 126, 103, 185, 197, 232, 134, 12, 95, 11, 233, 218, 190, 197, 62, 69, 78, 24, 160, 161, 116, 196, 136, 136, 162, 100, 136, 17, 91, 45, 201, 241, 223, 165, 45]) - }; - - return importKeys(pkcs8, spki, sizes) - .then(function(results) { - publicKeys = results.publicKeys; - privateKeys = results.privateKeys; - ecdsaKeyPairs = results.ecdsaKeyPairs; - noDeriveBitsKeys = results.noDeriveBitsKeys; - - Object.keys(sizes).forEach(function(namedCurve) { - // Basic success case - promise_test(function(test) { - return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve]) - .then(function(derivation) { - assert_true(equalBuffers(derivation, derivations[namedCurve]), "Derived correct bits"); - }, function(err) { - assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); - }); - }, namedCurve + " good parameters"); - - // Case insensitivity check - promise_test(function(test) { - return subtle.deriveBits({name: "EcDh", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve]) - .then(function(derivation) { - assert_true(equalBuffers(derivation, derivations[namedCurve]), "Derived correct bits"); - }, function(err) { - assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); - }); - }, namedCurve + " mixed case parameters"); - - // Shorter than entire derivation per algorithm - promise_test(function(test) { - return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve] - 32) - .then(function(derivation) { - assert_true(equalBuffers(derivation, derivations[namedCurve], 8 * sizes[namedCurve] - 32), "Derived correct bits"); - }, function(err) { - assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); - }); - }, namedCurve + " short result"); - - // Non-multiple of 8 - promise_test(function(test) { - return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve] - 11) - .then(function(derivation) { - assert_true(equalBuffers(derivation, derivations[namedCurve], 8 * sizes[namedCurve] - 11), "Derived correct bits"); - }, function(err) { - assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); - }); - }, namedCurve + " non-multiple of 8 bits"); - - // Errors to test: - - // - missing public property TypeError - promise_test(function(test) { - return subtle.deriveBits({name: "ECDH"}, privateKeys[namedCurve], 8 * sizes[namedCurve]) - .then(function(derivation) { - assert_unreached("deriveBits succeeded but should have failed with TypeError"); - }, function(err) { - assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, namedCurve + " missing public curve"); - - // - Non CryptoKey public property TypeError - promise_test(function(test) { - return subtle.deriveBits({name: "ECDH", public: {message: "Not a CryptoKey"}}, privateKeys[namedCurve], 8 * sizes[namedCurve]) - .then(function(derivation) { - assert_unreached("deriveBits succeeded but should have failed with TypeError"); - }, function(err) { - assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, namedCurve + " public property of algorithm is not a CryptoKey"); - - // - wrong named curve - promise_test(function(test) { - publicKey = publicKeys["P-256"]; - if (namedCurve === "P-256") { - publicKey = publicKeys["P-384"]; - } - return subtle.deriveBits({name: "ECDH", public: publicKey}, privateKeys[namedCurve], 8 * sizes[namedCurve]) - .then(function(derivation) { - assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, namedCurve + " mismatched curves"); - - // - not ECDH public property InvalidAccessError - promise_test(function(test) { - return subtle.deriveBits({name: "ECDH", public: ecdsaKeyPairs[namedCurve].publicKey}, privateKeys[namedCurve], 8 * sizes[namedCurve]) - .then(function(derivation) { - assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, namedCurve + " public property of algorithm is not an ECDSA public key"); - - // - No deriveBits usage in baseKey InvalidAccessError - promise_test(function(test) { - return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, noDeriveBitsKeys[namedCurve], 8 * sizes[namedCurve]) - .then(function(derivation) { - assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, namedCurve + " no deriveBits usage for base key"); - - // - Use public key for baseKey InvalidAccessError - promise_test(function(test) { - return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, publicKeys[namedCurve], 8 * sizes[namedCurve]) - .then(function(derivation) { - assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, namedCurve + " base key is not a private key"); - - // - Use private key for public property InvalidAccessError - promise_test(function(test) { - return subtle.deriveBits({name: "ECDH", public: privateKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve]) - .then(function(derivation) { - assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, namedCurve + " public property value is a private key"); - - // - Use secret key for public property InvalidAccessError - promise_test(function(test) { - return subtle.generateKey({name: "AES-CBC", length: 128}, true, ["encrypt", "decrypt"]) - .then(function(secretKey) { - return subtle.deriveBits({name: "ECDH", public: secretKey}, privateKeys[namedCurve], 8 * sizes[namedCurve]) - .then(function(derivation) { - assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }); - }, namedCurve + " public property value is a secret key"); - - // - Length greater than 256, 384, 521 for particular curves OperationError - promise_test(function(test) { - return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve] + 8) - .then(function(derivation) { - assert_unreached("deriveBits succeeded but should have failed with OperationError"); - }, function(err) { - assert_equals(err.name, "OperationError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, namedCurve + " asking for too many bits"); - }); - }); - - function importKeys(pkcs8, spki, sizes) { - var privateKeys = {}; - var publicKeys = {}; - var ecdsaKeyPairs = {}; - var noDeriveBitsKeys = {}; - - var promises = []; - Object.keys(pkcs8).forEach(function(namedCurve) { - var operation = subtle.importKey("pkcs8", pkcs8[namedCurve], - {name: "ECDH", namedCurve: namedCurve}, - false, ["deriveBits", "deriveKey"]) - .then(function(key) { - privateKeys[namedCurve] = key; - }, function (err) { - privateKeys[namedCurve] = null; - }); - promises.push(operation); - }); - Object.keys(pkcs8).forEach(function(namedCurve) { - var operation = subtle.importKey("pkcs8", pkcs8[namedCurve], - {name: "ECDH", namedCurve: namedCurve}, - false, ["deriveKey"]) - .then(function(key) { - noDeriveBitsKeys[namedCurve] = key; - }, function (err) { - noDeriveBitsKeys[namedCurve] = null; - }); - promises.push(operation); - }); - Object.keys(spki).forEach(function(namedCurve) { - var operation = subtle.importKey("spki", spki[namedCurve], - {name: "ECDH", namedCurve: namedCurve}, - false, []) - .then(function(key) { - publicKeys[namedCurve] = key; - }, function (err) { - publicKeys[namedCurve] = null; - }); - promises.push(operation); - }); - Object.keys(sizes).forEach(function(namedCurve) { - var operation = subtle.generateKey({name: "ECDSA", namedCurve: namedCurve}, false, ["sign", "verify"]) - .then(function(keyPair) { - ecdsaKeyPairs[namedCurve] = keyPair; - }, function (err) { - ecdsaKeyPairs[namedCurve] = null; - }); - promises.push(operation); - }); - - return Promise.all(promises) - .then(function(results) {return {privateKeys: privateKeys, publicKeys: publicKeys, ecdsaKeyPairs: ecdsaKeyPairs, noDeriveBitsKeys: noDeriveBitsKeys}}); - } - + return defineEcdhTests("deriveBits"); } diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_fixtures.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_fixtures.js new file mode 100644 index 000000000000..46539d548da7 --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_fixtures.js @@ -0,0 +1,32 @@ +function getEcdhTestFixtures() { + var pkcs8 = { + "P-521": new Uint8Array([48, 129, 238, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 4, 129, 214, 48, 129, 211, 2, 1, 1, 4, 66, 1, 166, 126, 211, 33, 145, 90, 100, 170, 53, 155, 125, 100, 141, 220, 38, 24, 250, 142, 141, 24, 103, 232, 247, 24, 48, 177, 13, 37, 237, 40, 145, 250, 241, 47, 60, 126, 117, 66, 26, 46, 162, 100, 249, 169, 21, 50, 13, 39, 79, 225, 71, 7, 66, 185, 132, 233, 107, 152, 145, 32, 129, 250, 205, 71, 141, 161, 129, 137, 3, 129, 134, 0, 4, 0, 32, 157, 72, 63, 40, 102, 104, 129, 198, 100, 31, 58, 18, 111, 64, 15, 81, 228, 101, 17, 112, 254, 103, 140, 117, 232, 87, 18, 226, 134, 138, 220, 133, 8, 36, 153, 123, 235, 240, 188, 130, 180, 48, 40, 166, 210, 236, 23, 119, 202, 69, 39, 159, 114, 6, 163, 234, 139, 92, 210, 7, 63, 73, 62, 69, 0, 12, 181, 76, 58, 90, 202, 162, 104, 197, 103, 16, 66, 136, 120, 217, 139, 138, 251, 246, 138, 97, 33, 83, 99, 40, 70, 216, 7, 233, 38, 114, 105, 143, 27, 156, 97, 29, 231, 211, 142, 52, 205, 108, 115, 136, 144, 146, 197, 110, 82, 214, 128, 241, 223, 208, 146, 184, 122, 200, 239, 159, 243, 200, 251, 72]), + "P-256": new Uint8Array([48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 15, 247, 79, 232, 241, 202, 175, 97, 92, 206, 241, 29, 217, 53, 114, 87, 98, 217, 216, 65, 236, 186, 185, 94, 170, 38, 68, 123, 52, 100, 245, 113, 161, 68, 3, 66, 0, 4, 140, 96, 11, 44, 102, 25, 45, 97, 158, 39, 210, 37, 107, 59, 151, 118, 178, 141, 30, 5, 246, 13, 234, 189, 98, 174, 123, 154, 211, 157, 224, 217, 59, 4, 102, 109, 199, 119, 14, 126, 207, 13, 211, 203, 203, 211, 110, 221, 107, 94, 220, 153, 81, 7, 55, 161, 237, 104, 46, 205, 112, 244, 10, 47]), + "P-384": new Uint8Array([48, 129, 182, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 4, 129, 158, 48, 129, 155, 2, 1, 1, 4, 48, 248, 113, 165, 102, 101, 137, 193, 74, 87, 71, 38, 62, 248, 91, 49, 156, 192, 35, 219, 110, 53, 103, 108, 61, 120, 30, 239, 139, 5, 95, 207, 190, 134, 250, 13, 6, 208, 86, 181, 25, 95, 177, 50, 58, 248, 222, 37, 179, 161, 100, 3, 98, 0, 4, 241, 25, 101, 223, 125, 212, 89, 77, 4, 25, 197, 8, 100, 130, 163, 184, 38, 185, 121, 127, 155, 224, 189, 13, 16, 156, 158, 30, 153, 137, 193, 185, 169, 43, 143, 38, 159, 152, 225, 122, 209, 132, 186, 115, 193, 247, 151, 98, 175, 69, 175, 129, 65, 96, 38, 66, 218, 39, 26, 107, 176, 255, 235, 12, 180, 71, 143, 207, 112, 126, 102, 26, 166, 214, 205, 245, 21, 73, 200, 140, 63, 19, 11, 233, 232, 32, 31, 111, 106, 9, 244, 24, 90, 175, 149, 196]) + }; + + var spki = { + "P-521": new Uint8Array([48, 129, 155, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 3, 129, 134, 0, 4, 0, 238, 105, 249, 71, 21, 215, 1, 233, 226, 1, 19, 51, 212, 244, 249, 108, 186, 125, 145, 248, 139, 17, 43, 175, 117, 207, 9, 204, 31, 138, 202, 151, 97, 141, 169, 56, 152, 34, 210, 155, 111, 233, 153, 106, 97, 32, 62, 247, 82, 183, 113, 232, 149, 143, 196, 103, 123, 179, 119, 133, 101, 171, 96, 214, 237, 0, 222, 171, 103, 97, 137, 91, 147, 94, 58, 211, 37, 251, 133, 73, 229, 111, 19, 120, 106, 167, 63, 136, 162, 236, 254, 64, 147, 52, 115, 216, 174, 242, 64, 196, 223, 215, 213, 6, 242, 44, 221, 14, 85, 85, 143, 63, 191, 5, 235, 247, 239, 239, 122, 114, 215, 143, 70, 70, 155, 132, 72, 242, 110, 39, 18]), + "P-256": new Uint8Array([48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 154, 116, 32, 120, 126, 95, 77, 105, 211, 232, 34, 114, 115, 1, 109, 56, 224, 71, 129, 133, 223, 127, 238, 156, 142, 103, 60, 202, 211, 79, 126, 128, 254, 49, 141, 182, 221, 107, 119, 218, 99, 32, 165, 246, 151, 89, 9, 68, 23, 177, 52, 239, 138, 139, 116, 193, 101, 4, 57, 198, 115, 0, 90, 61]), + "P-384": new Uint8Array([48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 145, 130, 45, 194, 175, 89, 193, 143, 91, 103, 248, 13, 246, 26, 38, 3, 194, 168, 240, 179, 192, 175, 130, 45, 99, 194, 121, 112, 26, 130, 69, 96, 64, 68, 1, 221, 233, 165, 110, 229, 39, 87, 234, 139, 199, 72, 212, 200, 43, 83, 55, 180, 141, 123, 101, 88, 58, 61, 87, 36, 56, 136, 0, 54, 186, 198, 115, 15, 66, 202, 82, 120, 150, 107, 213, 242, 30, 134, 226, 29, 48, 197, 166, 208, 70, 62, 197, 19, 221, 80, 159, 252, 220, 175, 31, 245]) + }; + + var sizes = { + "P-521": 66, + "P-256": 32, + "P-384": 48 + }; + + var derivations = { + "P-521": new Uint8Array([0, 156, 43, 206, 87, 190, 128, 173, 171, 59, 7, 56, 91, 142, 89, 144, 235, 125, 111, 222, 189, 176, 27, 243, 83, 113, 164, 246, 7, 94, 157, 40, 138, 193, 42, 109, 254, 3, 170, 87, 67, 188, 129, 112, 157, 73, 168, 34, 148, 2, 25, 182, 75, 118, 138, 205, 82, 15, 161, 54, 142, 160, 175, 141, 71, 93]), + "P-256": new Uint8Array([14, 143, 60, 77, 177, 178, 162, 131, 115, 90, 0, 220, 87, 31, 26, 232, 151, 28, 227, 35, 250, 17, 131, 137, 203, 95, 65, 196, 59, 61, 181, 161]), + "P-384": new Uint8Array([224, 189, 107, 206, 10, 239, 140, 164, 136, 56, 166, 226, 252, 197, 126, 103, 185, 197, 232, 134, 12, 95, 11, 233, 218, 190, 197, 62, 69, 78, 24, 160, 161, 116, 196, 136, 136, 162, 100, 136, 17, 91, 45, 201, 241, 223, 165, 45]) + }; + + return { + pkcs8: pkcs8, + spki: spki, + sizes: sizes, + derivations: derivations, + }; +} diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.https.any.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.https.any.js index 6464dacfe3aa..f9d0da921d52 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.https.any.js @@ -1,5 +1,8 @@ // META: title=WebCryptoAPI: deriveKey() Using ECDH // META: script=../util/helpers.js +// META: script=ecdh_fixtures.js +// META: script=derive.js +// META: script=ecdh.js // META: script=ecdh_keys.js // Define subtests from a `promise_test` to ensure the harness does not diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.js index 8c3d2aeb5a49..c4ee495aa6ff 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.js @@ -1,212 +1,3 @@ - function define_tests() { - // May want to test prefixed implementations. - var subtle = self.crypto.subtle; - - var pkcs8 = { - "P-521": new Uint8Array([48, 129, 238, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 4, 129, 214, 48, 129, 211, 2, 1, 1, 4, 66, 1, 166, 126, 211, 33, 145, 90, 100, 170, 53, 155, 125, 100, 141, 220, 38, 24, 250, 142, 141, 24, 103, 232, 247, 24, 48, 177, 13, 37, 237, 40, 145, 250, 241, 47, 60, 126, 117, 66, 26, 46, 162, 100, 249, 169, 21, 50, 13, 39, 79, 225, 71, 7, 66, 185, 132, 233, 107, 152, 145, 32, 129, 250, 205, 71, 141, 161, 129, 137, 3, 129, 134, 0, 4, 0, 32, 157, 72, 63, 40, 102, 104, 129, 198, 100, 31, 58, 18, 111, 64, 15, 81, 228, 101, 17, 112, 254, 103, 140, 117, 232, 87, 18, 226, 134, 138, 220, 133, 8, 36, 153, 123, 235, 240, 188, 130, 180, 48, 40, 166, 210, 236, 23, 119, 202, 69, 39, 159, 114, 6, 163, 234, 139, 92, 210, 7, 63, 73, 62, 69, 0, 12, 181, 76, 58, 90, 202, 162, 104, 197, 103, 16, 66, 136, 120, 217, 139, 138, 251, 246, 138, 97, 33, 83, 99, 40, 70, 216, 7, 233, 38, 114, 105, 143, 27, 156, 97, 29, 231, 211, 142, 52, 205, 108, 115, 136, 144, 146, 197, 110, 82, 214, 128, 241, 223, 208, 146, 184, 122, 200, 239, 159, 243, 200, 251, 72]), - "P-256": new Uint8Array([48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 15, 247, 79, 232, 241, 202, 175, 97, 92, 206, 241, 29, 217, 53, 114, 87, 98, 217, 216, 65, 236, 186, 185, 94, 170, 38, 68, 123, 52, 100, 245, 113, 161, 68, 3, 66, 0, 4, 140, 96, 11, 44, 102, 25, 45, 97, 158, 39, 210, 37, 107, 59, 151, 118, 178, 141, 30, 5, 246, 13, 234, 189, 98, 174, 123, 154, 211, 157, 224, 217, 59, 4, 102, 109, 199, 119, 14, 126, 207, 13, 211, 203, 203, 211, 110, 221, 107, 94, 220, 153, 81, 7, 55, 161, 237, 104, 46, 205, 112, 244, 10, 47]), - "P-384": new Uint8Array([48, 129, 182, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 4, 129, 158, 48, 129, 155, 2, 1, 1, 4, 48, 248, 113, 165, 102, 101, 137, 193, 74, 87, 71, 38, 62, 248, 91, 49, 156, 192, 35, 219, 110, 53, 103, 108, 61, 120, 30, 239, 139, 5, 95, 207, 190, 134, 250, 13, 6, 208, 86, 181, 25, 95, 177, 50, 58, 248, 222, 37, 179, 161, 100, 3, 98, 0, 4, 241, 25, 101, 223, 125, 212, 89, 77, 4, 25, 197, 8, 100, 130, 163, 184, 38, 185, 121, 127, 155, 224, 189, 13, 16, 156, 158, 30, 153, 137, 193, 185, 169, 43, 143, 38, 159, 152, 225, 122, 209, 132, 186, 115, 193, 247, 151, 98, 175, 69, 175, 129, 65, 96, 38, 66, 218, 39, 26, 107, 176, 255, 235, 12, 180, 71, 143, 207, 112, 126, 102, 26, 166, 214, 205, 245, 21, 73, 200, 140, 63, 19, 11, 233, 232, 32, 31, 111, 106, 9, 244, 24, 90, 175, 149, 196]) - }; - - var spki = { - "P-521": new Uint8Array([48, 129, 155, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 3, 129, 134, 0, 4, 0, 238, 105, 249, 71, 21, 215, 1, 233, 226, 1, 19, 51, 212, 244, 249, 108, 186, 125, 145, 248, 139, 17, 43, 175, 117, 207, 9, 204, 31, 138, 202, 151, 97, 141, 169, 56, 152, 34, 210, 155, 111, 233, 153, 106, 97, 32, 62, 247, 82, 183, 113, 232, 149, 143, 196, 103, 123, 179, 119, 133, 101, 171, 96, 214, 237, 0, 222, 171, 103, 97, 137, 91, 147, 94, 58, 211, 37, 251, 133, 73, 229, 111, 19, 120, 106, 167, 63, 136, 162, 236, 254, 64, 147, 52, 115, 216, 174, 242, 64, 196, 223, 215, 213, 6, 242, 44, 221, 14, 85, 85, 143, 63, 191, 5, 235, 247, 239, 239, 122, 114, 215, 143, 70, 70, 155, 132, 72, 242, 110, 39, 18]), - "P-256": new Uint8Array([48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 154, 116, 32, 120, 126, 95, 77, 105, 211, 232, 34, 114, 115, 1, 109, 56, 224, 71, 129, 133, 223, 127, 238, 156, 142, 103, 60, 202, 211, 79, 126, 128, 254, 49, 141, 182, 221, 107, 119, 218, 99, 32, 165, 246, 151, 89, 9, 68, 23, 177, 52, 239, 138, 139, 116, 193, 101, 4, 57, 198, 115, 0, 90, 61]), - "P-384": new Uint8Array([48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 145, 130, 45, 194, 175, 89, 193, 143, 91, 103, 248, 13, 246, 26, 38, 3, 194, 168, 240, 179, 192, 175, 130, 45, 99, 194, 121, 112, 26, 130, 69, 96, 64, 68, 1, 221, 233, 165, 110, 229, 39, 87, 234, 139, 199, 72, 212, 200, 43, 83, 55, 180, 141, 123, 101, 88, 58, 61, 87, 36, 56, 136, 0, 54, 186, 198, 115, 15, 66, 202, 82, 120, 150, 107, 213, 242, 30, 134, 226, 29, 48, 197, 166, 208, 70, 62, 197, 19, 221, 80, 159, 252, 220, 175, 31, 245]) - }; - - var sizes = { - "P-521": 66, - "P-256": 32, - "P-384": 48 - }; - - var derivations = { - "P-521": new Uint8Array([0, 156, 43, 206, 87, 190, 128, 173, 171, 59, 7, 56, 91, 142, 89, 144, 235, 125, 111, 222, 189, 176, 27, 243, 83, 113, 164, 246, 7, 94, 157, 40, 138, 193, 42, 109, 254, 3, 170, 87, 67, 188, 129, 112, 157, 73, 168, 34, 148, 2, 25, 182, 75, 118, 138, 205, 82, 15, 161, 54, 142, 160, 175, 141, 71, 93]), - "P-256": new Uint8Array([14, 143, 60, 77, 177, 178, 162, 131, 115, 90, 0, 220, 87, 31, 26, 232, 151, 28, 227, 35, 250, 17, 131, 137, 203, 95, 65, 196, 59, 61, 181, 161]), - "P-384": new Uint8Array([224, 189, 107, 206, 10, 239, 140, 164, 136, 56, 166, 226, 252, 197, 126, 103, 185, 197, 232, 134, 12, 95, 11, 233, 218, 190, 197, 62, 69, 78, 24, 160, 161, 116, 196, 136, 136, 162, 100, 136, 17, 91, 45, 201, 241, 223, 165, 45]) - }; - - return importKeys(pkcs8, spki, sizes) - .then(function(results) { - publicKeys = results.publicKeys; - privateKeys = results.privateKeys; - ecdsaKeyPairs = results.ecdsaKeyPairs; - noDeriveKeyKeys = results.noDeriveKeyKeys; - - Object.keys(sizes).forEach(function(namedCurve) { - // Basic success case - promise_test(function(test) { - return subtle.deriveKey({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) - .then(function(key) {return crypto.subtle.exportKey("raw", key);}) - .then(function(exportedKey) { - assert_true(equalBuffers(exportedKey, derivations[namedCurve], 8 * exportedKey.length), "Derived correct key"); - }, function(err) { - assert_unreached("deriveKey failed with error " + err.name + ": " + err.message); - }); - }, namedCurve + " good parameters"); - - // Case insensitivity check - promise_test(function(test) { - return subtle.deriveKey({name: "EcDh", public: publicKeys[namedCurve]}, privateKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) - .then(function(key) {return crypto.subtle.exportKey("raw", key);}) - .then(function(exportedKey) { - assert_true(equalBuffers(exportedKey, derivations[namedCurve], 8 * exportedKey.length), "Derived correct key"); - }, function(err) { - assert_unreached("deriveKey failed with error " + err.name + ": " + err.message); - }); - }, namedCurve + " mixed case parameters"); - // Errors to test: - - // - missing public property TypeError - promise_test(function(test) { - return subtle.deriveKey({name: "ECDH"}, privateKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) - .then(function(key) {return crypto.subtle.exportKey("raw", key);}) - .then(function(exportedKey) { - assert_unreached("deriveKey succeeded but should have failed with TypeError"); - }, function(err) { - assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, namedCurve + " missing public curve"); - - // - Non CryptoKey public property TypeError - promise_test(function(test) { - return subtle.deriveKey({name: "ECDH", public: {message: "Not a CryptoKey"}}, privateKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) - .then(function(key) {return crypto.subtle.exportKey("raw", key);}) - .then(function(exportedKey) { - assert_unreached("deriveKey succeeded but should have failed with TypeError"); - }, function(err) { - assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, namedCurve + " public property of algorithm is not a CryptoKey"); - - // - wrong named curve - promise_test(function(test) { - publicKey = publicKeys["P-256"]; - if (namedCurve === "P-256") { - publicKey = publicKeys["P-384"]; - } - return subtle.deriveKey({name: "ECDH", public: publicKey}, privateKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) - .then(function(key) {return crypto.subtle.exportKey("raw", key);}) - .then(function(exportedKey) { - assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, namedCurve + " mismatched curves"); - - // - not ECDH public property InvalidAccessError - promise_test(function(test) { - return subtle.deriveKey({name: "ECDH", public: ecdsaKeyPairs[namedCurve].publicKey}, privateKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) - .then(function(key) {return crypto.subtle.exportKey("raw", key);}) - .then(function(exportedKey) { - assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, namedCurve + " public property of algorithm is not an ECDSA public key"); - - // - No deriveKey usage in baseKey InvalidAccessError - promise_test(function(test) { - return subtle.deriveKey({name: "ECDH", public: publicKeys[namedCurve]}, noDeriveKeyKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) - .then(function(key) {return crypto.subtle.exportKey("raw", key);}) - .then(function(exportedKey) { - assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, namedCurve + " no deriveKey usage for base key"); - - // - Use public key for baseKey InvalidAccessError - promise_test(function(test) { - return subtle.deriveKey({name: "ECDH", public: publicKeys[namedCurve]}, publicKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) - .then(function(key) {return crypto.subtle.exportKey("raw", key);}) - .then(function(exportedKey) { - assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, namedCurve + " base key is not a private key"); - - // - Use private key for public property InvalidAccessError - promise_test(function(test) { - return subtle.deriveKey({name: "ECDH", public: privateKeys[namedCurve]}, privateKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) - .then(function(key) {return crypto.subtle.exportKey("raw", key);}) - .then(function(exportedKey) { - assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }, namedCurve + " public property value is a private key"); - - // - Use secret key for public property InvalidAccessError - promise_test(function(test) { - return subtle.generateKey({name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) - .then(function(secretKey) { - return subtle.deriveKey({name: "ECDH", public: secretKey}, privateKeys[namedCurve], {name: "AES-CBC", length: 256}, true, ["sign", "verify"]) - .then(function(key) {return crypto.subtle.exportKey("raw", key);}) - .then(function(exportedKey) { - assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); - }); - }); - }, namedCurve + " public property value is a secret key"); - }); - }); - - function importKeys(pkcs8, spki, sizes) { - var privateKeys = {}; - var publicKeys = {}; - var ecdsaKeyPairs = {}; - var noDeriveKeyKeys = {}; - - var promises = []; - Object.keys(pkcs8).forEach(function(namedCurve) { - var operation = subtle.importKey("pkcs8", pkcs8[namedCurve], - {name: "ECDH", namedCurve: namedCurve}, - false, ["deriveBits", "deriveKey"]) - .then(function(key) { - privateKeys[namedCurve] = key; - }, function (err) { - privateKeys[namedCurve] = null; - }); - promises.push(operation); - }); - Object.keys(pkcs8).forEach(function(namedCurve) { - var operation = subtle.importKey("pkcs8", pkcs8[namedCurve], - {name: "ECDH", namedCurve: namedCurve}, - false, ["deriveBits"]) - .then(function(key) { - noDeriveKeyKeys[namedCurve] = key; - }, function (err) { - noDeriveKeyKeys[namedCurve] = null; - }); - promises.push(operation); - }); - Object.keys(spki).forEach(function(namedCurve) { - var operation = subtle.importKey("spki", spki[namedCurve], - {name: "ECDH", namedCurve: namedCurve}, - false, []) - .then(function(key) { - publicKeys[namedCurve] = key; - }, function (err) { - publicKeys[namedCurve] = null; - }); - promises.push(operation); - }); - Object.keys(sizes).forEach(function(namedCurve) { - var operation = subtle.generateKey({name: "ECDSA", namedCurve: namedCurve}, false, ["sign", "verify"]) - .then(function(keyPair) { - ecdsaKeyPairs[namedCurve] = keyPair; - }, function (err) { - ecdsaKeyPairs[namedCurve] = null; - }); - promises.push(operation); - }); - - return Promise.all(promises) - .then(function(results) {return {privateKeys: privateKeys, publicKeys: publicKeys, ecdsaKeyPairs: ecdsaKeyPairs, noDeriveKeyKeys: noDeriveKeyKeys}}); - } - + return defineEcdhTests("deriveKey"); } diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/hkdf.https.any.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/hkdf.https.any.js index 3879ddb14b90..b283f2ba7920 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/hkdf.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/hkdf.https.any.js @@ -6,6 +6,7 @@ // META: script=../util/helpers.js // META: script=/common/subset-tests.js // META: script=hkdf_vectors.js +// META: script=kdf.js // META: script=hkdf.js // Define subtests from a `promise_test` to ensure the harness does not diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/hkdf.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/hkdf.js index 08e8c0c89746..a090169836e5 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/hkdf.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/hkdf.js @@ -1,278 +1,63 @@ - function define_tests() { - // May want to test prefixed implementations. - var subtle = self.crypto.subtle; - - // hkdf2_vectors sets up test data with the correct derivations for each - // test case. - var testData = getTestData(); - var derivedKeys = testData.derivedKeys; - var salts = testData.salts; - var derivations = testData.derivations; - var infos = testData.infos; - - // What kinds of keys can be created with deriveKey? The following: - var derivedKeyTypes = testData.derivedKeyTypes; - - return setUpBaseKeys(derivedKeys) - .then(function(allKeys) { - // We get several kinds of base keys. Normal ones that can be used for - // derivation operations, ones that lack the deriveBits usage, ones - // that lack the deriveKeys usage, and one key that is for the wrong - // algorithm (not HKDF in this case). - var baseKeys = allKeys.baseKeys; - var noBits = allKeys.noBits; - var noKey = allKeys.noKey; - var wrongKey = allKeys.wrongKey; - - // Test each combination of derivedKey size, salt size, hash function, - // and number of iterations. The derivations object is structured in - // that way, so navigate it to run tests and compare with correct results. - Object.keys(derivations).forEach(function(derivedKeySize) { - Object.keys(derivations[derivedKeySize]).forEach(function(saltSize) { - Object.keys(derivations[derivedKeySize][saltSize]).forEach(function(hashName) { - Object.keys(derivations[derivedKeySize][saltSize][hashName]).forEach(function(infoSize) { - var testName = derivedKeySize + " derivedKey, " + saltSize + " salt, " + hashName + ", with " + infoSize + " info"; - var algorithm = {name: "HKDF", salt: salts[saltSize], info: infos[infoSize], hash: hashName}; - - // Check for correct deriveBits result - subsetTest(promise_test, function(test) { - return subtle.deriveBits(algorithm, baseKeys[derivedKeySize], 256) - .then(function(derivation) { - assert_true(equalBuffers(derivation, derivations[derivedKeySize][saltSize][hashName][infoSize]), "Derived correct key"); - }, function(err) { - assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); - }); - }, testName); - - // 0 length - subsetTest(promise_test, function(test) { - return subtle.deriveBits(algorithm, baseKeys[derivedKeySize], 0) - .then(function(derivation) { - assert_equals(derivation.byteLength, 0, "Derived correctly empty key"); - }, function(err) { - assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); - }); - }, testName + " with 0 length"); - - // Check for correct deriveKey results for every kind of - // key that can be created by the deriveKeys operation. - derivedKeyTypes.forEach(function(derivedKeyType) { - var testName = "Derived key of type "; - Object.keys(derivedKeyType.algorithm).forEach(function(prop) { - testName += prop + ": " + derivedKeyType.algorithm[prop] + " "; - }); - testName += " using " + derivedKeySize + " derivedKey, " + saltSize + " salt, " + hashName + ", with " + infoSize + " info"; - - // Test the particular key derivation. - subsetTest(promise_test, function(test) { - return subtle.deriveKey(algorithm, baseKeys[derivedKeySize], derivedKeyType.algorithm, true, derivedKeyType.usages) - .then(function(key) { - // Need to export the key to see that the correct bits were set. - return subtle.exportKey("raw", key) - .then(function(buffer) { - assert_true(equalBuffers(buffer, derivations[derivedKeySize][saltSize][hashName][infoSize].slice(0, derivedKeyType.algorithm.length/8)), "Exported key matches correct value"); + return runKdfTests({ + name: "HKDF", + getBaseKeyData: function(testData) { + return testData.derivedKeys; + }, + registerTests: function(context) { + var subtle = context.subtle; + var testData = context.testData; + var derivations = testData.derivations; + var salts = testData.salts; + var infos = testData.infos; + + Object.keys(derivations).forEach(function(derivedKeySize) { + Object.keys(derivations[derivedKeySize]).forEach(function(saltSize) { + Object.keys(derivations[derivedKeySize][saltSize]).forEach(function(hashName) { + Object.keys(derivations[derivedKeySize][saltSize][hashName]).forEach(function(infoSize) { + var testName = derivedKeySize + " derivedKey, " + saltSize + " salt, " + hashName + ", with " + infoSize + " info"; + var testCase = { + name: testName, + keyName: derivedKeySize, + hash: hashName, + algorithm: {name: "HKDF", salt: salts[saltSize], info: infos[infoSize], hash: hashName}, + expected: derivations[derivedKeySize][saltSize][hashName][infoSize] + }; + + context.registerCase(testCase, function() { + subsetTest(promise_test, function(test) { + return subtle.deriveBits({name: "HKDF", info: infos[infoSize], hash: hashName}, context.keys.baseKeys[derivedKeySize], 0) + .then(function(derivation) { + assert_equals(derivation.byteLength, 0, "Derived even with missing salt"); }, function(err) { - assert_unreached("Exporting derived key failed with error " + err.name + ": " + err.message); + assert_equals(err.name, "TypeError", "deriveBits missing salt correctly threw OperationError: " + err.message); }); - }, function(err) { - assert_unreached("deriveKey failed with error " + err.name + ": " + err.message); - - }); - }, testName); - - // Test various error conditions for deriveKey: + }, testName + " with missing salt"); - // - illegal name for hash algorithm (NotSupportedError) - var badHash = hashName.substring(0, 3) + hashName.substring(4); - subsetTest(promise_test, function(test) { - var badAlgorithm = {name: "HKDF", salt: salts[saltSize], hash: badHash, info: algorithm.info}; - return subtle.deriveKey(badAlgorithm, baseKeys[derivedKeySize], derivedKeyType.algorithm, true, derivedKeyType.usages) - .then(function(key) { - assert_unreached("bad hash name should have thrown an NotSupportedError"); - }, function(err) { - assert_equals(err.name, "NotSupportedError", "deriveKey with bad hash name correctly threw NotSupportedError: " + err.message); - }); - }, testName + " with bad hash name " + badHash); - - // - baseKey usages missing "deriveKey" (InvalidAccessError) - subsetTest(promise_test, function(test) { - return subtle.deriveKey(algorithm, noKey[derivedKeySize], derivedKeyType.algorithm, true, derivedKeyType.usages) - .then(function(key) { - assert_unreached("missing deriveKey usage should have thrown an InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "deriveKey with missing deriveKey usage correctly threw InvalidAccessError: " + err.message); - }); - }, testName + " with missing deriveKey usage"); - - // - baseKey algorithm does not match HKDF (InvalidAccessError) - subsetTest(promise_test, function(test) { - return subtle.deriveKey(algorithm, wrongKey, derivedKeyType.algorithm, true, derivedKeyType.usages) - .then(function(key) { - assert_unreached("wrong (ECDH) key should have thrown an InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "deriveKey with wrong (ECDH) key correctly threw InvalidAccessError: " + err.message); - }); - }, testName + " with wrong (ECDH) key"); - - }); - - // Test various error conditions for deriveBits below: - - // missing salt (TypeError) - subsetTest(promise_test, function(test) { - return subtle.deriveBits({name: "HKDF", info: infos[infoSize], hash: hashName}, baseKeys[derivedKeySize], 0) - .then(function(derivation) { - assert_equals(derivation.byteLength, 0, "Derived even with missing salt"); - }, function(err) { - assert_equals(err.name, "TypeError", "deriveBits missing salt correctly threw OperationError: " + err.message); - }); - }, testName + " with missing salt"); - - // missing info (TypeError) - subsetTest(promise_test, function(test) { - return subtle.deriveBits({name: "HKDF", salt: salts[saltSize], hash: hashName}, baseKeys[derivedKeySize], 0) - .then(function(derivation) { - assert_equals(derivation.byteLength, 0, "Derived even with missing info"); - }, function(err) { - assert_equals(err.name, "TypeError", "deriveBits missing info correctly threw OperationError: " + err.message); - }); - }, testName + " with missing info"); - - // length not multiple of 8 (OperationError) - subsetTest(promise_test, function(test) { - return subtle.deriveBits(algorithm, baseKeys[derivedKeySize], 44) - .then(function(derivation) { - assert_unreached("non-multiple of 8 length should have thrown an OperationError"); - }, function(err) { - assert_equals(err.name, "OperationError", "deriveBits with non-multiple of 8 length correctly threw OperationError: " + err.message); - }); - }, testName + " with non-multiple of 8 length"); - - // - illegal name for hash algorithm (NotSupportedError) - var badHash = hashName.substring(0, 3) + hashName.substring(4); - subsetTest(promise_test, function(test) { - var badAlgorithm = {name: "HKDF", salt: salts[saltSize], hash: badHash, info: algorithm.info}; - return subtle.deriveBits(badAlgorithm, baseKeys[derivedKeySize], 256) - .then(function(derivation) { - assert_unreached("bad hash name should have thrown an NotSupportedError"); - }, function(err) { - assert_equals(err.name, "NotSupportedError", "deriveBits with bad hash name correctly threw NotSupportedError: " + err.message); - }); - }, testName + " with bad hash name " + badHash); - - // - baseKey usages missing "deriveBits" (InvalidAccessError) - subsetTest(promise_test, function(test) { - return subtle.deriveBits(algorithm, noBits[derivedKeySize], 256) - .then(function(derivation) { - assert_unreached("missing deriveBits usage should have thrown an InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "deriveBits with missing deriveBits usage correctly threw InvalidAccessError: " + err.message); - }); - }, testName + " with missing deriveBits usage"); - - // - baseKey algorithm does not match HKDF (InvalidAccessError) - subsetTest(promise_test, function(test) { - return subtle.deriveBits(algorithm, wrongKey, 256) - .then(function(derivation) { - assert_unreached("wrong (ECDH) key should have thrown an InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "deriveBits with wrong (ECDH) key correctly threw InvalidAccessError: " + err.message); + subsetTest(promise_test, function(test) { + return subtle.deriveBits({name: "HKDF", salt: salts[saltSize], hash: hashName}, context.keys.baseKeys[derivedKeySize], 0) + .then(function(derivation) { + assert_equals(derivation.byteLength, 0, "Derived even with missing info"); + }, function(err) { + assert_equals(err.name, "TypeError", "deriveBits missing info correctly threw OperationError: " + err.message); + }); + }, testName + " with missing info"); }); - }, testName + " with wrong (ECDH) key"); - }); - }); - - // - legal algorithm name but not digest one (e.g., PBKDF2) (NotSupportedError) - var nonDigestHash = "PBKDF2"; - Object.keys(infos).forEach(function(infoSize) { - var testName = derivedKeySize + " derivedKey, " + saltSize + " salt, " + nonDigestHash + ", with " + infoSize + " info"; - var algorithm = {name: "HKDF", salt: salts[saltSize], hash: nonDigestHash}; - if (infoSize !== "missing") { - algorithm.info = infos[infoSize]; - } - - subsetTest(promise_test, function(test) { - return subtle.deriveBits(algorithm, baseKeys[derivedKeySize], 256) - .then(function(derivation) { - assert_unreached("non-digest algorithm should have thrown an NotSupportedError"); - }, function(err) { - assert_equals(err.name, "NotSupportedError", "deriveBits with non-digest algorithm correctly threw NotSupportedError: " + err.message); }); - }, testName + " with non-digest algorithm " + nonDigestHash); + }); - derivedKeyTypes.forEach(function(derivedKeyType) { - var testName = "Derived key of type "; - Object.keys(derivedKeyType.algorithm).forEach(function(prop) { - testName += prop + ": " + derivedKeyType.algorithm[prop] + " "; + var nonDigestHash = "PBKDF2"; + Object.keys(infos).forEach(function(infoSize) { + var testName = derivedKeySize + " derivedKey, " + saltSize + " salt, " + nonDigestHash + ", with " + infoSize + " info"; + context.registerNonDigestCase({ + name: testName, + keyName: derivedKeySize, + hash: nonDigestHash, + algorithm: {name: "HKDF", salt: salts[saltSize], hash: nonDigestHash, info: infos[infoSize]} }); - testName += " using " + derivedKeySize + " derivedKey, " + saltSize + " salt, " + nonDigestHash + ", with " + infoSize + " info"; - - subsetTest(promise_test, function(test) { - return subtle.deriveKey(algorithm, baseKeys[derivedKeySize], derivedKeyType.algorithm, true, derivedKeyType.usages) - .then(function(derivation) { - assert_unreached("non-digest algorithm should have thrown an NotSupportedError"); - }, function(err) { - assert_equals(err.name, "NotSupportedError", "derivekey with non-digest algorithm correctly threw NotSupportedError: " + err.message); - }); - }, testName); }); - }); - }); - }); + } }); - - // Deriving bits and keys requires starting with a base key, which is created - // by importing a derivedKey. setUpBaseKeys returns a promise that yields the - // necessary base keys. - function setUpBaseKeys(derivedKeys) { - var promises = []; - - var baseKeys = {}; - var noBits = {}; - var noKey = {}; - var wrongKey = null; - - Object.keys(derivedKeys).forEach(function(derivedKeySize) { - var promise = subtle.importKey("raw", derivedKeys[derivedKeySize], {name: "HKDF"}, false, ["deriveKey", "deriveBits"]) - .then(function(baseKey) { - baseKeys[derivedKeySize] = baseKey; - }, function(err) { - baseKeys[derivedKeySize] = null; - }); - promises.push(promise); - - promise = subtle.importKey("raw", derivedKeys[derivedKeySize], {name: "HKDF"}, false, ["deriveBits"]) - .then(function(baseKey) { - noKey[derivedKeySize] = baseKey; - }, function(err) { - noKey[derivedKeySize] = null; - }); - promises.push(promise); - - promise = subtle.importKey("raw", derivedKeys[derivedKeySize], {name: "HKDF"}, false, ["deriveKey"]) - .then(function(baseKey) { - noBits[derivedKeySize] = baseKey; - }, function(err) { - noBits[derivedKeySize] = null; - }); - promises.push(promise); - }); - - var promise = subtle.generateKey({name: "ECDH", namedCurve: "P-256"}, false, ["deriveKey", "deriveBits"]) - .then(function(baseKey) { - wrongKey = baseKey.privateKey; - }, function(err) { - wrongKey = null; - }); - promises.push(promise); - - - return Promise.all(promises).then(function() { - return {baseKeys: baseKeys, noBits: noBits, noKey: noKey, wrongKey: wrongKey}; - }); - } - } diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/kdf.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/kdf.js new file mode 100644 index 000000000000..ecbb3b4148f4 --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/kdf.js @@ -0,0 +1,209 @@ +function runKdfTests(options) { + var subtle = self.crypto.subtle; + var testData = getTestData(); + var derivedKeyTypes = testData.derivedKeyTypes; + + return setUpBaseKeys(options.getBaseKeyData(testData)) + .then(function(allKeys) { + function derivedKeyTestName(derivedKeyType, caseName) { + var testName = "Derived key of type "; + Object.keys(derivedKeyType.algorithm).forEach(function(prop) { + testName += prop + ": " + derivedKeyType.algorithm[prop] + " "; + }); + return testName + " using " + caseName; + } + + function withHash(algorithm, hash) { + return Object.assign({}, algorithm, {hash: hash}); + } + + function registerCase(testCase, registerAdditionalBitsTests) { + var algorithm = testCase.algorithm; + var baseKey = allKeys.baseKeys[testCase.keyName]; + var badHash = testCase.hash.substring(0, 3) + testCase.hash.substring(4); + + subsetTest(promise_test, function(test) { + return subtle.deriveBits(algorithm, baseKey, 256) + .then(function(derivation) { + assert_true(equalBuffers(derivation, testCase.expected), "Derived correct key"); + }, function(err) { + assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); + }); + }, testCase.name); + + subsetTest(promise_test, function(test) { + return subtle.deriveBits(algorithm, baseKey, 0) + .then(function(derivation) { + assert_equals(derivation.byteLength, 0, "Derived correctly empty key"); + }, function(err) { + assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); + }); + }, testCase.name + " with 0 length"); + + derivedKeyTypes.forEach(function(derivedKeyType) { + var testName = derivedKeyTestName(derivedKeyType, testCase.name); + + subsetTest(promise_test, function(test) { + return subtle.deriveKey(algorithm, baseKey, derivedKeyType.algorithm, true, derivedKeyType.usages) + .then(function(key) { + return subtle.exportKey("raw", key) + .then(function(buffer) { + assert_true(equalBuffers(buffer, testCase.expected.slice(0, derivedKeyType.algorithm.length/8)), "Exported key matches correct value"); + }, function(err) { + assert_unreached("Exporting derived key failed with error " + err.name + ": " + err.message); + }); + }, function(err) { + assert_unreached("deriveKey failed with error " + err.name + ": " + err.message); + }); + }, testName); + + subsetTest(promise_test, function(test) { + return subtle.deriveKey(withHash(algorithm, badHash), baseKey, derivedKeyType.algorithm, true, derivedKeyType.usages) + .then(function(key) { + assert_unreached("bad hash name should have thrown an NotSupportedError"); + }, function(err) { + assert_equals(err.name, "NotSupportedError", "deriveKey with bad hash name correctly threw NotSupportedError: " + err.message); + }); + }, testName + " with bad hash name " + badHash); + + subsetTest(promise_test, function(test) { + return subtle.deriveKey(algorithm, allKeys.noKey[testCase.keyName], derivedKeyType.algorithm, true, derivedKeyType.usages) + .then(function(key) { + assert_unreached("missing deriveKey usage should have thrown an InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "deriveKey with missing deriveKey usage correctly threw InvalidAccessError: " + err.message); + }); + }, testName + " with missing deriveKey usage"); + + subsetTest(promise_test, function(test) { + return subtle.deriveKey(algorithm, allKeys.wrongKey, derivedKeyType.algorithm, true, derivedKeyType.usages) + .then(function(key) { + assert_unreached("wrong (ECDH) key should have thrown an InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "deriveKey with wrong (ECDH) key correctly threw InvalidAccessError: " + err.message); + }); + }, testName + " with wrong (ECDH) key"); + }); + + if (registerAdditionalBitsTests !== undefined) { + registerAdditionalBitsTests(); + } + + subsetTest(promise_test, function(test) { + return subtle.deriveBits(algorithm, baseKey, 44) + .then(function(derivation) { + assert_unreached("non-multiple of 8 length should have thrown an OperationError"); + }, function(err) { + assert_equals(err.name, "OperationError", "deriveBits with non-multiple of 8 length correctly threw OperationError: " + err.message); + }); + }, testCase.name + " with non-multiple of 8 length"); + + subsetTest(promise_test, function(test) { + return subtle.deriveBits(withHash(algorithm, badHash), baseKey, 256) + .then(function(derivation) { + assert_unreached("bad hash name should have thrown an NotSupportedError"); + }, function(err) { + assert_equals(err.name, "NotSupportedError", "deriveBits with bad hash name correctly threw NotSupportedError: " + err.message); + }); + }, testCase.name + " with bad hash name " + badHash); + + subsetTest(promise_test, function(test) { + return subtle.deriveBits(algorithm, allKeys.noBits[testCase.keyName], 256) + .then(function(derivation) { + assert_unreached("missing deriveBits usage should have thrown an InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "deriveBits with missing deriveBits usage correctly threw InvalidAccessError: " + err.message); + }); + }, testCase.name + " with missing deriveBits usage"); + + subsetTest(promise_test, function(test) { + return subtle.deriveBits(algorithm, allKeys.wrongKey, 256) + .then(function(derivation) { + assert_unreached("wrong (ECDH) key should have thrown an InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "deriveBits with wrong (ECDH) key correctly threw InvalidAccessError: " + err.message); + }); + }, testCase.name + " with wrong (ECDH) key"); + } + + function registerNonDigestCase(testCase) { + var baseKey = allKeys.baseKeys[testCase.keyName]; + + subsetTest(promise_test, function(test) { + return subtle.deriveBits(testCase.algorithm, baseKey, 256) + .then(function(derivation) { + assert_unreached("non-digest algorithm should have thrown an NotSupportedError"); + }, function(err) { + assert_equals(err.name, "NotSupportedError", "deriveBits with non-digest algorithm correctly threw NotSupportedError: " + err.message); + }); + }, testCase.name + " with non-digest algorithm " + testCase.hash); + + derivedKeyTypes.forEach(function(derivedKeyType) { + subsetTest(promise_test, function(test) { + return subtle.deriveKey(testCase.algorithm, baseKey, derivedKeyType.algorithm, true, derivedKeyType.usages) + .then(function(derivation) { + assert_unreached("non-digest algorithm should have thrown an NotSupportedError"); + }, function(err) { + assert_equals(err.name, "NotSupportedError", "derivekey with non-digest algorithm correctly threw NotSupportedError: " + err.message); + }); + }, derivedKeyTestName(derivedKeyType, testCase.name)); + }); + } + + options.registerTests({ + subtle: subtle, + testData: testData, + derivedKeyTypes: derivedKeyTypes, + keys: allKeys, + registerCase: registerCase, + registerNonDigestCase: registerNonDigestCase, + derivedKeyTestName: derivedKeyTestName + }); + }); + + function setUpBaseKeys(baseKeyData) { + var promises = []; + var baseKeys = {}; + var noBits = {}; + var noKey = {}; + var wrongKey = null; + + Object.keys(baseKeyData).forEach(function(keyName) { + var promise = subtle.importKey("raw", baseKeyData[keyName], {name: options.name}, false, ["deriveKey", "deriveBits"]) + .then(function(baseKey) { + baseKeys[keyName] = baseKey; + }, function(err) { + baseKeys[keyName] = null; + }); + promises.push(promise); + + promise = subtle.importKey("raw", baseKeyData[keyName], {name: options.name}, false, ["deriveBits"]) + .then(function(baseKey) { + noKey[keyName] = baseKey; + }, function(err) { + noKey[keyName] = null; + }); + promises.push(promise); + + promise = subtle.importKey("raw", baseKeyData[keyName], {name: options.name}, false, ["deriveKey"]) + .then(function(baseKey) { + noBits[keyName] = baseKey; + }, function(err) { + noBits[keyName] = null; + }); + promises.push(promise); + }); + + var promise = subtle.generateKey({name: "ECDH", namedCurve: "P-256"}, false, ["deriveKey", "deriveBits"]) + .then(function(baseKey) { + wrongKey = baseKey.privateKey; + }, function(err) { + wrongKey = null; + }); + promises.push(promise); + + return Promise.all(promises).then(function() { + return {baseKeys: baseKeys, noBits: noBits, noKey: noKey, wrongKey: wrongKey}; + }); + } +} diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.https.any.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.https.any.js index cc2ed9b9cef8..8d1299358575 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.https.any.js @@ -12,6 +12,7 @@ // META: script=../util/helpers.js // META: script=/common/subset-tests.js // META: script=pbkdf2_vectors.js +// META: script=kdf.js // META: script=pbkdf2.js // Define subtests from a `promise_test` to ensure the harness does not diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.js index 4d5b0137a387..57c19ae3f014 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.js @@ -1,274 +1,64 @@ function define_tests() { - // May want to test prefixed implementations. - var subtle = self.crypto.subtle; - - // pbkdf2_vectors sets up test data with the correct derivations for each - // test case. - var testData = getTestData(); - var passwords = testData.passwords; - var salts = testData.salts; - var derivations = testData.derivations; - - // What kinds of keys can be created with deriveKey? The following: - var derivedKeyTypes = testData.derivedKeyTypes; - - return setUpBaseKeys(passwords) - .then(function(allKeys) { - // We get several kinds of base keys. Normal ones that can be used for - // derivation operations, ones that lack the deriveBits usage, ones - // that lack the deriveKeys usage, and one key that is for the wrong - // algorithm (not PBKDF2 in this case). - var baseKeys = allKeys.baseKeys; - var noBits = allKeys.noBits; - var noKey = allKeys.noKey; - var wrongKey = allKeys.wrongKey; - - // Test each combination of password size, salt size, hash function, - // and number of iterations. The derivations object is structured in - // that way, so navigate it to run tests and compare with correct results. - Object.keys(derivations).forEach(function(passwordSize) { - Object.keys(derivations[passwordSize]).forEach(function(saltSize) { - Object.keys(derivations[passwordSize][saltSize]).forEach(function(hashName) { - Object.keys(derivations[passwordSize][saltSize][hashName]).forEach(function(iterations) { - var testName = passwordSize + " password, " + saltSize + " salt, " + hashName + ", with " + iterations + " iterations"; - - // Check for correct deriveBits result - subsetTest(promise_test, function(test) { - return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, baseKeys[passwordSize], 256) - .then(function(derivation) { - assert_true(equalBuffers(derivation, derivations[passwordSize][saltSize][hashName][iterations]), "Derived correct key"); - }, function(err) { - assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); + return runKdfTests({ + name: "PBKDF2", + getBaseKeyData: function(testData) { + return testData.passwords; + }, + registerTests: function(context) { + var subtle = context.subtle; + var testData = context.testData; + var derivations = testData.derivations; + var salts = testData.salts; + + Object.keys(derivations).forEach(function(passwordSize) { + Object.keys(derivations[passwordSize]).forEach(function(saltSize) { + Object.keys(derivations[passwordSize][saltSize]).forEach(function(hashName) { + Object.keys(derivations[passwordSize][saltSize][hashName]).forEach(function(iterations) { + var testName = passwordSize + " password, " + saltSize + " salt, " + hashName + ", with " + iterations + " iterations"; + context.registerCase({ + name: testName, + keyName: passwordSize, + hash: hashName, + algorithm: {name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, + expected: derivations[passwordSize][saltSize][hashName][iterations] }); - }, testName); + }); - // 0 length + var zeroIterationName = passwordSize + " password, " + saltSize + " salt, " + hashName + ", with 0 iterations"; + var zeroIterationAlgorithm = {name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: 0}; subsetTest(promise_test, function(test) { - return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, baseKeys[passwordSize], 0) + return subtle.deriveBits(zeroIterationAlgorithm, context.keys.baseKeys[passwordSize], 256) .then(function(derivation) { - assert_true(equalBuffers(derivation.byteLength, 0, "Derived correctly empty key")); + assert_unreached("0 iterations should have thrown an error"); }, function(err) { - assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); + assert_equals(err.name, "OperationError", "deriveBits with 0 iterations correctly threw OperationError: " + err.message); }); - }, testName + " with 0 length"); + }, zeroIterationName); - // Check for correct deriveKey results for every kind of - // key that can be created by the deriveKeys operation. - derivedKeyTypes.forEach(function(derivedKeyType) { - var testName = "Derived key of type "; - Object.keys(derivedKeyType.algorithm).forEach(function(prop) { - testName += prop + ": " + derivedKeyType.algorithm[prop] + " "; - }); - testName += " using " + passwordSize + " password, " + saltSize + " salt, " + hashName + ", with " + iterations + " iterations"; - - // Test the particular key derivation. - subsetTest(promise_test, function(test) { - return subtle.deriveKey({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, baseKeys[passwordSize], derivedKeyType.algorithm, true, derivedKeyType.usages) - .then(function(key) { - // Need to export the key to see that the correct bits were set. - return subtle.exportKey("raw", key) - .then(function(buffer) { - assert_true(equalBuffers(buffer, derivations[passwordSize][saltSize][hashName][iterations].slice(0, derivedKeyType.algorithm.length/8)), "Exported key matches correct value"); - }, function(err) { - assert_unreached("Exporting derived key failed with error " + err.name + ": " + err.message); - }); - }, function(err) { - assert_unreached("deriveKey failed with error " + err.name + ": " + err.message); - - }); - }, testName); - - // Test various error conditions for deriveKey: - - // - illegal name for hash algorithm (NotSupportedError) - var badHash = hashName.substring(0, 3) + hashName.substring(4); + context.derivedKeyTypes.forEach(function(derivedKeyType) { subsetTest(promise_test, function(test) { - return subtle.deriveKey({name: "PBKDF2", salt: salts[saltSize], hash: badHash, iterations: parseInt(iterations)}, baseKeys[passwordSize], derivedKeyType.algorithm, true, derivedKeyType.usages) - .then(function(key) { - assert_unreached("bad hash name should have thrown an NotSupportedError"); + return subtle.deriveKey(zeroIterationAlgorithm, context.keys.baseKeys[passwordSize], derivedKeyType.algorithm, true, derivedKeyType.usages) + .then(function(derivation) { + assert_unreached("0 iterations should have thrown an error"); }, function(err) { - assert_equals(err.name, "NotSupportedError", "deriveKey with bad hash name correctly threw NotSupportedError: " + err.message); + assert_equals(err.name, "OperationError", "derivekey with 0 iterations correctly threw OperationError: " + err.message); }); - }, testName + " with bad hash name " + badHash); - - // - baseKey usages missing "deriveKey" (InvalidAccessError) - subsetTest(promise_test, function(test) { - return subtle.deriveKey({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, noKey[passwordSize], derivedKeyType.algorithm, true, derivedKeyType.usages) - .then(function(key) { - assert_unreached("missing deriveKey usage should have thrown an InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "deriveKey with missing deriveKey usage correctly threw InvalidAccessError: " + err.message); - }); - }, testName + " with missing deriveKey usage"); - - // - baseKey algorithm does not match PBKDF2 (InvalidAccessError) - subsetTest(promise_test, function(test) { - return subtle.deriveKey({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, wrongKey, derivedKeyType.algorithm, true, derivedKeyType.usages) - .then(function(key) { - assert_unreached("wrong (ECDH) key should have thrown an InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "deriveKey with wrong (ECDH) key correctly threw InvalidAccessError: " + err.message); - }); - }, testName + " with wrong (ECDH) key"); - + }, context.derivedKeyTestName(derivedKeyType, zeroIterationName)); }); - - // length not multiple of 8 (OperationError) - subsetTest(promise_test, function(test) { - return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, baseKeys[passwordSize], 44) - .then(function(derivation) { - assert_unreached("non-multiple of 8 length should have thrown an OperationError"); - }, function(err) { - assert_equals(err.name, "OperationError", "deriveBits with non-multiple of 8 length correctly threw OperationError: " + err.message); - }); - }, testName + " with non-multiple of 8 length"); - - // - illegal name for hash algorithm (NotSupportedError) - var badHash = hashName.substring(0, 3) + hashName.substring(4); - subsetTest(promise_test, function(test) { - return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: badHash, iterations: parseInt(iterations)}, baseKeys[passwordSize], 256) - .then(function(derivation) { - assert_unreached("bad hash name should have thrown an NotSupportedError"); - }, function(err) { - assert_equals(err.name, "NotSupportedError", "deriveBits with bad hash name correctly threw NotSupportedError: " + err.message); - }); - }, testName + " with bad hash name " + badHash); - - // - baseKey usages missing "deriveBits" (InvalidAccessError) - subsetTest(promise_test, function(test) { - return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, noBits[passwordSize], 256) - .then(function(derivation) { - assert_unreached("missing deriveBits usage should have thrown an InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "deriveBits with missing deriveBits usage correctly threw InvalidAccessError: " + err.message); - }); - }, testName + " with missing deriveBits usage"); - - // - baseKey algorithm does not match PBKDF2 (InvalidAccessError) - subsetTest(promise_test, function(test) { - return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, wrongKey, 256) - .then(function(derivation) { - assert_unreached("wrong (ECDH) key should have thrown an InvalidAccessError"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "deriveBits with wrong (ECDH) key correctly threw InvalidAccessError: " + err.message); - }); - }, testName + " with wrong (ECDH) key"); - }); - - // Check that 0 iterations throws proper error - subsetTest(promise_test, function(test) { - return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: 0}, baseKeys[passwordSize], 256) - .then(function(derivation) { - assert_unreached("0 iterations should have thrown an error"); - }, function(err) { - assert_equals(err.name, "OperationError", "deriveBits with 0 iterations correctly threw OperationError: " + err.message); - }); - }, passwordSize + " password, " + saltSize + " salt, " + hashName + ", with 0 iterations"); - - derivedKeyTypes.forEach(function(derivedKeyType) { - var testName = "Derived key of type "; - Object.keys(derivedKeyType.algorithm).forEach(function(prop) { - testName += prop + ": " + derivedKeyType.algorithm[prop] + " "; - }); - testName += " using " + passwordSize + " password, " + saltSize + " salt, " + hashName + ", with 0 iterations"; - - subsetTest(promise_test, function(test) { - return subtle.deriveKey({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: 0}, baseKeys[passwordSize], derivedKeyType.algorithm, true, derivedKeyType.usages) - .then(function(derivation) { - assert_unreached("0 iterations should have thrown an error"); - }, function(err) { - assert_equals(err.name, "OperationError", "derivekey with 0 iterations correctly threw OperationError: " + err.message); - }); - }, testName); }); - }); - - // - legal algorithm name but not digest one (e.g., PBKDF2) (NotSupportedError) - var nonDigestHash = "PBKDF2"; - [1, 1000, 100000].forEach(function(iterations) { - var testName = passwordSize + " password, " + saltSize + " salt, " + nonDigestHash + ", with " + iterations + " iterations"; - - subsetTest(promise_test, function(test) { - return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: nonDigestHash, iterations: parseInt(iterations)}, baseKeys[passwordSize], 256) - .then(function(derivation) { - assert_unreached("non-digest algorithm should have thrown an NotSupportedError"); - }, function(err) { - assert_equals(err.name, "NotSupportedError", "deriveBits with non-digest algorithm correctly threw NotSupportedError: " + err.message); - }); - }, testName + " with non-digest algorithm " + nonDigestHash); - derivedKeyTypes.forEach(function(derivedKeyType) { - var testName = "Derived key of type "; - Object.keys(derivedKeyType.algorithm).forEach(function(prop) { - testName += prop + ": " + derivedKeyType.algorithm[prop] + " "; + var nonDigestHash = "PBKDF2"; + [1, 1000, 100000].forEach(function(iterations) { + var testName = passwordSize + " password, " + saltSize + " salt, " + nonDigestHash + ", with " + iterations + " iterations"; + context.registerNonDigestCase({ + name: testName, + keyName: passwordSize, + hash: nonDigestHash, + algorithm: {name: "PBKDF2", salt: salts[saltSize], hash: nonDigestHash, iterations: parseInt(iterations)} }); - testName += " using " + passwordSize + " password, " + saltSize + " salt, " + nonDigestHash + ", with " + iterations + " iterations"; - - subsetTest(promise_test, function(test) { - return subtle.deriveKey({name: "PBKDF2", salt: salts[saltSize], hash: nonDigestHash, iterations: parseInt(iterations)}, baseKeys[passwordSize], derivedKeyType.algorithm, true, derivedKeyType.usages) - .then(function(derivation) { - assert_unreached("non-digest algorithm should have thrown an NotSupportedError"); - }, function(err) { - assert_equals(err.name, "NotSupportedError", "derivekey with non-digest algorithm correctly threw NotSupportedError: " + err.message); - }); - }, testName); }); - }); - }); - }); + } }); - - // Deriving bits and keys requires starting with a base key, which is created - // by importing a password. setUpBaseKeys returns a promise that yields the - // necessary base keys. - function setUpBaseKeys(passwords) { - var promises = []; - - var baseKeys = {}; - var noBits = {}; - var noKey = {}; - var wrongKey = null; - - Object.keys(passwords).forEach(function(passwordSize) { - var promise = subtle.importKey("raw", passwords[passwordSize], {name: "PBKDF2"}, false, ["deriveKey", "deriveBits"]) - .then(function(baseKey) { - baseKeys[passwordSize] = baseKey; - }, function(err) { - baseKeys[passwordSize] = null; - }); - promises.push(promise); - - promise = subtle.importKey("raw", passwords[passwordSize], {name: "PBKDF2"}, false, ["deriveBits"]) - .then(function(baseKey) { - noKey[passwordSize] = baseKey; - }, function(err) { - noKey[passwordSize] = null; - }); - promises.push(promise); - - promise = subtle.importKey("raw", passwords[passwordSize], {name: "PBKDF2"}, false, ["deriveKey"]) - .then(function(baseKey) { - noBits[passwordSize] = baseKey; - }, function(err) { - noBits[passwordSize] = null; - }); - promises.push(promise); - }); - - var promise = subtle.generateKey({name: "ECDH", namedCurve: "P-256"}, false, ["deriveKey", "deriveBits"]) - .then(function(baseKey) { - wrongKey = baseKey.privateKey; - }, function(err) { - wrongKey = null; - }); - promises.push(promise); - - - return Promise.all(promises).then(function() { - return {baseKeys: baseKeys, noBits: noBits, noKey: noKey, wrongKey: wrongKey}; - }); - } - } diff --git a/test/fixtures/wpt/WebCryptoAPI/digest/cshake.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/digest/cshake.tentative.https.any.js index 81793666294c..1bf78f581154 100644 --- a/test/fixtures/wpt/WebCryptoAPI/digest/cshake.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/digest/cshake.tentative.https.any.js @@ -1,23 +1,12 @@ // META: title=WebCryptoAPI: digest() cSHAKE algorithms // META: script=../util/helpers.js +// META: script=digest_test_data.js +// META: script=digest.js // META: timeout=long var subtle = crypto.subtle; // Change to test prefixed implementations -var sourceData = { - empty: new Uint8Array(0), - short: new Uint8Array([ - 21, 110, 234, 124, 193, 76, 86, 203, 148, 219, 3, 10, 74, 157, 149, 255, - ]), - medium: new Uint8Array([ - 182, 200, 249, 223, 100, 140, 208, 136, 183, 15, 56, 231, 65, 151, 177, 140, - 184, 30, 30, 67, 80, 213, 11, 204, 184, 251, 90, 115, 121, 200, 123, 178, - 227, 214, 237, 84, 97, 237, 30, 159, 54, 243, 64, 163, 150, 42, 68, 107, - 129, 91, 121, 75, 75, 212, 58, 68, 3, 80, 32, 119, 178, 37, 108, 200, 7, - 131, 127, 58, 172, 209, 24, 235, 75, 156, 43, 174, 184, 151, 6, 134, 37, - 171, 172, 161, 147, - ]), -}; +var sourceData = getDigestSourceData(false); // Test different output lengths for cSHAKE var digestLengths = [0, 256, 384, 512]; @@ -158,91 +147,19 @@ var digestedData = { }; // Test cSHAKE digest algorithms with variable output lengths -Object.keys(digestedData).forEach(function (alg) { - digestLengths.forEach(function (length) { - Object.keys(sourceData).forEach(function (size) { - promise_test(function (test) { - return crypto.subtle - .digest({ name: alg, outputLength: length }, sourceData[size]) - .then(function (result) { - assert_true( - equalBuffers(result, digestedData[alg][length][size]), - 'digest matches expected' - ); - }); - }, alg + ' with ' + length + ' bit output and ' + size + ' source data'); - - if (sourceData[size].length > 0) { - promise_test(function (test) { - var buffer = new Uint8Array(sourceData[size]); - // Alter the buffer before calling digest - buffer[0] = ~buffer[0]; - return crypto.subtle - .digest({ - get name() { - // Alter the buffer back while calling digest - buffer[0] = sourceData[size][0]; - return alg; - }, - outputLength: length - }, buffer) - .then(function (result) { - assert_true( - equalBuffers(result, digestedData[alg][length][size]), - 'digest matches expected' - ); - }); - }, alg + ' with ' + length + ' bit output and ' + size + ' source data and altered buffer during call'); - - promise_test(function (test) { - var buffer = new Uint8Array(sourceData[size]); - var promise = crypto.subtle - .digest({ name: alg, outputLength: length }, buffer) - .then(function (result) { - assert_true( - equalBuffers(result, digestedData[alg][length][size]), - 'digest matches expected' - ); - }); - // Alter the buffer after calling digest - buffer[0] = ~buffer[0]; - return promise; - }, alg + ' with ' + length + ' bit output and ' + size + ' source data and altered buffer after call'); - - promise_test(function (test) { - var buffer = new Uint8Array(sourceData[size]); - return crypto.subtle - .digest({ - get name() { - // Transfer the buffer while calling digest - buffer.buffer.transfer(); - return alg; - }, - outputLength: length - }, buffer) - .then(function (result) { - assert_true( - equalBuffers(result, digestedData[alg][length].empty), - 'digest on transferred buffer should match result for empty buffer' - ); - }); - }, alg + ' with ' + length + ' bit output and ' + size + ' source data and transferred buffer during call'); - - promise_test(function (test) { - var buffer = new Uint8Array(sourceData[size]); - var promise = crypto.subtle - .digest({ name: alg, outputLength: length }, buffer) - .then(function (result) { - assert_true( - equalBuffers(result, digestedData[alg][length][size]), - 'digest matches expected' - ); - }); - // Transfer the buffer after calling digest - buffer.buffer.transfer(); - return promise; - }, alg + ' with ' + length + ' bit output and ' + size + ' source data and transferred buffer after call'); - } +runDigestTests(subtle, sourceData, function (size) { + var vectors = []; + Object.keys(digestedData).forEach(function (alg) { + digestLengths.forEach(function (length) { + vectors.push({ + algorithm: {name: alg, outputLength: length}, + expected: digestedData[alg][length][size], + emptyExpected: digestedData[alg][length].empty, + label: alg + ' with ' + length + ' bit output and ' + + size + ' source data', + mutations: true, + }); }); }); + return vectors; }); diff --git a/test/fixtures/wpt/WebCryptoAPI/digest/digest.https.any.js b/test/fixtures/wpt/WebCryptoAPI/digest/digest.https.any.js index 38ce85ec06cf..26711b2880d9 100644 --- a/test/fixtures/wpt/WebCryptoAPI/digest/digest.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/digest/digest.https.any.js @@ -1,19 +1,12 @@ // META: title=WebCryptoAPI: digest() // META: script=../util/helpers.js +// META: script=digest_test_data.js +// META: script=digest.js // META: timeout=long var subtle = crypto.subtle; // Change to test prefixed implementations - var sourceData = { - empty: new Uint8Array(0), - short: new Uint8Array([21, 110, 234, 124, 193, 76, 86, 203, 148, 219, 3, 10, 74, 157, 149, 255]), - medium: new Uint8Array([182, 200, 249, 223, 100, 140, 208, 136, 183, 15, 56, 231, 65, 151, 177, 140, 184, 30, 30, 67, 80, 213, 11, 204, 184, 251, 90, 115, 121, 200, 123, 178, 227, 214, 237, 84, 97, 237, 30, 159, 54, 243, 64, 163, 150, 42, 68, 107, 129, 91, 121, 75, 75, 212, 58, 68, 3, 80, 32, 119, 178, 37, 108, 200, 7, 131, 127, 58, 172, 209, 24, 235, 75, 156, 43, 174, 184, 151, 6, 134, 37, 171, 172, 161, 147]) - }; - - sourceData.long = new Uint8Array(1024 * sourceData.medium.byteLength); - for (var i=0; i<1024; i++) { - sourceData.long.set(sourceData.medium, i * sourceData.medium.byteLength); - } + var sourceData = getDigestSourceData(true); var digestedData = { "sha-1": { @@ -43,105 +36,36 @@ } // Try every combination of hash with source data size. Variations tested are - // hash name in upper, lower, or mixed case, and upper-case version with the - // source buffer altered after call. - Object.keys(sourceData).forEach(function(size) { - Object.keys(digestedData).forEach(function(alg) { + // hash name in upper, lower, or mixed case, plus buffer mutation and transfer. + runDigestTests(subtle, sourceData, function (size) { + var vectors = []; + Object.keys(digestedData).forEach(function (alg) { var upCase = alg.toUpperCase(); var downCase = alg.toLowerCase(); - var mixedCase = upCase.substr(0, 1) + downCase.substr(1); - - promise_test(function(test) { - var promise = subtle.digest({name: upCase}, sourceData[size]) - .then(function(result) { - assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size); - }, function(err) { - assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message); - }); - - return promise; - }, upCase + " with " + size + " source data"); - - promise_test(function(test) { - var promise = subtle.digest({name: downCase}, sourceData[size]) - .then(function(result) { - assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size); - }, function(err) { - assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message); - }); - - return promise; - }, downCase + " with " + size + " source data"); - - promise_test(function(test) { - var promise = subtle.digest({name: mixedCase}, sourceData[size]) - .then(function(result) { - assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size); - }, function(err) { - assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message); - }); - - return promise; - }, mixedCase + " with " + size + " source data"); - - if (sourceData[size].length > 0) { - promise_test(function(test) { - var copiedBuffer = copyBuffer(sourceData[size]); - copiedBuffer[0] = 255 - copiedBuffer[0]; - var promise = subtle.digest({ - get name() { - copiedBuffer[0] = sourceData[size][0]; - return upCase; - } - }, copiedBuffer) - .then(function(result) { - assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size); - }, function(err) { - assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message); - }); - return promise; - }, upCase + " with " + size + " source data and altered buffer during call"); - - promise_test(function(test) { - var copiedBuffer = copyBuffer(sourceData[size]); - var promise = subtle.digest({name: upCase}, copiedBuffer) - .then(function(result) { - assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size); - }, function(err) { - assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message); - }); - - copiedBuffer[0] = 255 - copiedBuffer[0]; - return promise; - }, upCase + " with " + size + " source data and altered buffer after call"); - - promise_test(function(test) { - var copiedBuffer = copyBuffer(sourceData[size]); - copiedBuffer.buffer.transfer(); - return subtle.digest({name: upCase}, copiedBuffer) - .then(function(result) { - assert_true(equalBuffers(result, digestedData[alg].empty), "digest() on transferred buffer should yield result for empty buffer for " + alg + ":" + size); - }, function(err) { - assert_unreached("digest() threw an error for transferred buffer for " + alg + ":" + size + ": " + err.message); - }); - }, upCase + " with " + size + " source data and transferred buffer during call"); - - promise_test(function(test) { - var copiedBuffer = copyBuffer(sourceData[size]); - var promise = subtle.digest({name: upCase}, copiedBuffer) - .then(function(result) { - assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size); - }, function(err) { - assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message); - }); - - copiedBuffer.buffer.transfer(); - return promise; - }, upCase + " with " + size + " source data and transferred buffer after call"); - } + var mixedCase = upCase.slice(0, 1) + downCase.slice(1); + var expected = digestedData[alg][size]; + + vectors.push({ + algorithm: {name: upCase}, + expected: expected, + emptyExpected: digestedData[alg].empty, + label: upCase + " with " + size + " source data", + mutations: true, + transferBeforeCall: true, + }); + vectors.push({ + algorithm: {name: downCase}, + expected: expected, + label: downCase + " with " + size + " source data", + }); + vectors.push({ + algorithm: {name: mixedCase}, + expected: expected, + label: mixedCase + " with " + size + " source data", + }); }); + return vectors; }); - // Call digest() with bad algorithm names to get an error var badNames = ["AES-GCM", "RSA-OAEP", "PBKDF2", "AES-KW"]; Object.keys(sourceData).forEach(function(size) { diff --git a/test/fixtures/wpt/WebCryptoAPI/digest/digest.js b/test/fixtures/wpt/WebCryptoAPI/digest/digest.js new file mode 100644 index 000000000000..9ef9c69a180b --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/digest/digest.js @@ -0,0 +1,92 @@ +function runDigestTests(subtle, sourceData, getVectors) { + function algorithmName(algorithm) { + return typeof algorithm === 'string' ? algorithm : algorithm.name; + } + + function withNameGetter(algorithm, getter) { + var result = typeof algorithm === 'string' ? {} : { ...algorithm }; + Object.defineProperty(result, 'name', { + enumerable: true, + get: getter, + }); + return result; + } + + Object.keys(sourceData).forEach(function (size) { + getVectors(size).forEach(function (vector) { + promise_test(function () { + return subtle.digest(vector.algorithm, sourceData[size]) + .then(function (result) { + assert_true( + equalBuffers(result, vector.expected), + 'digest matches expected' + ); + }); + }, vector.label); + + if (!vector.mutations || sourceData[size].length === 0) { + return; + } + + promise_test(function () { + var buffer = new Uint8Array(sourceData[size]); + buffer[0] = ~buffer[0]; + var algorithm = withNameGetter(vector.algorithm, function () { + buffer[0] = sourceData[size][0]; + return algorithmName(vector.algorithm); + }); + return subtle.digest(algorithm, buffer).then(function (result) { + assert_true( + equalBuffers(result, vector.expected), + 'digest matches expected' + ); + }); + }, vector.label + ' and altered buffer during call'); + + promise_test(function () { + var buffer = new Uint8Array(sourceData[size]); + var promise = subtle.digest(vector.algorithm, buffer) + .then(function (result) { + assert_true( + equalBuffers(result, vector.expected), + 'digest matches expected' + ); + }); + buffer[0] = ~buffer[0]; + return promise; + }, vector.label + ' and altered buffer after call'); + + promise_test(function () { + var buffer = new Uint8Array(sourceData[size]); + var algorithm = vector.transferBeforeCall + ? vector.algorithm + : withNameGetter(vector.algorithm, function () { + buffer.buffer.transfer(); + return algorithmName(vector.algorithm); + }); + if (vector.transferBeforeCall) { + buffer.buffer.transfer(); + } + return subtle.digest(algorithm, buffer).then(function (result) { + assert_true( + equalBuffers(result, vector.emptyExpected), + 'digest on transferred buffer should match result for empty buffer' + ); + }); + }, vector.label + ' and transferred buffer during call'); + + promise_test(function () { + var buffer = new Uint8Array(sourceData[size]); + var promise = subtle.digest(vector.algorithm, buffer) + .then(function (result) { + assert_true( + equalBuffers(result, vector.expected), + 'digest matches expected' + ); + }); + buffer.buffer.transfer(); + return promise; + }, vector.label + ' and transferred buffer after call'); + }); + }); +} diff --git a/test/fixtures/wpt/WebCryptoAPI/digest/digest_test_data.js b/test/fixtures/wpt/WebCryptoAPI/digest/digest_test_data.js new file mode 100644 index 000000000000..f088e02a0870 --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/digest/digest_test_data.js @@ -0,0 +1,25 @@ +function getDigestSourceData(includeLong) { + var sourceData = { + empty: new Uint8Array(0), + short: new Uint8Array([ + 21, 110, 234, 124, 193, 76, 86, 203, 148, 219, 3, 10, 74, 157, 149, 255, + ]), + medium: new Uint8Array([ + 182, 200, 249, 223, 100, 140, 208, 136, 183, 15, 56, 231, 65, 151, 177, + 140, 184, 30, 30, 67, 80, 213, 11, 204, 184, 251, 90, 115, 121, 200, 123, + 178, 227, 214, 237, 84, 97, 237, 30, 159, 54, 243, 64, 163, 150, 42, 68, + 107, 129, 91, 121, 75, 75, 212, 58, 68, 3, 80, 32, 119, 178, 37, 108, + 200, 7, 131, 127, 58, 172, 209, 24, 235, 75, 156, 43, 174, 184, 151, 6, + 134, 37, 171, 172, 161, 147, + ]), + }; + + if (includeLong) { + sourceData.long = new Uint8Array(1024 * sourceData.medium.byteLength); + for (var i = 0; i < 1024; i++) { + sourceData.long.set(sourceData.medium, i * sourceData.medium.byteLength); + } + } + + return sourceData; +} diff --git a/test/fixtures/wpt/WebCryptoAPI/digest/kangarootwelve.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/digest/kangarootwelve.tentative.https.any.js index 9f800b793787..0e38eb0542ad 100644 --- a/test/fixtures/wpt/WebCryptoAPI/digest/kangarootwelve.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/digest/kangarootwelve.tentative.https.any.js @@ -1,24 +1,10 @@ // META: title=WebCryptoAPI: digest() KangarooTwelve algorithms // META: script=../util/helpers.js +// META: script=xof_digest.js // META: timeout=long var subtle = crypto.subtle; // Change to test prefixed implementations -// Generates a Uint8Array of length n by repeating the pattern 00 01 02 .. F9 FA. -function ptn(n) { - var buf = new Uint8Array(n); - for (var i = 0; i < n; i++) - buf[i] = i % 251; - return buf; -} - -function hexToBytes(hex) { - var bytes = new Uint8Array(hex.length / 2); - for (var i = 0; i < hex.length; i += 2) - bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16); - return bytes; -} - // RFC 9861 Section 5 test vectors // [input, outputLengthBits, expected hex(, customization)] var kt128Vectors = [ @@ -182,143 +168,21 @@ var largeOutputTests = [ '2752f3ccd855288efee5fcbb8b563069'], ]; -largeOutputTests.forEach(function (entry) { - var alg = entry[0]; - var outputLength = entry[1]; - var lastN = entry[2]; - var expected = entry[3]; - - promise_test(function (test) { - return subtle - .digest({ name: alg, outputLength: outputLength }, new Uint8Array(0)) - .then(function (result) { - var full = new Uint8Array(result); - var last = full.slice(full.length - lastN); - assert_true( - equalBuffers(last.buffer, hexToBytes(expected)), - 'last ' + lastN + ' bytes of digest match expected' - ); - }); - }, alg + ' with ' + outputLength + ' bit output, verify last ' + lastN + ' bytes'); -}); - -function customizationEqual(emptyDataVector, customization) { - return equalBuffers(customization ?? new Uint8Array(0), emptyDataVector[3] ?? new Uint8Array(0)); -} - -function outputLengthLessOrEqual(emptyDataVector, outputLength) { - return outputLength <= emptyDataVector[1]; -} - -var allVectors = { - KT128: kt128Vectors, - KT256: kt256Vectors, -}; - -Object.keys(allVectors).forEach(function (alg) { - var emptyDataVector = allVectors[alg][0]; - allVectors[alg].forEach(function (vector, i) { - var input = vector[0]; - var outputLength = vector[1]; - var expected = vector[2]; - var customization = vector[3]; - - var algorithmParams = { name: alg, outputLength: outputLength }; - if (customization !== undefined) - algorithmParams.customization = customization; - - var label = alg + ' vector #' + (i + 1) + - ' (' + outputLength + ' bit output, ' + input.length + ' byte input' + - (customization !== undefined ? ', C=' + customization.length + ' bytes' : '') + ')'; - - promise_test(function (test) { - return subtle - .digest(algorithmParams, input) - .then(function (result) { - assert_true( - equalBuffers(result, hexToBytes(expected)), - 'digest matches expected' - ); - }); - }, label); - - if (input.length > 0) { - promise_test(function (test) { - var buffer = new Uint8Array(input); - // Alter the buffer before calling digest - buffer[0] = ~buffer[0]; - return subtle - .digest({ - get name() { - // Alter the buffer back while calling digest - buffer[0] = input[0]; - return alg; - }, - outputLength: outputLength, - customization: customization, - }, buffer) - .then(function (result) { - assert_true( - equalBuffers(result, hexToBytes(expected)), - 'digest matches expected' - ); - }); - }, label + ' and altered buffer during call'); - - promise_test(function (test) { - var buffer = new Uint8Array(input); - var promise = subtle - .digest(algorithmParams, buffer) - .then(function (result) { - assert_true( - equalBuffers(result, hexToBytes(expected)), - 'digest matches expected' - ); - }); - // Alter the buffer after calling digest - buffer[0] = ~buffer[0]; - return promise; - }, label + ' and altered buffer after call'); - - promise_test(function (test) { - var buffer = new Uint8Array(input); - return subtle - .digest({ - get name() { - // Transfer the buffer while calling digest - buffer.buffer.transfer(); - return alg; - }, - outputLength: outputLength, - customization: customization, - }, buffer) - .then(function (result) { - if (customizationEqual(emptyDataVector, customization) && outputLengthLessOrEqual(emptyDataVector, outputLength)) { - assert_true( - equalBuffers(result, Uint8Array.fromHex(emptyDataVector[2]).subarray(0, outputLength / 8)), - 'digest on transferred buffer should match result for empty buffer' - ); - } else { - assert_equals(result.byteLength, outputLength / 8, - 'digest on transferred buffer should have correct output length'); - } - }); - }, label + ' and transferred buffer during call'); - - promise_test(function (test) { - var buffer = new Uint8Array(input); - var promise = subtle - .digest(algorithmParams, buffer) - .then(function (result) { - assert_true( - equalBuffers(result, hexToBytes(expected)), - 'digest matches expected' - ); - }); - // Transfer the buffer after calling digest - buffer.buffer.transfer(); - return promise; - }, label + ' and transferred buffer after call'); - } - }); +runXofDigestTests(subtle, { + vectors: { + KT128: kt128Vectors, + KT256: kt256Vectors, + }, + largeOutputTests: largeOutputTests, + parameterName: 'customization', + formatParameter: function (customization) { + return customization !== undefined ? + ', C=' + customization.length + ' bytes' : ''; + }, + parameterEquals: function (emptyDataVector, customization) { + return equalBuffers( + customization ?? new Uint8Array(0), + emptyDataVector[3] ?? new Uint8Array(0) + ); + }, }); diff --git a/test/fixtures/wpt/WebCryptoAPI/digest/sha3.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/digest/sha3.tentative.https.any.js index f9f38eadc2c3..a6cafbb639f8 100644 --- a/test/fixtures/wpt/WebCryptoAPI/digest/sha3.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/digest/sha3.tentative.https.any.js @@ -1,28 +1,12 @@ // META: title=WebCryptoAPI: digest() SHA-3 algorithms // META: script=../util/helpers.js +// META: script=digest_test_data.js +// META: script=digest.js // META: timeout=long var subtle = crypto.subtle; // Change to test prefixed implementations -var sourceData = { - empty: new Uint8Array(0), - short: new Uint8Array([ - 21, 110, 234, 124, 193, 76, 86, 203, 148, 219, 3, 10, 74, 157, 149, 255, - ]), - medium: new Uint8Array([ - 182, 200, 249, 223, 100, 140, 208, 136, 183, 15, 56, 231, 65, 151, 177, 140, - 184, 30, 30, 67, 80, 213, 11, 204, 184, 251, 90, 115, 121, 200, 123, 178, - 227, 214, 237, 84, 97, 237, 30, 159, 54, 243, 64, 163, 150, 42, 68, 107, - 129, 91, 121, 75, 75, 212, 58, 68, 3, 80, 32, 119, 178, 37, 108, 200, 7, - 131, 127, 58, 172, 209, 24, 235, 75, 156, 43, 174, 184, 151, 6, 134, 37, - 171, 172, 161, 147, - ]), -}; - -sourceData.long = new Uint8Array(1024 * sourceData.medium.byteLength); -for (var i = 0; i < 1024; i++) { - sourceData.long.set(sourceData.medium, i * sourceData.medium.byteLength); -} +var sourceData = getDigestSourceData(true); var digestedData = { 'SHA3-256': { @@ -97,83 +81,14 @@ var digestedData = { }; // Test SHA-3 digest algorithms -Object.keys(sourceData).forEach(function (size) { - Object.keys(digestedData).forEach(function (alg) { - promise_test(function (test) { - return crypto.subtle - .digest(alg, sourceData[size]) - .then(function (result) { - assert_true( - equalBuffers(result, digestedData[alg][size]), - 'digest matches expected' - ); - }); - }, alg + ' with ' + size + ' source data'); - - if (sourceData[size].length > 0) { - promise_test(function (test) { - var buffer = new Uint8Array(sourceData[size]); - // Alter the buffer before calling digest - buffer[0] = ~buffer[0]; - return crypto.subtle - .digest({ - get name() { - // Alter the buffer back while calling digest - buffer[0] = sourceData[size][0]; - return alg; - } - }, buffer) - .then(function (result) { - assert_true( - equalBuffers(result, digestedData[alg][size]), - 'digest matches expected' - ); - }); - }, alg + ' with ' + size + ' source data and altered buffer during call'); - - promise_test(function (test) { - var buffer = new Uint8Array(sourceData[size]); - var promise = crypto.subtle.digest(alg, buffer).then(function (result) { - assert_true( - equalBuffers(result, digestedData[alg][size]), - 'digest matches expected' - ); - }); - // Alter the buffer after calling digest - buffer[0] = ~buffer[0]; - return promise; - }, alg + ' with ' + size + ' source data and altered buffer after call'); - - promise_test(function (test) { - var buffer = new Uint8Array(sourceData[size]); - return crypto.subtle - .digest({ - get name() { - // Transfer the buffer while calling digest - buffer.buffer.transfer(); - return alg; - } - }, buffer) - .then(function (result) { - assert_true( - equalBuffers(result, digestedData[alg].empty), - 'digest on transferred buffer should match result for empty buffer' - ); - }); - }, alg + ' with ' + size + ' source data and transferred buffer during call'); - - promise_test(function (test) { - var buffer = new Uint8Array(sourceData[size]); - var promise = crypto.subtle.digest(alg, buffer).then(function (result) { - assert_true( - equalBuffers(result, digestedData[alg][size]), - 'digest matches expected' - ); - }); - // Transfer the buffer after calling digest - buffer.buffer.transfer(); - return promise; - }, alg + ' with ' + size + ' source data and transferred buffer after call'); - } +runDigestTests(subtle, sourceData, function (size) { + return Object.keys(digestedData).map(function (alg) { + return { + algorithm: alg, + expected: digestedData[alg][size], + emptyExpected: digestedData[alg].empty, + label: alg + ' with ' + size + ' source data', + mutations: true, + }; }); }); diff --git a/test/fixtures/wpt/WebCryptoAPI/digest/turboshake.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/digest/turboshake.tentative.https.any.js index 243931cd1198..356e6987956c 100644 --- a/test/fixtures/wpt/WebCryptoAPI/digest/turboshake.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/digest/turboshake.tentative.https.any.js @@ -1,24 +1,10 @@ // META: title=WebCryptoAPI: digest() TurboSHAKE algorithms // META: script=../util/helpers.js +// META: script=xof_digest.js // META: timeout=long var subtle = crypto.subtle; // Change to test prefixed implementations -// Generates a Uint8Array of length n by repeating the pattern 00 01 02 .. F9 FA. -function ptn(n) { - var buf = new Uint8Array(n); - for (var i = 0; i < n; i++) - buf[i] = i % 251; - return buf; -} - -function hexToBytes(hex) { - var bytes = new Uint8Array(hex.length / 2); - for (var i = 0; i < hex.length; i += 2) - bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16); - return bytes; -} - // RFC 9861 Section 5 test vectors // [input, outputLengthBits, expected hex(, domainSeparation)] var turboSHAKE128Vectors = [ @@ -155,143 +141,18 @@ var largeOutputTests = [ '207265dccf2f43534e9c61ba0c9d1d75'], ]; -largeOutputTests.forEach(function (entry) { - var alg = entry[0]; - var outputLength = entry[1]; - var lastN = entry[2]; - var expected = entry[3]; - - promise_test(function (test) { - return subtle - .digest({ name: alg, outputLength: outputLength }, new Uint8Array(0)) - .then(function (result) { - var full = new Uint8Array(result); - var last = full.slice(full.length - lastN); - assert_true( - equalBuffers(last.buffer, hexToBytes(expected)), - 'last ' + lastN + ' bytes of digest match expected' - ); - }); - }, alg + ' with ' + outputLength + ' bit output, verify last ' + lastN + ' bytes'); -}); - -function domainSeparationEqual(emptyDataVector, domainSeparation) { - return (domainSeparation ?? 0x1f) === (emptyDataVector[3] ?? 0x1f); -} - -function outputLengthLessOrEqual(emptyDataVector, outputLength) { - return outputLength <= emptyDataVector[1]; -} - -var allVectors = { - TurboSHAKE128: turboSHAKE128Vectors, - TurboSHAKE256: turboSHAKE256Vectors, -}; - -Object.keys(allVectors).forEach(function (alg) { - var emptyDataVector = allVectors[alg][0]; - allVectors[alg].forEach(function (vector, i) { - var input = vector[0]; - var outputLength = vector[1]; - var expected = vector[2]; - var domainSeparation = vector[3]; - - var algorithmParams = { name: alg, outputLength: outputLength }; - if (domainSeparation !== undefined) - algorithmParams.domainSeparation = domainSeparation; - - var label = alg + ' vector #' + (i + 1) + - ' (' + outputLength + ' bit output, ' + input.length + ' byte input' + - (domainSeparation !== undefined ? ', D=0x' + domainSeparation.toString(16) : '') + ')'; - - promise_test(function (test) { - return subtle - .digest(algorithmParams, input) - .then(function (result) { - assert_true( - equalBuffers(result, hexToBytes(expected)), - 'digest matches expected' - ); - }); - }, label); - - if (input.length > 0) { - promise_test(function (test) { - var buffer = new Uint8Array(input); - // Alter the buffer before calling digest - buffer[0] = ~buffer[0]; - return subtle - .digest({ - get name() { - // Alter the buffer back while calling digest - buffer[0] = input[0]; - return alg; - }, - outputLength: outputLength, - domainSeparation: domainSeparation, - }, buffer) - .then(function (result) { - assert_true( - equalBuffers(result, hexToBytes(expected)), - 'digest matches expected' - ); - }); - }, label + ' and altered buffer during call'); - - promise_test(function (test) { - var buffer = new Uint8Array(input); - var promise = subtle - .digest(algorithmParams, buffer) - .then(function (result) { - assert_true( - equalBuffers(result, hexToBytes(expected)), - 'digest matches expected' - ); - }); - // Alter the buffer after calling digest - buffer[0] = ~buffer[0]; - return promise; - }, label + ' and altered buffer after call'); - - promise_test(function (test) { - var buffer = new Uint8Array(input); - return subtle - .digest({ - get name() { - // Transfer the buffer while calling digest - buffer.buffer.transfer(); - return alg; - }, - outputLength: outputLength, - domainSeparation: domainSeparation, - }, buffer) - .then(function (result) { - if (domainSeparationEqual(emptyDataVector, domainSeparation) && outputLengthLessOrEqual(emptyDataVector, outputLength)) { - assert_true( - equalBuffers(result, Uint8Array.fromHex(emptyDataVector[2]).subarray(0, outputLength / 8)), - 'digest on transferred buffer should match result for empty buffer' - ); - } else { - assert_equals(result.byteLength, outputLength / 8, - 'digest on transferred buffer should have correct output length'); - } - }); - }, label + ' and transferred buffer during call'); - - promise_test(function (test) { - var buffer = new Uint8Array(input); - var promise = subtle - .digest(algorithmParams, buffer) - .then(function (result) { - assert_true( - equalBuffers(result, hexToBytes(expected)), - 'digest matches expected' - ); - }); - // Transfer the buffer after calling digest - buffer.buffer.transfer(); - return promise; - }, label + ' and transferred buffer after call'); - } - }); +runXofDigestTests(subtle, { + vectors: { + TurboSHAKE128: turboSHAKE128Vectors, + TurboSHAKE256: turboSHAKE256Vectors, + }, + largeOutputTests: largeOutputTests, + parameterName: 'domainSeparation', + formatParameter: function (domainSeparation) { + return domainSeparation !== undefined ? + ', D=0x' + domainSeparation.toString(16) : ''; + }, + parameterEquals: function (emptyDataVector, domainSeparation) { + return (domainSeparation ?? 0x1f) === (emptyDataVector[3] ?? 0x1f); + }, }); diff --git a/test/fixtures/wpt/WebCryptoAPI/digest/xof_digest.js b/test/fixtures/wpt/WebCryptoAPI/digest/xof_digest.js new file mode 100644 index 000000000000..f5ef5846b796 --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/digest/xof_digest.js @@ -0,0 +1,146 @@ +// Generates a Uint8Array of length n by repeating the pattern 00 01 02 .. F9 FA. +function ptn(n) { + var buf = new Uint8Array(n); + for (var i = 0; i < n; i++) + buf[i] = i % 251; + return buf; +} + +function runXofDigestTests(subtle, options) { + options.largeOutputTests.forEach(function (entry) { + var alg = entry[0]; + var outputLength = entry[1]; + var lastN = entry[2]; + var expected = entry[3]; + + promise_test(function (test) { + return subtle + .digest({ name: alg, outputLength: outputLength }, new Uint8Array(0)) + .then(function (result) { + var full = new Uint8Array(result); + var last = full.slice(full.length - lastN); + assert_true( + equalBuffers(last.buffer, hexStringToUint8Array(expected)), + 'last ' + lastN + ' bytes of digest match expected' + ); + }); + }, alg + ' with ' + outputLength + ' bit output, verify last ' + lastN + ' bytes'); + }); + + Object.keys(options.vectors).forEach(function (alg) { + var emptyDataVector = options.vectors[alg][0]; + options.vectors[alg].forEach(function (vector, i) { + var input = vector[0]; + var outputLength = vector[1]; + var expected = vector[2]; + var parameter = vector[3]; + + var algorithmParams = { name: alg, outputLength: outputLength }; + if (parameter !== undefined) + algorithmParams[options.parameterName] = parameter; + + var label = alg + ' vector #' + (i + 1) + + ' (' + outputLength + ' bit output, ' + input.length + ' byte input' + + options.formatParameter(parameter) + ')'; + + promise_test(function (test) { + return subtle + .digest(algorithmParams, input) + .then(function (result) { + assert_true( + equalBuffers(result, hexStringToUint8Array(expected)), + 'digest matches expected' + ); + }); + }, label); + + if (input.length > 0) { + promise_test(function (test) { + var buffer = new Uint8Array(input); + // Alter the buffer before calling digest + buffer[0] = ~buffer[0]; + var duringCallParams = { + get name() { + // Alter the buffer back while calling digest + buffer[0] = input[0]; + return alg; + }, + outputLength: outputLength, + }; + duringCallParams[options.parameterName] = parameter; + return subtle + .digest(duringCallParams, buffer) + .then(function (result) { + assert_true( + equalBuffers(result, hexStringToUint8Array(expected)), + 'digest matches expected' + ); + }); + }, label + ' and altered buffer during call'); + + promise_test(function (test) { + var buffer = new Uint8Array(input); + var promise = subtle + .digest(algorithmParams, buffer) + .then(function (result) { + assert_true( + equalBuffers(result, hexStringToUint8Array(expected)), + 'digest matches expected' + ); + }); + // Alter the buffer after calling digest + buffer[0] = ~buffer[0]; + return promise; + }, label + ' and altered buffer after call'); + + promise_test(function (test) { + var buffer = new Uint8Array(input); + var duringCallParams = { + get name() { + // Transfer the buffer while calling digest + buffer.buffer.transfer(); + return alg; + }, + outputLength: outputLength, + }; + duringCallParams[options.parameterName] = parameter; + return subtle + .digest(duringCallParams, buffer) + .then(function (result) { + if ( + options.parameterEquals(emptyDataVector, parameter) && + outputLength <= emptyDataVector[1] + ) { + assert_true( + equalBuffers( + result, + hexStringToUint8Array(emptyDataVector[2]) + .subarray(0, outputLength / 8) + ), + 'digest on transferred buffer should match result for empty buffer' + ); + } else { + assert_equals(result.byteLength, outputLength / 8, + 'digest on transferred buffer should have correct output length'); + } + }); + }, label + ' and transferred buffer during call'); + + promise_test(function (test) { + var buffer = new Uint8Array(input); + var promise = subtle + .digest(algorithmParams, buffer) + .then(function (result) { + assert_true( + equalBuffers(result, hexStringToUint8Array(expected)), + 'digest matches expected' + ); + }); + // Transfer the buffer after calling digest + buffer.buffer.transfer(); + return promise; + }, label + ' and transferred buffer after call'); + } + }); + }); +} diff --git a/test/fixtures/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any.js index 5a669753cd27..ffb78f7e5348 100644 --- a/test/fixtures/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any.js @@ -27,11 +27,11 @@ function define_bits_tests() { 'encapsulateBits should return an object' ); assert_true( - encapsulatedBits.hasOwnProperty('sharedKey'), + Object.hasOwn(encapsulatedBits, 'sharedKey'), 'Result should have sharedKey property' ); assert_true( - encapsulatedBits.hasOwnProperty('ciphertext'), + Object.hasOwn(encapsulatedBits, 'ciphertext'), 'Result should have ciphertext property' ); assert_true( diff --git a/test/fixtures/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any.js index 0a45c1fc4e9f..a482eafbb610 100644 --- a/test/fixtures/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any.js @@ -61,11 +61,11 @@ function define_key_tests() { 'encapsulateKey should return an object' ); assert_true( - encapsulatedKey.hasOwnProperty('sharedKey'), + Object.hasOwn(encapsulatedKey, 'sharedKey'), 'Result should have sharedKey property' ); assert_true( - encapsulatedKey.hasOwnProperty('ciphertext'), + Object.hasOwn(encapsulatedKey, 'ciphertext'), 'Result should have ciphertext property' ); assert_true( diff --git a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes.js b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes.js index 879a6efe257e..9caecf695cf7 100644 --- a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes.js +++ b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes.js @@ -458,9 +458,7 @@ function run_test() { }); promise_test(function() { - return Promise.all(all_promises) - .then(function() {done();}) - .catch(function() {done();}) + return Promise.all(all_promises).finally(done); }, "setup"); // A test vector has all needed fields for encryption, EXCEPT that the @@ -470,9 +468,7 @@ function run_test() { // Returns a Promise that yields an updated vector on success. function importVectorKey(vector, usages) { if (vector.key !== null) { - return new Promise(function(resolve, reject) { - resolve(vector); - }); + return Promise.resolve(vector); } else { return subtle.importKey(vector.algorithm.name.toUpperCase() === "AES-OCB" ? "raw-secret" : "raw", vector.keyBuffer, {name: vector.algorithm.name}, false, usages) .then(function(key) { diff --git a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_cbc.https.any.js b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_cbc.https.any.js index ec09aae5a954..9dcbfbdeccbf 100644 --- a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_cbc.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_cbc.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: encrypt() Using AES-CBC // META: script=../util/helpers.js +// META: script=aes_common_fixtures.js // META: script=aes_cbc_vectors.js // META: script=aes.js // META: timeout=long diff --git a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_cbc_vectors.js b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_cbc_vectors.js index 96445a96325a..28ef75fece62 100644 --- a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_cbc_vectors.js +++ b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_cbc_vectors.js @@ -12,59 +12,9 @@ // plaintext - the text to encrypt // result - the expected result (usually just ciphertext, sometimes with added authentication) function getTestVectors() { - // Before we can really start, we need to fill a bunch of buffers with data - var plaintext = new Uint8Array([84, 104, 105, 115, 32, 115, - 112, 101, 99, 105, 102, 105, 99, 97, 116, 105, 111, 110, - 32, 100, 101, 115, 99, 114, 105, 98, 101, 115, 32, 97, 32, - 74, 97, 118, 97, 83, 99, 114, 105, 112, 116, 32, 65, 80, - 73, 32, 102, 111, 114, 32, 112, 101, 114, 102, 111, 114, - 109, 105, 110, 103, 32, 98, 97, 115, 105, 99, 32, 99, 114, - 121, 112, 116, 111, 103, 114, 97, 112, 104, 105, 99, 32, - 111, 112, 101, 114, 97, 116, 105, 111, 110, 115, 32, 105, - 110, 32, 119, 101, 98, 32, 97, 112, 112, 108, 105, 99, 97, - 116, 105, 111, 110, 115, 44, 32, 115, 117, 99, 104, 32, 97, - 115, 32, 104, 97, 115, 104, 105, 110, 103, 44, 32, 115, - 105, 103, 110, 97, 116, 117, 114, 101, 32, 103, 101, 110, - 101, 114, 97, 116, 105, 111, 110, 32, 97, 110, 100, 32, - 118, 101, 114, 105, 102, 105, 99, 97, 116, 105, 111, 110, - 44, 32, 97, 110, 100, 32, 101, 110, 99, 114, 121, 112, - 116, 105, 111, 110, 32, 97, 110, 100, 32, 100, 101, 99, - 114, 121, 112, 116, 105, 111, 110, 46, 32, 65, 100, 100, - 105, 116, 105, 111, 110, 97, 108, 108, 121, 44, 32, 105, - 116, 32, 100, 101, 115, 99, 114, 105, 98, 101, 115, 32, 97, - 110, 32, 65, 80, 73, 32, 102, 111, 114, 32, 97, 112, 112, - 108, 105, 99, 97, 116, 105, 111, 110, 115, 32, 116, 111, - 32, 103, 101, 110, 101, 114, 97, 116, 101, 32, 97, 110, - 100, 47, 111, 114, 32, 109, 97, 110, 97, 103, 101, 32, 116, - 104, 101, 32, 107, 101, 121, 105, 110, 103, 32, 109, 97, - 116, 101, 114, 105, 97, 108, 32, 110, 101, 99, 101, 115, - 115, 97, 114, 121, 32, 116, 111, 32, 112, 101, 114, 102, - 111, 114, 109, 32, 116, 104, 101, 115, 101, 32, 111, 112, - 101, 114, 97, 116, 105, 111, 110, 115, 46, 32, 85, 115, - 101, 115, 32, 102, 111, 114, 32, 116, 104, 105, 115, 32, - 65, 80, 73, 32, 114, 97, 110, 103, 101, 32, 102, 114, 111, - 109, 32, 117, 115, 101, 114, 32, 111, 114, 32, 115, 101, - 114, 118, 105, 99, 101, 32, 97, 117, 116, 104, 101, 110, - 116, 105, 99, 97, 116, 105, 111, 110, 44, 32, 100, 111, - 99, 117, 109, 101, 110, 116, 32, 111, 114, 32, 99, 111, - 100, 101, 32, 115, 105, 103, 110, 105, 110, 103, 44, 32, - 97, 110, 100, 32, 116, 104, 101, 32, 99, 111, 110, 102, - 105, 100, 101, 110, 116, 105, 97, 108, 105, 116, 121, 32, - 97, 110, 100, 32, 105, 110, 116, 101, 103, 114, 105, 116, - 121, 32, 111, 102, 32, 99, 111, 109, 109, 117, 110, 105, - 99, 97, 116, 105, 111, 110, 115, 46]); - - // We want some random key bytes of various sizes. - // These were randomly generated from a script. - var keyBytes = { - 128: new Uint8Array([222, 192, 212, 252, 191, 60, 71, - 65, 200, 146, 218, 189, 28, 212, 192, 78]), - 192: new Uint8Array([208, 238, 131, 65, 63, 68, 196, 63, 186, 208, - 61, 207, 166, 18, 99, 152, 29, 109, 221, 95, 240, 30, 28, 246]), - 256: new Uint8Array([103, 105, 56, 35, 251, 29, 88, 7, 63, 145, 236, - 233, 204, 58, 249, 16, 229, 83, 38, 22, 164, 210, 123, 19, 235, 123, 116, - 216, 0, 11, 191, 48]) - } + var commonFixtures = getAesCommonFixtures(); + var plaintext = commonFixtures.plaintext; + var keyBytes = commonFixtures.keyBytes; // AES-CBC needs a 16 byte (128 bit) IV. var iv = new Uint8Array([85, 170, 248, 155, 168, 148, 19, 213, 78, 167, 39, diff --git a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_common_fixtures.js b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_common_fixtures.js new file mode 100644 index 000000000000..d8c6d1666cca --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_common_fixtures.js @@ -0,0 +1,57 @@ +function getAesCommonFixtures() { + var plaintext = new Uint8Array([ + 84, 104, 105, 115, 32, 115, 112, 101, 99, 105, 102, 105, 99, 97, 116, 105, + 111, 110, 32, 100, 101, 115, 99, 114, 105, 98, 101, 115, 32, 97, 32, 74, 97, + 118, 97, 83, 99, 114, 105, 112, 116, 32, 65, 80, 73, 32, 102, 111, 114, 32, + 112, 101, 114, 102, 111, 114, 109, 105, 110, 103, 32, 98, 97, 115, 105, 99, + 32, 99, 114, 121, 112, 116, 111, 103, 114, 97, 112, 104, 105, 99, 32, 111, + 112, 101, 114, 97, 116, 105, 111, 110, 115, 32, 105, 110, 32, 119, 101, 98, + 32, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 115, 44, 32, 115, + 117, 99, 104, 32, 97, 115, 32, 104, 97, 115, 104, 105, 110, 103, 44, 32, + 115, 105, 103, 110, 97, 116, 117, 114, 101, 32, 103, 101, 110, 101, 114, 97, + 116, 105, 111, 110, 32, 97, 110, 100, 32, 118, 101, 114, 105, 102, 105, 99, + 97, 116, 105, 111, 110, 44, 32, 97, 110, 100, 32, 101, 110, 99, 114, 121, + 112, 116, 105, 111, 110, 32, 97, 110, 100, 32, 100, 101, 99, 114, 121, 112, + 116, 105, 111, 110, 46, 32, 65, 100, 100, 105, 116, 105, 111, 110, 97, 108, + 108, 121, 44, 32, 105, 116, 32, 100, 101, 115, 99, 114, 105, 98, 101, 115, + 32, 97, 110, 32, 65, 80, 73, 32, 102, 111, 114, 32, 97, 112, 112, 108, 105, + 99, 97, 116, 105, 111, 110, 115, 32, 116, 111, 32, 103, 101, 110, 101, 114, + 97, 116, 101, 32, 97, 110, 100, 47, 111, 114, 32, 109, 97, 110, 97, 103, + 101, 32, 116, 104, 101, 32, 107, 101, 121, 105, 110, 103, 32, 109, 97, 116, + 101, 114, 105, 97, 108, 32, 110, 101, 99, 101, 115, 115, 97, 114, 121, 32, + 116, 111, 32, 112, 101, 114, 102, 111, 114, 109, 32, 116, 104, 101, 115, + 101, 32, 111, 112, 101, 114, 97, 116, 105, 111, 110, 115, 46, 32, 85, 115, + 101, 115, 32, 102, 111, 114, 32, 116, 104, 105, 115, 32, 65, 80, 73, 32, + 114, 97, 110, 103, 101, 32, 102, 114, 111, 109, 32, 117, 115, 101, 114, 32, + 111, 114, 32, 115, 101, 114, 118, 105, 99, 101, 32, 97, 117, 116, 104, 101, + 110, 116, 105, 99, 97, 116, 105, 111, 110, 44, 32, 100, 111, 99, 117, 109, + 101, 110, 116, 32, 111, 114, 32, 99, 111, 100, 101, 32, 115, 105, 103, 110, + 105, 110, 103, 44, 32, 97, 110, 100, 32, 116, 104, 101, 32, 99, 111, 110, + 102, 105, 100, 101, 110, 116, 105, 97, 108, 105, 116, 121, 32, 97, 110, 100, + 32, 105, 110, 116, 101, 103, 114, 105, 116, 121, 32, 111, 102, 32, 99, 111, + 109, 109, 117, 110, 105, 99, 97, 116, 105, 111, 110, 115, 46, + ]); + + var keyBytes = { + 128: new Uint8Array([ + 222, 192, 212, 252, 191, 60, 71, 65, 200, 146, 218, 189, 28, 212, 192, 78, + ]), + 192: new Uint8Array([ + 208, 238, 131, 65, 63, 68, 196, 63, 186, 208, 61, 207, 166, 18, 99, 152, + 29, 109, 221, 95, 240, 30, 28, 246, + ]), + 256: new Uint8Array([ + 103, 105, 56, 35, 251, 29, 88, 7, 63, 145, 236, 233, 204, 58, 249, 16, + 229, 83, 38, 22, 164, 210, 123, 19, 235, 123, 116, 216, 0, 11, 191, 48, + ]), + }; + + var additionalData = new Uint8Array([ + 84, 104, 101, 114, 101, 32, 97, 114, 101, 32, 55, 32, 102, 117, 114, 116, + 104, 101, 114, 32, 101, 100, 105, 116, 111, 114, 105, 97, 108, 32, 110, 111, + 116, 101, 115, 32, 105, 110, 32, 116, 104, 101, 32, 100, 111, 99, 117, 109, + 101, 110, 116, 46, + ]); + + return { plaintext, keyBytes, additionalData }; +} diff --git a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_ctr.https.any.js b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_ctr.https.any.js index f9d85bb6c93b..cbda32f35432 100644 --- a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_ctr.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_ctr.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: encrypt() Using AES-CTR // META: script=../util/helpers.js +// META: script=aes_common_fixtures.js // META: script=aes_ctr_vectors.js // META: script=aes.js // META: timeout=long diff --git a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_ctr_vectors.js b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_ctr_vectors.js index 201dff83ce9c..89a19fa5fcbe 100644 --- a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_ctr_vectors.js +++ b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_ctr_vectors.js @@ -12,59 +12,9 @@ // plaintext - the text to encrypt // result - the expected result (usually just ciphertext, sometimes with added authentication) function getTestVectors() { - // Before we can really start, we need to fill a bunch of buffers with data - var plaintext = new Uint8Array([84, 104, 105, 115, 32, 115, - 112, 101, 99, 105, 102, 105, 99, 97, 116, 105, 111, 110, - 32, 100, 101, 115, 99, 114, 105, 98, 101, 115, 32, 97, 32, - 74, 97, 118, 97, 83, 99, 114, 105, 112, 116, 32, 65, 80, - 73, 32, 102, 111, 114, 32, 112, 101, 114, 102, 111, 114, - 109, 105, 110, 103, 32, 98, 97, 115, 105, 99, 32, 99, 114, - 121, 112, 116, 111, 103, 114, 97, 112, 104, 105, 99, 32, - 111, 112, 101, 114, 97, 116, 105, 111, 110, 115, 32, 105, - 110, 32, 119, 101, 98, 32, 97, 112, 112, 108, 105, 99, 97, - 116, 105, 111, 110, 115, 44, 32, 115, 117, 99, 104, 32, 97, - 115, 32, 104, 97, 115, 104, 105, 110, 103, 44, 32, 115, - 105, 103, 110, 97, 116, 117, 114, 101, 32, 103, 101, 110, - 101, 114, 97, 116, 105, 111, 110, 32, 97, 110, 100, 32, - 118, 101, 114, 105, 102, 105, 99, 97, 116, 105, 111, 110, - 44, 32, 97, 110, 100, 32, 101, 110, 99, 114, 121, 112, - 116, 105, 111, 110, 32, 97, 110, 100, 32, 100, 101, 99, - 114, 121, 112, 116, 105, 111, 110, 46, 32, 65, 100, 100, - 105, 116, 105, 111, 110, 97, 108, 108, 121, 44, 32, 105, - 116, 32, 100, 101, 115, 99, 114, 105, 98, 101, 115, 32, 97, - 110, 32, 65, 80, 73, 32, 102, 111, 114, 32, 97, 112, 112, - 108, 105, 99, 97, 116, 105, 111, 110, 115, 32, 116, 111, - 32, 103, 101, 110, 101, 114, 97, 116, 101, 32, 97, 110, - 100, 47, 111, 114, 32, 109, 97, 110, 97, 103, 101, 32, 116, - 104, 101, 32, 107, 101, 121, 105, 110, 103, 32, 109, 97, - 116, 101, 114, 105, 97, 108, 32, 110, 101, 99, 101, 115, - 115, 97, 114, 121, 32, 116, 111, 32, 112, 101, 114, 102, - 111, 114, 109, 32, 116, 104, 101, 115, 101, 32, 111, 112, - 101, 114, 97, 116, 105, 111, 110, 115, 46, 32, 85, 115, - 101, 115, 32, 102, 111, 114, 32, 116, 104, 105, 115, 32, - 65, 80, 73, 32, 114, 97, 110, 103, 101, 32, 102, 114, 111, - 109, 32, 117, 115, 101, 114, 32, 111, 114, 32, 115, 101, - 114, 118, 105, 99, 101, 32, 97, 117, 116, 104, 101, 110, - 116, 105, 99, 97, 116, 105, 111, 110, 44, 32, 100, 111, - 99, 117, 109, 101, 110, 116, 32, 111, 114, 32, 99, 111, - 100, 101, 32, 115, 105, 103, 110, 105, 110, 103, 44, 32, - 97, 110, 100, 32, 116, 104, 101, 32, 99, 111, 110, 102, - 105, 100, 101, 110, 116, 105, 97, 108, 105, 116, 121, 32, - 97, 110, 100, 32, 105, 110, 116, 101, 103, 114, 105, 116, - 121, 32, 111, 102, 32, 99, 111, 109, 109, 117, 110, 105, - 99, 97, 116, 105, 111, 110, 115, 46]); - - // We want some random key bytes of various sizes. - // These were randomly generated from a script. - var keyBytes = { - 128: new Uint8Array([222, 192, 212, 252, 191, 60, 71, - 65, 200, 146, 218, 189, 28, 212, 192, 78]), - 192: new Uint8Array([208, 238, 131, 65, 63, 68, 196, 63, 186, 208, - 61, 207, 166, 18, 99, 152, 29, 109, 221, 95, 240, 30, 28, 246]), - 256: new Uint8Array([103, 105, 56, 35, 251, 29, 88, 7, 63, 145, 236, - 233, 204, 58, 249, 16, 229, 83, 38, 22, 164, 210, 123, 19, 235, 123, 116, - 216, 0, 11, 191, 48]) - } + var commonFixtures = getAesCommonFixtures(); + var plaintext = commonFixtures.plaintext; + var keyBytes = commonFixtures.keyBytes; // AES-CTR needs a 16 byte (128 bit) counter. var counter = new Uint8Array([85, 170, 248, 155, 168, 148, 19, 213, 78, 167, 39, diff --git a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm.https.any.js b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm.https.any.js index b3e6b5f0d2c1..295351fc319d 100644 --- a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: encrypt() Using AES-GCM w/ 96-bit iv // META: script=../util/helpers.js +// META: script=aes_common_fixtures.js // META: script=aes_gcm_96_iv_fixtures.js // META: script=aes_gcm_vectors.js // META: script=aes.js diff --git a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm_256_iv.https.any.js b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm_256_iv.https.any.js index 196a8ea94fb1..a46f4c79b891 100644 --- a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm_256_iv.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm_256_iv.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: encrypt() Using AES-GCM w/ 256-bit iv // META: script=../util/helpers.js +// META: script=aes_common_fixtures.js // META: script=aes_gcm_256_iv_fixtures.js // META: script=aes_gcm_vectors.js // META: script=aes.js diff --git a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm_256_iv_fixtures.js b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm_256_iv_fixtures.js index 9cdbbbb79075..a081b8e86483 100644 --- a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm_256_iv_fixtures.js +++ b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm_256_iv_fixtures.js @@ -1,53 +1,7 @@ function getFixtures() { - // Before we can really start, we need to fill a bunch of buffers with data - var plaintext = new Uint8Array([ - 84, 104, 105, 115, 32, 115, 112, 101, 99, 105, 102, 105, 99, 97, 116, 105, - 111, 110, 32, 100, 101, 115, 99, 114, 105, 98, 101, 115, 32, 97, 32, 74, 97, - 118, 97, 83, 99, 114, 105, 112, 116, 32, 65, 80, 73, 32, 102, 111, 114, 32, - 112, 101, 114, 102, 111, 114, 109, 105, 110, 103, 32, 98, 97, 115, 105, 99, - 32, 99, 114, 121, 112, 116, 111, 103, 114, 97, 112, 104, 105, 99, 32, 111, - 112, 101, 114, 97, 116, 105, 111, 110, 115, 32, 105, 110, 32, 119, 101, 98, - 32, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 115, 44, 32, 115, - 117, 99, 104, 32, 97, 115, 32, 104, 97, 115, 104, 105, 110, 103, 44, 32, - 115, 105, 103, 110, 97, 116, 117, 114, 101, 32, 103, 101, 110, 101, 114, 97, - 116, 105, 111, 110, 32, 97, 110, 100, 32, 118, 101, 114, 105, 102, 105, 99, - 97, 116, 105, 111, 110, 44, 32, 97, 110, 100, 32, 101, 110, 99, 114, 121, - 112, 116, 105, 111, 110, 32, 97, 110, 100, 32, 100, 101, 99, 114, 121, 112, - 116, 105, 111, 110, 46, 32, 65, 100, 100, 105, 116, 105, 111, 110, 97, 108, - 108, 121, 44, 32, 105, 116, 32, 100, 101, 115, 99, 114, 105, 98, 101, 115, - 32, 97, 110, 32, 65, 80, 73, 32, 102, 111, 114, 32, 97, 112, 112, 108, 105, - 99, 97, 116, 105, 111, 110, 115, 32, 116, 111, 32, 103, 101, 110, 101, 114, - 97, 116, 101, 32, 97, 110, 100, 47, 111, 114, 32, 109, 97, 110, 97, 103, - 101, 32, 116, 104, 101, 32, 107, 101, 121, 105, 110, 103, 32, 109, 97, 116, - 101, 114, 105, 97, 108, 32, 110, 101, 99, 101, 115, 115, 97, 114, 121, 32, - 116, 111, 32, 112, 101, 114, 102, 111, 114, 109, 32, 116, 104, 101, 115, - 101, 32, 111, 112, 101, 114, 97, 116, 105, 111, 110, 115, 46, 32, 85, 115, - 101, 115, 32, 102, 111, 114, 32, 116, 104, 105, 115, 32, 65, 80, 73, 32, - 114, 97, 110, 103, 101, 32, 102, 114, 111, 109, 32, 117, 115, 101, 114, 32, - 111, 114, 32, 115, 101, 114, 118, 105, 99, 101, 32, 97, 117, 116, 104, 101, - 110, 116, 105, 99, 97, 116, 105, 111, 110, 44, 32, 100, 111, 99, 117, 109, - 101, 110, 116, 32, 111, 114, 32, 99, 111, 100, 101, 32, 115, 105, 103, 110, - 105, 110, 103, 44, 32, 97, 110, 100, 32, 116, 104, 101, 32, 99, 111, 110, - 102, 105, 100, 101, 110, 116, 105, 97, 108, 105, 116, 121, 32, 97, 110, 100, - 32, 105, 110, 116, 101, 103, 114, 105, 116, 121, 32, 111, 102, 32, 99, 111, - 109, 109, 117, 110, 105, 99, 97, 116, 105, 111, 110, 115, 46, - ]); - - // We want some random key bytes of various sizes. - // These were randomly generated from a script. - var keyBytes = { - 128: new Uint8Array([ - 222, 192, 212, 252, 191, 60, 71, 65, 200, 146, 218, 189, 28, 212, 192, 78, - ]), - 192: new Uint8Array([ - 208, 238, 131, 65, 63, 68, 196, 63, 186, 208, 61, 207, 166, 18, 99, 152, - 29, 109, 221, 95, 240, 30, 28, 246, - ]), - 256: new Uint8Array([ - 103, 105, 56, 35, 251, 29, 88, 7, 63, 145, 236, 233, 204, 58, 249, 16, - 229, 83, 38, 22, 164, 210, 123, 19, 235, 123, 116, 216, 0, 11, 191, 48, - ]), - }; + var commonFixtures = getAesCommonFixtures(); + var plaintext = commonFixtures.plaintext; + var keyBytes = commonFixtures.keyBytes; // AES-GCM needs an IV of no more than 2^64 - 1 bytes. Arbitrary 32 bytes is okay then. var iv = new Uint8Array([ @@ -55,15 +9,7 @@ function getFixtures() { 33, 117, 56, 94, 248, 173, 234, 194, 200, 115, 53, 235, 146, 141, 212, ]); - // Authenticated encryption via AES-GCM requires additional data that - // will be checked. We use the ASCII encoded Editorial Note - // following the Abstract of the Web Cryptography API recommendation. - var additionalData = new Uint8Array([ - 84, 104, 101, 114, 101, 32, 97, 114, 101, 32, 55, 32, 102, 117, 114, 116, - 104, 101, 114, 32, 101, 100, 105, 116, 111, 114, 105, 97, 108, 32, 110, 111, - 116, 101, 115, 32, 105, 110, 32, 116, 104, 101, 32, 100, 111, 99, 117, 109, - 101, 110, 116, 46, - ]); + var additionalData = commonFixtures.additionalData; // The length of the tag defaults to 16 bytes (128 bit). var tag = { diff --git a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm_96_iv_fixtures.js b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm_96_iv_fixtures.js index bb00e2d7dd92..e120b58d8dc4 100644 --- a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm_96_iv_fixtures.js +++ b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm_96_iv_fixtures.js @@ -1,68 +1,14 @@ function getFixtures() { - // Before we can really start, we need to fill a bunch of buffers with data - var plaintext = new Uint8Array([ - 84, 104, 105, 115, 32, 115, 112, 101, 99, 105, 102, 105, 99, 97, 116, 105, - 111, 110, 32, 100, 101, 115, 99, 114, 105, 98, 101, 115, 32, 97, 32, 74, 97, - 118, 97, 83, 99, 114, 105, 112, 116, 32, 65, 80, 73, 32, 102, 111, 114, 32, - 112, 101, 114, 102, 111, 114, 109, 105, 110, 103, 32, 98, 97, 115, 105, 99, - 32, 99, 114, 121, 112, 116, 111, 103, 114, 97, 112, 104, 105, 99, 32, 111, - 112, 101, 114, 97, 116, 105, 111, 110, 115, 32, 105, 110, 32, 119, 101, 98, - 32, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 115, 44, 32, 115, - 117, 99, 104, 32, 97, 115, 32, 104, 97, 115, 104, 105, 110, 103, 44, 32, - 115, 105, 103, 110, 97, 116, 117, 114, 101, 32, 103, 101, 110, 101, 114, 97, - 116, 105, 111, 110, 32, 97, 110, 100, 32, 118, 101, 114, 105, 102, 105, 99, - 97, 116, 105, 111, 110, 44, 32, 97, 110, 100, 32, 101, 110, 99, 114, 121, - 112, 116, 105, 111, 110, 32, 97, 110, 100, 32, 100, 101, 99, 114, 121, 112, - 116, 105, 111, 110, 46, 32, 65, 100, 100, 105, 116, 105, 111, 110, 97, 108, - 108, 121, 44, 32, 105, 116, 32, 100, 101, 115, 99, 114, 105, 98, 101, 115, - 32, 97, 110, 32, 65, 80, 73, 32, 102, 111, 114, 32, 97, 112, 112, 108, 105, - 99, 97, 116, 105, 111, 110, 115, 32, 116, 111, 32, 103, 101, 110, 101, 114, - 97, 116, 101, 32, 97, 110, 100, 47, 111, 114, 32, 109, 97, 110, 97, 103, - 101, 32, 116, 104, 101, 32, 107, 101, 121, 105, 110, 103, 32, 109, 97, 116, - 101, 114, 105, 97, 108, 32, 110, 101, 99, 101, 115, 115, 97, 114, 121, 32, - 116, 111, 32, 112, 101, 114, 102, 111, 114, 109, 32, 116, 104, 101, 115, - 101, 32, 111, 112, 101, 114, 97, 116, 105, 111, 110, 115, 46, 32, 85, 115, - 101, 115, 32, 102, 111, 114, 32, 116, 104, 105, 115, 32, 65, 80, 73, 32, - 114, 97, 110, 103, 101, 32, 102, 114, 111, 109, 32, 117, 115, 101, 114, 32, - 111, 114, 32, 115, 101, 114, 118, 105, 99, 101, 32, 97, 117, 116, 104, 101, - 110, 116, 105, 99, 97, 116, 105, 111, 110, 44, 32, 100, 111, 99, 117, 109, - 101, 110, 116, 32, 111, 114, 32, 99, 111, 100, 101, 32, 115, 105, 103, 110, - 105, 110, 103, 44, 32, 97, 110, 100, 32, 116, 104, 101, 32, 99, 111, 110, - 102, 105, 100, 101, 110, 116, 105, 97, 108, 105, 116, 121, 32, 97, 110, 100, - 32, 105, 110, 116, 101, 103, 114, 105, 116, 121, 32, 111, 102, 32, 99, 111, - 109, 109, 117, 110, 105, 99, 97, 116, 105, 111, 110, 115, 46, - ]); - - // We want some random key bytes of various sizes. - // These were randomly generated from a script. - var keyBytes = { - 128: new Uint8Array([ - 222, 192, 212, 252, 191, 60, 71, 65, 200, 146, 218, 189, 28, 212, 192, 78, - ]), - 192: new Uint8Array([ - 208, 238, 131, 65, 63, 68, 196, 63, 186, 208, 61, 207, 166, 18, 99, 152, - 29, 109, 221, 95, 240, 30, 28, 246, - ]), - 256: new Uint8Array([ - 103, 105, 56, 35, 251, 29, 88, 7, 63, 145, 236, 233, 204, 58, 249, 16, - 229, 83, 38, 22, 164, 210, 123, 19, 235, 123, 116, 216, 0, 11, 191, 48, - ]), - }; + var commonFixtures = getAesCommonFixtures(); + var plaintext = commonFixtures.plaintext; + var keyBytes = commonFixtures.keyBytes; // AES-GCM specification recommends that the IV should be 96 bits long. var iv = new Uint8Array([ 58, 146, 115, 42, 166, 234, 57, 191, 57, 134, 224, 199, ]); - // Authenticated encryption via AES-GCM requires additional data that - // will be checked. We use the ASCII encoded Editorial Note - // following the Abstract of the Web Cryptography API recommendation. - var additionalData = new Uint8Array([ - 84, 104, 101, 114, 101, 32, 97, 114, 101, 32, 55, 32, 102, 117, 114, 116, - 104, 101, 114, 32, 101, 100, 105, 116, 111, 114, 105, 97, 108, 32, 110, 111, - 116, 101, 115, 32, 105, 110, 32, 116, 104, 101, 32, 100, 111, 99, 117, 109, - 101, 110, 116, 46, - ]); + var additionalData = commonFixtures.additionalData; // The length of the tag defaults to 16 bytes (128 bit). var tag = { diff --git a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_ocb.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_ocb.tentative.https.any.js index cca34e9e54e7..e6a6246074c1 100644 --- a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_ocb.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_ocb.tentative.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: encrypt() Using AES-OCB w/ 120-bit iv // META: script=../util/helpers.js +// META: script=aes_common_fixtures.js // META: script=aes_ocb_fixtures.js // META: script=aes_ocb_vectors.js // META: script=aes.js diff --git a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_ocb_fixtures.js b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_ocb_fixtures.js index a5795195f163..3e0c014c3e1c 100644 --- a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_ocb_fixtures.js +++ b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes_ocb_fixtures.js @@ -1,64 +1,13 @@ function getFixtures() { - // Before we can really start, we need to fill a bunch of buffers with data - var plaintext = new Uint8Array([ - 84, 104, 105, 115, 32, 115, 112, 101, 99, 105, 102, 105, 99, 97, 116, 105, - 111, 110, 32, 100, 101, 115, 99, 114, 105, 98, 101, 115, 32, 97, 32, 74, 97, - 118, 97, 83, 99, 114, 105, 112, 116, 32, 65, 80, 73, 32, 102, 111, 114, 32, - 112, 101, 114, 102, 111, 114, 109, 105, 110, 103, 32, 98, 97, 115, 105, 99, - 32, 99, 114, 121, 112, 116, 111, 103, 114, 97, 112, 104, 105, 99, 32, 111, - 112, 101, 114, 97, 116, 105, 111, 110, 115, 32, 105, 110, 32, 119, 101, 98, - 32, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 115, 44, 32, 115, - 117, 99, 104, 32, 97, 115, 32, 104, 97, 115, 104, 105, 110, 103, 44, 32, - 115, 105, 103, 110, 97, 116, 117, 114, 101, 32, 103, 101, 110, 101, 114, 97, - 116, 105, 111, 110, 32, 97, 110, 100, 32, 118, 101, 114, 105, 102, 105, 99, - 97, 116, 105, 111, 110, 44, 32, 97, 110, 100, 32, 101, 110, 99, 114, 121, - 112, 116, 105, 111, 110, 32, 97, 110, 100, 32, 100, 101, 99, 114, 121, 112, - 116, 105, 111, 110, 46, 32, 65, 100, 100, 105, 116, 105, 111, 110, 97, 108, - 108, 121, 44, 32, 105, 116, 32, 100, 101, 115, 99, 114, 105, 98, 101, 115, - 32, 97, 110, 32, 65, 80, 73, 32, 102, 111, 114, 32, 97, 112, 112, 108, 105, - 99, 97, 116, 105, 111, 110, 115, 32, 116, 111, 32, 103, 101, 110, 101, 114, - 97, 116, 101, 32, 97, 110, 100, 47, 111, 114, 32, 109, 97, 110, 97, 103, - 101, 32, 116, 104, 101, 32, 107, 101, 121, 105, 110, 103, 32, 109, 97, 116, - 101, 114, 105, 97, 108, 32, 110, 101, 99, 101, 115, 115, 97, 114, 121, 32, - 116, 111, 32, 112, 101, 114, 102, 111, 114, 109, 32, 116, 104, 101, 115, - 101, 32, 111, 112, 101, 114, 97, 116, 105, 111, 110, 115, 46, 32, 85, 115, - 101, 115, 32, 102, 111, 114, 32, 116, 104, 105, 115, 32, 65, 80, 73, 32, - 114, 97, 110, 103, 101, 32, 102, 114, 111, 109, 32, 117, 115, 101, 114, 32, - 111, 114, 32, 115, 101, 114, 118, 105, 99, 101, 32, 97, 117, 116, 104, 101, - 110, 116, 105, 99, 97, 116, 105, 111, 110, 44, 32, 100, 111, 99, 117, 109, - 101, 110, 116, 32, 111, 114, 32, 99, 111, 100, 101, 32, 115, 105, 103, 110, - 105, 110, 103, 44, 32, 97, 110, 100, 32, 116, 104, 101, 32, 99, 111, 110, - 102, 105, 100, 101, 110, 116, 105, 97, 108, 105, 116, 121, 32, 97, 110, 100, - 32, 105, 110, 116, 101, 103, 114, 105, 116, 121, 32, 111, 102, 32, 99, 111, - 109, 109, 117, 110, 105, 99, 97, 116, 105, 111, 110, 115, 46, - ]); - - // We want some random key bytes of various sizes. - // These were randomly generated from a script. - var keyBytes = { - 128: new Uint8Array([ - 222, 192, 212, 252, 191, 60, 71, 65, 200, 146, 218, 189, 28, 212, 192, 78, - ]), - 192: new Uint8Array([ - 208, 238, 131, 65, 63, 68, 196, 63, 186, 208, 61, 207, 166, 18, 99, 152, - 29, 109, 221, 95, 240, 30, 28, 246, - ]), - 256: new Uint8Array([ - 103, 105, 56, 35, 251, 29, 88, 7, 63, 145, 236, 233, 204, 58, 249, 16, - 229, 83, 38, 22, 164, 210, 123, 19, 235, 123, 116, 216, 0, 11, 191, 48, - ]), - }; + var commonFixtures = getAesCommonFixtures(); + var plaintext = commonFixtures.plaintext; + var keyBytes = commonFixtures.keyBytes; var iv = new Uint8Array([ 58, 146, 115, 42, 166, 234, 57, 191, 57, 134, 224, 199, 108, 116, 46, ]); - var additionalData = new Uint8Array([ - 84, 104, 101, 114, 101, 32, 97, 114, 101, 32, 55, 32, 102, 117, 114, 116, - 104, 101, 114, 32, 101, 100, 105, 116, 111, 114, 105, 97, 108, 32, 110, 111, - 116, 101, 115, 32, 105, 110, 32, 116, 104, 101, 32, 100, 111, 99, 117, 109, - 101, 110, 116, 46, - ]); + var additionalData = commonFixtures.additionalData; var ciphertext = { 128: { diff --git a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/rsa.js b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/rsa.js index 071c086b3c4d..951ffd56e581 100644 --- a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/rsa.js +++ b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/rsa.js @@ -23,7 +23,7 @@ function run_test() { promise_test(function(test) { return subtle.decrypt(vector.algorithm, vector.privateKey, vector.ciphertext) .then(function(plaintext) { - assert_true(equalBuffers(plaintext, vector.plaintext, "Decryption works")); + assert_true(equalBuffers(plaintext, vector.plaintext), "Decryption works"); }, function(err) { assert_unreached("Decryption should not throw error " + vector.name + ": '" + err.message + "'"); }); @@ -60,7 +60,7 @@ function run_test() { } }, vector.privateKey, ciphertext) .then(function(plaintext) { - assert_true(equalBuffers(plaintext, vector.plaintext, "Decryption works")); + assert_true(equalBuffers(plaintext, vector.plaintext), "Decryption works"); }, function(err) { assert_unreached("Decryption should not throw error " + vector.name + ": '" + err.message + "'"); }); @@ -91,7 +91,7 @@ function run_test() { var ciphertext = copyBuffer(vector.ciphertext); var operation = subtle.decrypt(vector.algorithm, vector.privateKey, ciphertext) .then(function(plaintext) { - assert_true(equalBuffers(plaintext, vector.plaintext, "Decryption works")); + assert_true(equalBuffers(plaintext, vector.plaintext), "Decryption works"); }, function(err) { assert_unreached("Decryption should not throw error " + vector.name + ": '" + err.message + "'"); }); @@ -160,7 +160,7 @@ function run_test() { var ciphertext = copyBuffer(vector.ciphertext); var operation = subtle.decrypt(vector.algorithm, vector.privateKey, ciphertext) .then(function(plaintext) { - assert_true(equalBuffers(plaintext, vector.plaintext, "Decryption works")); + assert_true(equalBuffers(plaintext, vector.plaintext), "Decryption works"); }, function(err) { assert_unreached("Decryption should not throw error " + vector.name + ": '" + err.message + "'"); }); @@ -538,9 +538,7 @@ function run_test() { }); promise_test(function() { - return Promise.all(all_promises) - .then(function() {done();}) - .catch(function() {done();}) + return Promise.all(all_promises).finally(done); }, "setup"); // A test vector has all needed fields for encryption, EXCEPT that the @@ -552,9 +550,7 @@ function run_test() { var publicPromise, privatePromise; if (vector.publicKey !== null) { - publicPromise = new Promise(function(resolve, reject) { - resolve(vector); - }); + publicPromise = Promise.resolve(vector); } else { publicPromise = subtle.importKey(vector.publicKeyFormat, vector.publicKeyBuffer, {name: vector.algorithm.name, hash: vector.hash}, false, publicKeyUsages) .then(function(key) { @@ -564,9 +560,7 @@ function run_test() { } if (vector.privateKey !== null) { - privatePromise = new Promise(function(resolve, reject) { - resolve(vector); - }); + privatePromise = Promise.resolve(vector); } else { privatePromise = subtle.importKey(vector.privateKeyFormat, vector.privateKeyBuffer, {name: vector.algorithm.name, hash: vector.hash}, false, privateKeyUsages) .then(function(key) { diff --git a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/rsa_oaep.https.any.js b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/rsa_oaep.https.any.js index 3550f5eec287..42511415f157 100644 --- a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/rsa_oaep.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/rsa_oaep.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: encrypt() Using RSA-OAEP // META: script=../util/helpers.js +// META: script=../util/rsa_key_fixtures.js // META: script=rsa_vectors.js // META: script=rsa.js // META: timeout=long diff --git a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/rsa_vectors.js b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/rsa_vectors.js index fcc732eddc1d..ca99953524e4 100644 --- a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/rsa_vectors.js +++ b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/rsa_vectors.js @@ -18,8 +18,9 @@ // plaintext - the text to encrypt // result - the expected result (usually just ciphertext, sometimes with added authentication) function getTestVectors() { - var pkcs8 = new Uint8Array([48, 130, 4, 191, 2, 1, 0, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 4, 130, 4, 169, 48, 130, 4, 165, 2, 1, 0, 2, 130, 1, 1, 0, 211, 87, 96, 146, 230, 41, 87, 54, 69, 68, 231, 228, 35, 59, 123, 219, 41, 61, 178, 8, 81, 34, 196, 121, 50, 133, 70, 249, 240, 247, 18, 246, 87, 196, 177, 120, 104, 201, 48, 144, 140, 197, 148, 247, 237, 0, 192, 20, 66, 193, 175, 4, 194, 246, 120, 164, 139, 162, 200, 15, 209, 113, 62, 48, 181, 172, 80, 120, 122, 195, 81, 101, 137, 241, 113, 150, 127, 99, 134, 173, 163, 73, 0, 166, 187, 4, 238, 206, 164, 43, 240, 67, 206, 217, 160, 249, 77, 12, 192, 158, 145, 155, 157, 113, 102, 192, 138, 182, 206, 32, 70, 64, 174, 164, 196, 146, 13, 182, 216, 110, 185, 22, 208, 220, 192, 244, 52, 26, 16, 56, 4, 41, 231, 225, 3, 33, 68, 234, 148, 157, 232, 246, 192, 204, 191, 149, 250, 142, 146, 141, 112, 216, 163, 140, 225, 104, 219, 69, 246, 241, 52, 102, 61, 111, 101, 111, 92, 234, 188, 114, 93, 168, 192, 42, 171, 234, 170, 19, 172, 54, 167, 92, 192, 186, 225, 53, 223, 49, 20, 182, 101, 137, 199, 237, 60, 182, 21, 89, 174, 90, 56, 79, 22, 43, 250, 128, 219, 228, 97, 127, 134, 195, 241, 208, 16, 201, 79, 226, 201, 191, 1, 154, 110, 99, 179, 239, 192, 40, 212, 60, 238, 97, 28, 133, 236, 38, 60, 144, 108, 70, 55, 114, 198, 145, 27, 25, 238, 192, 150, 202, 118, 236, 94, 49, 225, 227, 2, 3, 1, 0, 1, 2, 130, 1, 1, 0, 139, 55, 92, 203, 135, 200, 37, 197, 255, 61, 83, 208, 9, 145, 110, 150, 65, 5, 126, 24, 82, 114, 39, 160, 122, 178, 38, 190, 16, 136, 129, 58, 59, 56, 187, 123, 72, 243, 119, 5, 81, 101, 250, 42, 147, 57, 210, 77, 198, 103, 213, 197, 186, 52, 39, 230, 164, 129, 23, 110, 172, 21, 255, 212, 144, 104, 49, 30, 28, 40, 59, 159, 58, 142, 12, 184, 9, 180, 99, 12, 80, 170, 143, 62, 69, 166, 11, 53, 158, 25, 191, 140, 187, 94, 202, 214, 78, 118, 31, 16, 149, 116, 63, 243, 106, 175, 92, 240, 236, 185, 127, 237, 173, 221, 166, 11, 91, 243, 93, 129, 26, 117, 184, 34, 35, 12, 250, 160, 25, 47, 173, 64, 84, 126, 39, 84, 72, 170, 51, 22, 191, 142, 43, 76, 224, 133, 79, 199, 112, 139, 83, 123, 162, 45, 19, 33, 11, 9, 174, 195, 122, 39, 89, 239, 192, 130, 161, 83, 27, 35, 169, 23, 48, 3, 125, 222, 78, 242, 107, 95, 150, 239, 220, 195, 159, 211, 76, 52, 90, 213, 28, 187, 228, 79, 229, 139, 138, 59, 78, 201, 151, 134, 108, 8, 109, 255, 27, 136, 49, 239, 10, 31, 234, 38, 60, 247, 218, 205, 3, 192, 76, 188, 194, 178, 121, 229, 127, 165, 185, 83, 153, 107, 251, 29, 214, 136, 23, 175, 127, 180, 44, 222, 247, 165, 41, 74, 87, 250, 194, 184, 173, 115, 159, 27, 2, 153, 2, 129, 129, 0, 251, 248, 51, 194, 198, 49, 201, 112, 36, 12, 142, 116, 133, 240, 106, 62, 162, 168, 72, 34, 81, 26, 134, 39, 221, 70, 78, 248, 175, 175, 113, 72, 209, 164, 37, 182, 184, 101, 125, 221, 82, 70, 131, 43, 142, 83, 48, 32, 197, 187, 181, 104, 133, 90, 106, 236, 62, 66, 33, 215, 147, 241, 220, 91, 47, 37, 132, 226, 65, 94, 72, 233, 162, 189, 41, 43, 19, 64, 49, 249, 156, 142, 180, 47, 192, 188, 208, 68, 155, 242, 44, 230, 222, 201, 112, 20, 239, 229, 172, 147, 235, 232, 53, 135, 118, 86, 37, 44, 187, 177, 108, 65, 91, 103, 177, 132, 210, 40, 69, 104, 162, 119, 213, 147, 53, 88, 92, 253, 2, 129, 129, 0, 214, 184, 206, 39, 199, 41, 93, 93, 22, 252, 53, 112, 237, 100, 200, 218, 147, 3, 250, 210, 148, 136, 193, 166, 94, 154, 215, 17, 249, 3, 112, 24, 125, 187, 253, 129, 49, 109, 105, 100, 139, 200, 140, 197, 200, 53, 81, 175, 255, 69, 222, 186, 207, 182, 17, 5, 247, 9, 228, 195, 8, 9, 185, 0, 49, 235, 214, 134, 36, 68, 150, 198, 246, 158, 105, 46, 189, 200, 20, 246, 66, 57, 244, 173, 21, 117, 110, 203, 120, 197, 165, 176, 153, 49, 219, 24, 48, 119, 197, 70, 163, 140, 76, 116, 56, 137, 173, 61, 62, 208, 121, 181, 98, 46, 208, 18, 15, 160, 225, 249, 59, 89, 61, 183, 216, 82, 224, 95, 2, 129, 128, 56, 135, 75, 157, 131, 247, 129, 120, 206, 45, 158, 252, 23, 92, 131, 137, 127, 214, 127, 48, 107, 191, 166, 159, 100, 238, 52, 35, 104, 206, 212, 124, 128, 195, 241, 206, 23, 122, 117, 141, 100, 186, 251, 12, 151, 134, 164, 66, 133, 250, 1, 205, 236, 53, 7, 205, 238, 125, 201, 183, 226, 178, 29, 60, 187, 204, 16, 14, 238, 153, 103, 132, 59, 5, 115, 41, 253, 204, 166, 41, 152, 237, 15, 17, 179, 140, 232, 176, 171, 199, 222, 57, 1, 124, 113, 207, 208, 174, 87, 84, 108, 85, 145, 68, 205, 208, 175, 208, 100, 95, 126, 168, 255, 7, 185, 116, 209, 237, 68, 253, 31, 142, 0, 245, 96, 191, 109, 69, 2, 129, 129, 0, 133, 41, 239, 144, 115, 207, 143, 123, 95, 249, 226, 26, 186, 223, 58, 65, 115, 211, 144, 6, 112, 223, 175, 89, 66, 106, 188, 223, 4, 147, 193, 61, 47, 29, 27, 70, 184, 36, 166, 172, 24, 148, 179, 217, 37, 37, 12, 24, 30, 52, 114, 193, 96, 120, 5, 110, 177, 154, 141, 40, 247, 31, 48, 128, 146, 117, 52, 129, 212, 148, 68, 253, 247, 140, 158, 166, 194, 68, 7, 220, 1, 142, 119, 211, 175, 239, 56, 91, 47, 247, 67, 158, 150, 35, 121, 65, 51, 45, 212, 70, 206, 190, 255, 219, 68, 4, 254, 79, 113, 89, 81, 97, 208, 22, 64, 44, 51, 77, 15, 87, 198, 26, 190, 79, 249, 244, 203, 249, 2, 129, 129, 0, 135, 216, 119, 8, 212, 103, 99, 228, 204, 190, 178, 209, 233, 113, 46, 91, 240, 33, 109, 112, 222, 148, 32, 165, 178, 6, 155, 116, 89, 185, 159, 93, 159, 127, 47, 173, 124, 215, 154, 174, 230, 122, 127, 154, 52, 67, 126, 60, 121, 168, 74, 240, 205, 141, 233, 223, 242, 104, 235, 12, 71, 147, 245, 1, 249, 136, 213, 64, 246, 211, 71, 92, 32, 121, 184, 34, 122, 35, 217, 104, 222, 196, 227, 198, 101, 3, 24, 113, 147, 69, 150, 48, 71, 43, 253, 182, 186, 29, 231, 134, 199, 151, 250, 111, 78, 166, 90, 42, 132, 25, 38, 47, 41, 103, 136, 86, 203, 115, 201, 189, 75, 200, 155, 94, 4, 27, 34, 119]); - var spki = new Uint8Array([48, 130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 130, 1, 15, 0, 48, 130, 1, 10, 2, 130, 1, 1, 0, 211, 87, 96, 146, 230, 41, 87, 54, 69, 68, 231, 228, 35, 59, 123, 219, 41, 61, 178, 8, 81, 34, 196, 121, 50, 133, 70, 249, 240, 247, 18, 246, 87, 196, 177, 120, 104, 201, 48, 144, 140, 197, 148, 247, 237, 0, 192, 20, 66, 193, 175, 4, 194, 246, 120, 164, 139, 162, 200, 15, 209, 113, 62, 48, 181, 172, 80, 120, 122, 195, 81, 101, 137, 241, 113, 150, 127, 99, 134, 173, 163, 73, 0, 166, 187, 4, 238, 206, 164, 43, 240, 67, 206, 217, 160, 249, 77, 12, 192, 158, 145, 155, 157, 113, 102, 192, 138, 182, 206, 32, 70, 64, 174, 164, 196, 146, 13, 182, 216, 110, 185, 22, 208, 220, 192, 244, 52, 26, 16, 56, 4, 41, 231, 225, 3, 33, 68, 234, 148, 157, 232, 246, 192, 204, 191, 149, 250, 142, 146, 141, 112, 216, 163, 140, 225, 104, 219, 69, 246, 241, 52, 102, 61, 111, 101, 111, 92, 234, 188, 114, 93, 168, 192, 42, 171, 234, 170, 19, 172, 54, 167, 92, 192, 186, 225, 53, 223, 49, 20, 182, 101, 137, 199, 237, 60, 182, 21, 89, 174, 90, 56, 79, 22, 43, 250, 128, 219, 228, 97, 127, 134, 195, 241, 208, 16, 201, 79, 226, 201, 191, 1, 154, 110, 99, 179, 239, 192, 40, 212, 60, 238, 97, 28, 133, 236, 38, 60, 144, 108, 70, 55, 114, 198, 145, 27, 25, 238, 192, 150, 202, 118, 236, 94, 49, 225, 227, 2, 3, 1, 0, 1]); + var keyFixtures = getRsaKeyFixtures(); + var pkcs8 = keyFixtures.pkcs8; + var spki = keyFixtures.spki; // Can optionally provide a label for encryption. We use the ASCII-encoded // abstract from the candidate recommendation. diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/algorithm_registry.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/algorithm_registry.js new file mode 100644 index 000000000000..2c7493dfffd6 --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/algorithm_registry.js @@ -0,0 +1,36 @@ +// Generated by WebCryptoAPI/tools/generate.py. Do not edit directly. +const generateKeyTestVectors = [ + {name: "AES-CTR", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []}, + {name: "AES-CBC", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []}, + {name: "AES-GCM", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []}, + {name: "AES-OCB", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []}, + {name: "ChaCha20-Poly1305", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []}, + {name: "AES-KW", resultType: CryptoKey, usages: ["wrapKey", "unwrapKey"], mandatoryUsages: []}, + {name: "HMAC", resultType: CryptoKey, usages: ["sign", "verify"], mandatoryUsages: []}, + {name: "RSASSA-PKCS1-v1_5", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, + {name: "RSA-PSS", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, + {name: "RSA-OAEP", resultType: "CryptoKeyPair", usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: ["decrypt", "unwrapKey"]}, + {name: "ECDSA", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, + {name: "ECDH", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]}, + {name: "Ed25519", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, + {name: "Ed448", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, + {name: "ML-DSA-44", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, + {name: "ML-DSA-65", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, + {name: "ML-DSA-87", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, + {name: "ML-KEM-512", resultType: "CryptoKeyPair", usages: ["decapsulateBits", "decapsulateKey", "encapsulateBits", "encapsulateKey"], mandatoryUsages: ["decapsulateBits", "decapsulateKey"]}, + {name: "ML-KEM-768", resultType: "CryptoKeyPair", usages: ["decapsulateBits", "decapsulateKey", "encapsulateBits", "encapsulateKey"], mandatoryUsages: ["decapsulateBits", "decapsulateKey"]}, + {name: "ML-KEM-1024", resultType: "CryptoKeyPair", usages: ["decapsulateBits", "decapsulateKey", "encapsulateBits", "encapsulateKey"], mandatoryUsages: ["decapsulateBits", "decapsulateKey"]}, + {name: "X25519", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]}, + {name: "X448", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]}, + {name: "KMAC128", resultType: CryptoKey, usages: ["sign", "verify"], mandatoryUsages: []}, + {name: "KMAC256", resultType: CryptoKey, usages: ["sign", "verify"], mandatoryUsages: []}, +]; + +function getGenerateKeyTestVectors(algorithmNames) { + if (algorithmNames && !Array.isArray(algorithmNames)) { + algorithmNames = [algorithmNames]; + } + + return generateKeyTestVectors.filter( + vector => !algorithmNames || algorithmNames.includes(vector.name)); +} diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures.js index a3258ae0dd77..e4a75c065152 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures.js @@ -1,8 +1,3 @@ -function run_test(algorithmNames) { - var subtle = crypto.subtle; // Change to test prefixed implementations - - setup({explicit_timeout: true}); - // These tests check that generateKey throws an error, and that // the error is of the right type, for a wide set of incorrect parameters. // @@ -21,77 +16,83 @@ function run_test(algorithmNames) { // helper functions that generate all possible test parameters for // different situations. - var allTestVectors = [ // Parameters that should work for generateKey - {name: "AES-CTR", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []}, - {name: "AES-CBC", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []}, - {name: "AES-GCM", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []}, - {name: "AES-OCB", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []}, - {name: "ChaCha20-Poly1305", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []}, - {name: "AES-KW", resultType: CryptoKey, usages: ["wrapKey", "unwrapKey"], mandatoryUsages: []}, - {name: "HMAC", resultType: CryptoKey, usages: ["sign", "verify"], mandatoryUsages: []}, - {name: "RSASSA-PKCS1-v1_5", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, - {name: "RSA-PSS", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, - {name: "RSA-OAEP", resultType: "CryptoKeyPair", usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: ["decrypt", "unwrapKey"]}, - {name: "ECDSA", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, - {name: "ECDH", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]}, - {name: "Ed25519", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, - {name: "Ed448", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, - {name: "ML-DSA-44", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, - {name: "ML-DSA-65", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, - {name: "ML-DSA-87", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, - {name: "ML-KEM-512", resultType: "CryptoKeyPair", usages: ["decapsulateBits", "decapsulateKey", "encapsulateBits", "encapsulateKey"], mandatoryUsages: ["decapsulateBits", "decapsulateKey"]}, - {name: "ML-KEM-768", resultType: "CryptoKeyPair", usages: ["decapsulateBits", "decapsulateKey", "encapsulateBits", "encapsulateKey"], mandatoryUsages: ["decapsulateBits", "decapsulateKey"]}, - {name: "ML-KEM-1024", resultType: "CryptoKeyPair", usages: ["decapsulateBits", "decapsulateKey", "encapsulateBits", "encapsulateKey"], mandatoryUsages: ["decapsulateBits", "decapsulateKey"]}, - {name: "X25519", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]}, - {name: "X448", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]}, - {name: "KMAC128", resultType: CryptoKey, usages: ["sign", "verify"], mandatoryUsages: []}, - {name: "KMAC256", resultType: CryptoKey, usages: ["sign", "verify"], mandatoryUsages: []}, - ]; +function parameterString(algorithm, extractable, usages) { + if (typeof algorithm !== "object" && typeof algorithm !== "string") { + alert(algorithm); + } - var testVectors = []; - if (algorithmNames && !Array.isArray(algorithmNames)) { - algorithmNames = [algorithmNames]; - }; - allTestVectors.forEach(function(vector) { - if (!algorithmNames || algorithmNames.includes(vector.name)) { - testVectors.push(vector); - } - }); + var result = "(" + + objectToString(algorithm) + ", " + + objectToString(extractable) + ", " + + objectToString(usages) + + ")"; + return result; +} - function parameterString(algorithm, extractable, usages) { - if (typeof algorithm !== "object" && typeof algorithm !== "string") { - alert(algorithm); - } +// Test that a given combination of parameters results in an error, +// AND that it is the correct kind of error. +// +// Expected error is either a number, tested against the error code, +// or a string, tested against the error name. +function testError(algorithm, extractable, usages, expectedError, testTag) { + promise_test(function(test) { + return crypto.subtle.generateKey(algorithm, extractable, usages) + .then(function(result) { + assert_unreached("Operation succeeded, but should not have"); + }, function(err) { + if (typeof expectedError === "number") { + assert_equals(err.code, expectedError, testTag + " not supported"); + } else { + assert_equals(err.name, expectedError, testTag + " not supported"); + } + }); + }, testTag + ": generateKey" + parameterString(algorithm, extractable, usages)); +} - var result = "(" + - objectToString(algorithm) + ", " + - objectToString(extractable) + ", " + - objectToString(usages) + - ")"; - return result; - } +// Algorithm normalization happens before generateKey looks at any other +// argument, so these cases are independent of the algorithm under test and +// only need to run once for the whole suite. +function run_bad_algorithm_test() { + // Algorithm normalization should fail with "Not supported" + var badAlgorithmNames = [ + "AES", + {name: "AES"}, + {name: "AES", length: 128}, + {name: "AES-CMAC", length: 128}, // Removed after CR + {name: "AES-CFB", length: 128}, // Removed after CR + {name: "HMAC", hash: "MD5"}, + {name: "RSA", hash: "SHA-256", modulusLength: 2048, publicExponent: new Uint8Array([1,0,1])}, + {name: "RSA-PSS", hash: "SHA", modulusLength: 2048, publicExponent: new Uint8Array([1,0,1])}, + {name: "EC", namedCurve: "P521"} + ]; + - // Test that a given combination of parameters results in an error, - // AND that it is the correct kind of error. - // - // Expected error is either a number, tested against the error code, - // or a string, tested against the error name. - function testError(algorithm, extractable, usages, expectedError, testTag) { - promise_test(function(test) { - return crypto.subtle.generateKey(algorithm, extractable, usages) - .then(function(result) { - assert_unreached("Operation succeeded, but should not have"); - }, function(err) { - if (typeof expectedError === "number") { - assert_equals(err.code, expectedError, testTag + " not supported"); - } else { - assert_equals(err.name, expectedError, testTag + " not supported"); - } + // Algorithm normalization failures should be found first + // - all other parameters can be good or bad, should fail + // due to NotSupportedError. + badAlgorithmNames.forEach(function(algorithm) { + allValidUsages(["decrypt", "sign", "deriveBits"], true, []) // Small search space, shouldn't matter because should fail before used + .forEach(function(usages) { + [false, true, "RED", 7].forEach(function(extractable){ + testError(algorithm, extractable, usages, "NotSupportedError", "Bad algorithm"); }); - }, testTag + ": generateKey" + parameterString(algorithm, extractable, usages)); - } + }); + }); + + // Empty algorithm should fail with TypeError + allValidUsages(["decrypt", "sign", "deriveBits"], true, []) // Small search space, shouldn't matter because should fail before used + .forEach(function(usages) { + [false, true, "RED", 7].forEach(function(extractable){ + testError({}, extractable, usages, "TypeError", "Empty algorithm"); + }); + }); +} + + +function run_test(algorithmNames) { + var testVectors = getGenerateKeyTestVectors(algorithmNames); // Given an algorithm name, create several invalid parameters. @@ -117,16 +118,15 @@ function run_test(algorithmNames) { } - // Don't create an exhaustive list of all invalid usages, - // because there would usually be nearly 2**8 of them, - // way too many to test. Instead, create every singleton + // Don't create an exhaustive list of all invalid usages because + // there would be too many to test. Instead, create every singleton // of an illegal usage, and "poison" every valid usage // with an illegal one. function invalidUsages(validUsages, mandatoryUsages) { var results = []; var illegalUsages = []; - ["encrypt", "decrypt", "sign", "verify", "wrapKey", "unwrapKey", "deriveKey", "deriveBits"].forEach(function(usage) { + allKeyUsages.forEach(function(usage) { if (!validUsages.includes(usage)) { illegalUsages.push(usage); } @@ -146,45 +146,9 @@ function run_test(algorithmNames) { // Now test for properly handling errors -// - Unsupported algorithm // - Bad usages for algorithm // - Bad key lengths - // Algorithm normalization should fail with "Not supported" - var badAlgorithmNames = [ - "AES", - {name: "AES"}, - {name: "AES", length: 128}, - {name: "AES-CMAC", length: 128}, // Removed after CR - {name: "AES-CFB", length: 128}, // Removed after CR - {name: "HMAC", hash: "MD5"}, - {name: "RSA", hash: "SHA-256", modulusLength: 2048, publicExponent: new Uint8Array([1,0,1])}, - {name: "RSA-PSS", hash: "SHA", modulusLength: 2048, publicExponent: new Uint8Array([1,0,1])}, - {name: "EC", namedCurve: "P521"} - ]; - - - // Algorithm normalization failures should be found first - // - all other parameters can be good or bad, should fail - // due to NotSupportedError. - badAlgorithmNames.forEach(function(algorithm) { - allValidUsages(["decrypt", "sign", "deriveBits"], true, []) // Small search space, shouldn't matter because should fail before used - .forEach(function(usages) { - [false, true, "RED", 7].forEach(function(extractable){ - testError(algorithm, extractable, usages, "NotSupportedError", "Bad algorithm"); - }); - }); - }); - - // Empty algorithm should fail with TypeError - allValidUsages(["decrypt", "sign", "deriveBits"], true, []) // Small search space, shouldn't matter because should fail before used - .forEach(function(usages) { - [false, true, "RED", 7].forEach(function(extractable){ - testError({}, extractable, usages, "TypeError", "Empty algorithm"); - }); - }); - - // Algorithms normalize okay, but usages bad (though not empty). // It shouldn't matter what other extractable is. Should fail // due to SyntaxError diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_AES-CBC.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_AES-CBC.https.any.js index 38bed1cc7028..5febdbb94926 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_AES-CBC.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_AES-CBC.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: generateKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=algorithm_registry.js // META: script=failures.js run_test(["AES-CBC"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_AES-CTR.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_AES-CTR.https.any.js index 0e7940775fe0..0eb6664f5d00 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_AES-CTR.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_AES-CTR.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: generateKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=algorithm_registry.js // META: script=failures.js run_test(["AES-CTR"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_AES-GCM.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_AES-GCM.https.any.js index a394c8b629c5..3d13b78903fd 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_AES-GCM.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_AES-GCM.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: generateKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=algorithm_registry.js // META: script=failures.js run_test(["AES-GCM"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_AES-KW.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_AES-KW.https.any.js index 40c199b29a5c..138565e59ac1 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_AES-KW.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_AES-KW.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: generateKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=algorithm_registry.js // META: script=failures.js run_test(["AES-KW"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_AES-OCB.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_AES-OCB.tentative.https.any.js index d4a2cd868ff5..ef7c8c38e537 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_AES-OCB.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_AES-OCB.tentative.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: generateKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=algorithm_registry.js // META: script=failures.js run_test(["AES-OCB"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_ECDH.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_ECDH.https.any.js index e522254d743a..f61d27e995c4 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_ECDH.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_ECDH.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: generateKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=algorithm_registry.js // META: script=failures.js run_test(["ECDH"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_ECDSA.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_ECDSA.https.any.js index e19974ff488c..e49b5e675b3f 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_ECDSA.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_ECDSA.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: generateKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=algorithm_registry.js // META: script=failures.js run_test(["ECDSA"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_Ed25519.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_Ed25519.https.any.js index 8f18fb1efe09..7505e97bf2e1 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_Ed25519.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_Ed25519.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: generateKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=algorithm_registry.js // META: script=failures.js run_test(["Ed25519"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_Ed448.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_Ed448.tentative.https.any.js index b25dcd149094..6ee388e40f76 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_Ed448.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_Ed448.tentative.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: generateKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=algorithm_registry.js // META: script=failures.js run_test(["Ed448"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_HMAC.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_HMAC.https.any.js index 43ce1c026fc7..e3097cd46cdc 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_HMAC.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_HMAC.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: generateKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=algorithm_registry.js // META: script=failures.js run_test(["HMAC"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_ML-DSA.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_ML-DSA.tentative.https.any.js index 91e20bc6148f..d41636dea797 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_ML-DSA.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_ML-DSA.tentative.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: generateKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=algorithm_registry.js // META: script=failures.js run_test(["ML-DSA-44", "ML-DSA-65", "ML-DSA-87"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_ML-KEM.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_ML-KEM.tentative.https.any.js index 9cd347d00f81..0ece96944e7b 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_ML-KEM.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_ML-KEM.tentative.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: generateKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=algorithm_registry.js // META: script=failures.js run_test(["ML-KEM-512", "ML-KEM-768", "ML-KEM-1024"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_RSA-OAEP.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_RSA-OAEP.https.any.js index 1d2bca96b18c..a4eb4e6cbc82 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_RSA-OAEP.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_RSA-OAEP.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: generateKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=algorithm_registry.js // META: script=failures.js run_test(["RSA-OAEP"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_RSA-PSS.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_RSA-PSS.https.any.js index 562f66697c9f..62ac442ebe2b 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_RSA-PSS.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_RSA-PSS.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: generateKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=algorithm_registry.js // META: script=failures.js run_test(["RSA-PSS"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.https.any.js index fb19308de6f7..f06e3402799a 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: generateKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=algorithm_registry.js // META: script=failures.js run_test(["RSASSA-PKCS1-v1_5"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_X25519.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_X25519.https.any.js index 2662d8697a9a..6735e85151e6 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_X25519.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_X25519.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: generateKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=algorithm_registry.js // META: script=failures.js run_test(["X25519"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_X448.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_X448.tentative.https.any.js index 455e260d1fe9..26e12b972590 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_X448.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_X448.tentative.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: generateKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=algorithm_registry.js // META: script=failures.js run_test(["X448"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_bad_algorithm.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_bad_algorithm.https.any.js new file mode 100644 index 000000000000..5fe0b15784e3 --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_bad_algorithm.https.any.js @@ -0,0 +1,5 @@ +// META: title=WebCryptoAPI: generateKey() for Failures +// META: timeout=long +// META: script=../util/helpers.js +// META: script=failures.js +run_bad_algorithm_test(); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_chacha20_poly1305.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_chacha20_poly1305.tentative.https.any.js index c9a278cdfc2b..6ec0593a14b9 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_chacha20_poly1305.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_chacha20_poly1305.tentative.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: generateKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=algorithm_registry.js // META: script=failures.js run_test(["ChaCha20-Poly1305"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_kmac.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_kmac.tentative.https.any.js index f906038c7d3f..889c17e9c23b 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_kmac.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/failures_kmac.tentative.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: generateKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=algorithm_registry.js // META: script=failures.js run_test(["KMAC128", "KMAC256"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes.js index c72384b7b93b..c70ecb331873 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes.js @@ -2,8 +2,6 @@ function run_test(algorithmNames, slowTest) { var subtle = crypto.subtle; // Change to test prefixed implementations - setup({explicit_timeout: true}); - // These tests check that generateKey successfully creates keys // when provided any of a wide set of correct parameters // and that they can be exported afterwards. @@ -17,42 +15,7 @@ function run_test(algorithmNames, slowTest) { // helper functions that generate all possible test parameters for // different situations. - var allTestVectors = [ // Parameters that should work for generateKey - {name: "AES-CTR", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []}, - {name: "AES-CBC", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []}, - {name: "AES-GCM", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []}, - {name: "AES-OCB", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []}, - {name: "ChaCha20-Poly1305", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []}, - {name: "AES-KW", resultType: CryptoKey, usages: ["wrapKey", "unwrapKey"], mandatoryUsages: []}, - {name: "HMAC", resultType: CryptoKey, usages: ["sign", "verify"], mandatoryUsages: []}, - {name: "RSASSA-PKCS1-v1_5", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, - {name: "RSA-PSS", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, - {name: "RSA-OAEP", resultType: "CryptoKeyPair", usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: ["decrypt", "unwrapKey"]}, - {name: "ECDSA", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, - {name: "ECDH", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]}, - {name: "Ed25519", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, - {name: "Ed448", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, - {name: "ML-DSA-44", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, - {name: "ML-DSA-65", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, - {name: "ML-DSA-87", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]}, - {name: "ML-KEM-512", resultType: "CryptoKeyPair", usages: ["decapsulateBits", "decapsulateKey", "encapsulateBits", "encapsulateKey"], mandatoryUsages: ["decapsulateBits", "decapsulateKey"]}, - {name: "ML-KEM-768", resultType: "CryptoKeyPair", usages: ["decapsulateBits", "decapsulateKey", "encapsulateBits", "encapsulateKey"], mandatoryUsages: ["decapsulateBits", "decapsulateKey"]}, - {name: "ML-KEM-1024", resultType: "CryptoKeyPair", usages: ["decapsulateBits", "decapsulateKey", "encapsulateBits", "encapsulateKey"], mandatoryUsages: ["decapsulateBits", "decapsulateKey"]}, - {name: "X25519", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]}, - {name: "X448", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]}, - {name: "KMAC128", resultType: CryptoKey, usages: ["sign", "verify"], mandatoryUsages: []}, - {name: "KMAC256", resultType: CryptoKey, usages: ["sign", "verify"], mandatoryUsages: []}, - ]; - - var testVectors = []; - if (algorithmNames && !Array.isArray(algorithmNames)) { - algorithmNames = [algorithmNames]; - }; - allTestVectors.forEach(function(vector) { - if (!algorithmNames || algorithmNames.includes(vector.name)) { - testVectors.push(vector); - } - }); + var testVectors = getGenerateKeyTestVectors(algorithmNames); function parameterString(algorithm, extractable, usages) { var result = "(" + @@ -93,6 +56,7 @@ function run_test(algorithmNames, slowTest) { ]; if (extractable) promises.push(subtle.exportKey('raw-seed', result.privateKey)); + await Promise.all(promises); } else if (resultType === "CryptoKeyPair") { const promises = [ subtle.exportKey('jwk', result.publicKey), @@ -146,6 +110,27 @@ function run_test(algorithmNames, slowTest) { assert_unreached("exportKey threw an unexpected error: " + err.toString()); }) }, testTag + ": generateKey" + parameterString(algorithm, extractable, usages)); + + // Special case for ECDH and ECDSA: check that the generated key length is consistent. + // Particularly for P-521, there is a high risk of the generated key being one byte short + // if the implementation isn't careful. + if (algorithm.namedCurve && extractable) { + promise_test(async function(test) { + // We run about 20 variants of this test, times 10 key generations below, + // so this should have a decent chance of catching issues. + await Promise.all(Array.from({ length: 10 }).map(async () => { + const { privateKey, publicKey } = await subtle.generateKey(algorithm, extractable, usages); + const [jwkPub, jwkPriv] = await Promise.all([ + subtle.exportKey('jwk', publicKey), + subtle.exportKey('jwk', privateKey), + ]); + const expectedLength = Math.ceil(Math.ceil(parseInt(algorithm.namedCurve.substring(2)) / 8) * 4/3); + assert_equals(jwkPub.x.length, expectedLength, "Public key value x has correct length"); + assert_equals(jwkPub.y.length, expectedLength, "Public key value y has correct length"); + assert_equals(jwkPriv.d.length, expectedLength, "Private key value d has correct length"); + })); + }, testTag + ": generateKey" + parameterString(algorithm, extractable, usages) + " produces consistent length key"); + } } // Test all valid sets of parameters for successful diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_AES-CBC.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_AES-CBC.https.any.js index 80f92c2cb7d7..b2e1b2971a91 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_AES-CBC.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_AES-CBC.https.any.js @@ -2,5 +2,6 @@ // META: timeout=long // META: script=../util/helpers.js // META: script=/common/subset-tests.js +// META: script=algorithm_registry.js // META: script=successes.js run_test(["AES-CBC"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_AES-CTR.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_AES-CTR.https.any.js index 243a104b606d..bec9e22f3205 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_AES-CTR.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_AES-CTR.https.any.js @@ -2,5 +2,6 @@ // META: timeout=long // META: script=../util/helpers.js // META: script=/common/subset-tests.js +// META: script=algorithm_registry.js // META: script=successes.js run_test(["AES-CTR"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_AES-GCM.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_AES-GCM.https.any.js index f0f947c8160f..df6e694c1e12 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_AES-GCM.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_AES-GCM.https.any.js @@ -2,5 +2,6 @@ // META: timeout=long // META: script=../util/helpers.js // META: script=/common/subset-tests.js +// META: script=algorithm_registry.js // META: script=successes.js run_test(["AES-GCM"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_AES-KW.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_AES-KW.https.any.js index dbc040fdc5cb..e55b24745c26 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_AES-KW.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_AES-KW.https.any.js @@ -2,5 +2,6 @@ // META: timeout=long // META: script=../util/helpers.js // META: script=/common/subset-tests.js +// META: script=algorithm_registry.js // META: script=successes.js run_test(["AES-KW"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_AES-OCB.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_AES-OCB.tentative.https.any.js index b43abc4edb41..c87f875f4b1e 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_AES-OCB.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_AES-OCB.tentative.https.any.js @@ -2,5 +2,6 @@ // META: timeout=long // META: script=../util/helpers.js // META: script=/common/subset-tests.js +// META: script=algorithm_registry.js // META: script=successes.js run_test(["AES-OCB"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_ECDH.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_ECDH.https.any.js index e9dee526149d..9ec44a350605 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_ECDH.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_ECDH.https.any.js @@ -2,5 +2,6 @@ // META: timeout=long // META: script=../util/helpers.js // META: script=/common/subset-tests.js +// META: script=algorithm_registry.js // META: script=successes.js run_test(["ECDH"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_ECDSA.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_ECDSA.https.any.js index a022f31fe9d1..9b0f40aa9a9b 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_ECDSA.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_ECDSA.https.any.js @@ -2,5 +2,6 @@ // META: timeout=long // META: script=../util/helpers.js // META: script=/common/subset-tests.js +// META: script=algorithm_registry.js // META: script=successes.js run_test(["ECDSA"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_Ed25519.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_Ed25519.https.any.js index 6b3bc460f60f..8ecbbd23553c 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_Ed25519.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_Ed25519.https.any.js @@ -2,5 +2,6 @@ // META: timeout=long // META: script=../util/helpers.js // META: script=/common/subset-tests.js +// META: script=algorithm_registry.js // META: script=successes.js run_test(["Ed25519"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_Ed448.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_Ed448.tentative.https.any.js index 8e37f57b244b..d017170ca1ad 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_Ed448.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_Ed448.tentative.https.any.js @@ -2,5 +2,6 @@ // META: timeout=long // META: script=../util/helpers.js // META: script=/common/subset-tests.js +// META: script=algorithm_registry.js // META: script=successes.js run_test(["Ed448"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_HMAC.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_HMAC.https.any.js index 18e0b271226f..59fab83b08b8 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_HMAC.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_HMAC.https.any.js @@ -2,5 +2,6 @@ // META: timeout=long // META: script=../util/helpers.js // META: script=/common/subset-tests.js +// META: script=algorithm_registry.js // META: script=successes.js run_test(["HMAC"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_ML-DSA.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_ML-DSA.tentative.https.any.js index 15d52f2a5059..6c81b193167c 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_ML-DSA.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_ML-DSA.tentative.https.any.js @@ -2,5 +2,6 @@ // META: timeout=long // META: script=../util/helpers.js // META: script=/common/subset-tests.js +// META: script=algorithm_registry.js // META: script=successes.js run_test(["ML-DSA-44", "ML-DSA-65", "ML-DSA-87"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_ML-KEM.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_ML-KEM.tentative.https.any.js index 68a0d97b9755..f41b5c34cdb5 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_ML-KEM.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_ML-KEM.tentative.https.any.js @@ -2,5 +2,6 @@ // META: timeout=long // META: script=../util/helpers.js // META: script=/common/subset-tests.js +// META: script=algorithm_registry.js // META: script=successes.js run_test(["ML-KEM-512", "ML-KEM-768", "ML-KEM-1024"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_RSA-OAEP.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_RSA-OAEP.https.any.js index d933fd981d4a..f7c550df2222 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_RSA-OAEP.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_RSA-OAEP.https.any.js @@ -18,5 +18,6 @@ // META: variant=?151-last // META: script=../util/helpers.js // META: script=/common/subset-tests.js +// META: script=algorithm_registry.js // META: script=successes.js run_test(["RSA-OAEP"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_RSA-PSS.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_RSA-PSS.https.any.js index cb43e3de3de3..d1a9ec33ac23 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_RSA-PSS.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_RSA-PSS.https.any.js @@ -6,5 +6,6 @@ // META: variant=?31-last // META: script=../util/helpers.js // META: script=/common/subset-tests.js +// META: script=algorithm_registry.js // META: script=successes.js run_test(["RSA-PSS"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.https.any.js index b8db5972284d..6db5a3703fe7 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.https.any.js @@ -6,5 +6,6 @@ // META: variant=?31-last // META: script=../util/helpers.js // META: script=/common/subset-tests.js +// META: script=algorithm_registry.js // META: script=successes.js run_test(["RSASSA-PKCS1-v1_5"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_X25519.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_X25519.https.any.js index 0e87cf50108e..5acd5b5a1c2b 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_X25519.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_X25519.https.any.js @@ -2,5 +2,6 @@ // META: timeout=long // META: script=../util/helpers.js // META: script=/common/subset-tests.js +// META: script=algorithm_registry.js // META: script=successes.js run_test(["X25519"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_X448.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_X448.tentative.https.any.js index e7dbe32696d8..f1475c16bbd2 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_X448.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_X448.tentative.https.any.js @@ -2,5 +2,6 @@ // META: timeout=long // META: script=../util/helpers.js // META: script=/common/subset-tests.js +// META: script=algorithm_registry.js // META: script=successes.js run_test(["X448"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_chacha20_poly1305.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_chacha20_poly1305.tentative.https.any.js index a1cef25c2f24..2f3efebb6bc2 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_chacha20_poly1305.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_chacha20_poly1305.tentative.https.any.js @@ -2,5 +2,6 @@ // META: timeout=long // META: script=../util/helpers.js // META: script=/common/subset-tests.js +// META: script=algorithm_registry.js // META: script=successes.js run_test(["ChaCha20-Poly1305"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_kmac.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_kmac.tentative.https.any.js index 9f881f92bc17..8276fa9058c4 100644 --- a/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_kmac.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/generateKey/successes_kmac.tentative.https.any.js @@ -2,5 +2,6 @@ // META: timeout=long // META: script=../util/helpers.js // META: script=/common/subset-tests.js +// META: script=algorithm_registry.js // META: script=successes.js run_test(["KMAC128", "KMAC256"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/getRandomValues.any.js b/test/fixtures/wpt/WebCryptoAPI/getRandomValues.any.js index aecd38efd60b..8fd18a81deff 100644 --- a/test/fixtures/wpt/WebCryptoAPI/getRandomValues.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/getRandomValues.any.js @@ -66,7 +66,7 @@ for (const array of arrays) { }, "Large length: " + array); test(function() { - assert_true(self.crypto.getRandomValues(new ctor(0)).length == 0) + assert_true(self.crypto.getRandomValues(new ctor(0)).length === 0) }, "Null arrays: " + array); test(function() { diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/ML-DSA_importKey.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/import_export/ML-DSA_importKey.tentative.https.any.js index 5ce13d858d6f..02f745d71c28 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/ML-DSA_importKey.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/ML-DSA_importKey.tentative.https.any.js @@ -1,8 +1,9 @@ // META: title=WebCryptoAPI: importKey() for ML-DSA keys // META: timeout=long // META: script=../util/helpers.js +// META: script=../util/mldsa_key_fixtures.js // META: script=ML-DSA_importKey_fixtures.js -// META: script=ML-DSA_importKey.js +// META: script=ml_importKey.js runTests("ML-DSA-44"); runTests("ML-DSA-65"); diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/ML-DSA_importKey_fixtures.js b/test/fixtures/wpt/WebCryptoAPI/import_export/ML-DSA_importKey_fixtures.js index ef1f5a1f51a9..abccc10c63fb 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/ML-DSA_importKey_fixtures.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/ML-DSA_importKey_fixtures.js @@ -1,99 +1,11 @@ +var mldsaKeyFixtures = getMldsaKeyFixtures(); + var keyData = { 'ML-DSA-44': { privateUsages: ['sign'], publicUsages: ['verify'], - pkcs8: new Uint8Array([ - 48, 52, 2, 1, 0, 48, 11, 6, 9, 96, 134, 72, 1, 101, 3, 4, 3, 17, 4, 34, - 128, 32, 153, 21, 95, 99, 48, 150, 218, 124, 190, 8, 122, 137, 72, 184, - 79, 118, 123, 16, 249, 1, 200, 35, 194, 64, 177, 221, 43, 200, 112, 5, - 201, 62, - ]), - spki: new Uint8Array([ - 48, 130, 5, 50, 48, 11, 6, 9, 96, 134, 72, 1, 101, 3, 4, 3, 17, 3, 130, 5, - 33, 0, 85, 152, 213, 68, 198, 20, 177, 84, 200, 188, 33, 104, 36, 161, - 193, 127, 226, 151, 48, 107, 122, 191, 89, 86, 188, 3, 245, 199, 18, 79, - 168, 192, 218, 218, 223, 227, 84, 133, 41, 187, 9, 183, 14, 222, 155, 137, - 84, 111, 138, 97, 234, 152, 52, 15, 163, 47, 227, 218, 19, 20, 229, 93, - 99, 252, 155, 213, 30, 241, 158, 211, 213, 191, 155, 73, 211, 145, 59, - 194, 75, 140, 3, 161, 149, 139, 48, 172, 155, 172, 120, 234, 142, 79, 78, - 116, 215, 184, 50, 182, 162, 192, 93, 221, 179, 216, 70, 186, 92, 93, 51, - 190, 61, 173, 105, 206, 9, 208, 52, 54, 208, 252, 115, 176, 146, 118, 23, - 0, 5, 41, 151, 121, 241, 246, 193, 206, 212, 160, 181, 7, 99, 220, 78, 96, - 123, 142, 35, 107, 37, 218, 138, 139, 228, 207, 166, 132, 87, 36, 116, - 251, 174, 10, 41, 196, 171, 26, 212, 90, 213, 223, 141, 87, 232, 59, 46, - 173, 16, 247, 173, 4, 219, 165, 234, 8, 217, 233, 163, 13, 10, 160, 22, - 87, 232, 2, 9, 92, 177, 35, 67, 55, 104, 51, 204, 231, 81, 209, 62, 31, - 117, 56, 141, 78, 109, 148, 118, 191, 93, 193, 59, 30, 88, 237, 19, 169, - 14, 11, 150, 102, 215, 144, 69, 246, 32, 159, 110, 49, 75, 78, 225, 121, - 184, 206, 234, 126, 171, 164, 43, 237, 244, 63, 83, 70, 136, 213, 244, - 121, 184, 34, 201, 249, 95, 64, 165, 99, 14, 195, 231, 18, 121, 20, 156, - 80, 231, 133, 197, 0, 94, 195, 22, 251, 255, 174, 213, 103, 75, 88, 58, - 138, 66, 37, 85, 162, 15, 242, 29, 49, 147, 191, 163, 170, 109, 195, 22, - 63, 197, 149, 117, 100, 36, 81, 115, 203, 126, 62, 86, 103, 193, 182, 69, - 238, 233, 162, 62, 248, 132, 158, 212, 208, 187, 127, 212, 198, 169, 245, - 26, 153, 28, 207, 85, 65, 145, 200, 23, 196, 38, 64, 49, 54, 233, 185, 72, - 156, 86, 230, 127, 152, 108, 184, 240, 109, 8, 103, 228, 206, 142, 73, 74, - 214, 52, 182, 203, 82, 201, 175, 188, 111, 42, 232, 8, 177, 131, 47, 237, - 92, 120, 210, 124, 48, 185, 215, 137, 36, 70, 162, 164, 119, 0, 155, 20, - 57, 33, 27, 220, 77, 254, 233, 190, 106, 135, 21, 194, 57, 238, 95, 162, - 78, 164, 33, 210, 215, 43, 100, 96, 232, 87, 19, 43, 65, 240, 183, 17, - 131, 247, 97, 241, 7, 111, 159, 40, 252, 45, 228, 76, 71, 46, 85, 181, 54, - 41, 135, 162, 144, 227, 128, 121, 173, 207, 119, 54, 19, 197, 23, 231, - 176, 125, 190, 32, 76, 60, 34, 24, 160, 42, 73, 190, 124, 99, 5, 9, 214, - 6, 220, 177, 206, 79, 222, 10, 142, 250, 63, 179, 67, 21, 159, 57, 126, - 239, 28, 238, 240, 107, 79, 185, 174, 232, 168, 146, 128, 229, 119, 19, - 21, 33, 239, 193, 42, 178, 152, 124, 24, 203, 131, 193, 93, 162, 2, 208, - 231, 20, 203, 232, 47, 54, 114, 255, 236, 97, 99, 156, 15, 160, 75, 60, - 111, 59, 35, 25, 230, 43, 91, 170, 161, 74, 70, 179, 180, 251, 71, 197, - 240, 104, 42, 39, 202, 206, 12, 115, 249, 138, 55, 252, 216, 61, 185, 121, - 76, 137, 172, 166, 88, 92, 130, 18, 52, 67, 13, 187, 49, 147, 212, 77, 74, - 56, 59, 123, 99, 205, 36, 137, 96, 111, 148, 121, 157, 2, 83, 246, 86, - 156, 152, 98, 172, 77, 244, 214, 225, 184, 240, 121, 144, 56, 213, 161, - 43, 67, 4, 161, 104, 202, 91, 134, 247, 108, 24, 46, 187, 63, 216, 50, - 125, 120, 17, 216, 22, 228, 156, 253, 7, 180, 15, 130, 180, 72, 71, 169, - 3, 236, 247, 11, 170, 32, 76, 236, 225, 133, 250, 20, 235, 200, 143, 89, - 25, 158, 49, 158, 164, 213, 221, 81, 120, 241, 150, 210, 19, 79, 165, 24, - 35, 170, 182, 242, 255, 143, 171, 148, 140, 41, 207, 186, 98, 224, 16, - 152, 224, 38, 110, 175, 169, 111, 132, 201, 178, 114, 25, 196, 50, 149, - 158, 193, 180, 101, 183, 92, 109, 131, 102, 119, 123, 78, 107, 223, 4, 1, - 206, 140, 130, 237, 205, 36, 18, 180, 197, 154, 26, 236, 140, 173, 230, - 101, 35, 189, 121, 104, 21, 75, 81, 224, 186, 212, 81, 107, 66, 244, 235, - 64, 90, 206, 39, 44, 43, 162, 187, 63, 229, 217, 154, 185, 157, 24, 125, - 252, 91, 136, 59, 47, 182, 200, 73, 19, 137, 132, 81, 16, 234, 227, 210, - 32, 16, 160, 188, 250, 27, 190, 164, 53, 244, 219, 199, 177, 146, 117, 50, - 99, 72, 235, 37, 154, 72, 51, 203, 61, 39, 230, 34, 132, 117, 217, 167, - 201, 42, 17, 76, 72, 103, 172, 93, 169, 29, 76, 88, 178, 226, 32, 53, 190, - 60, 210, 132, 113, 198, 26, 70, 179, 47, 34, 184, 88, 178, 208, 1, 196, - 89, 136, 167, 33, 38, 9, 255, 89, 202, 27, 93, 229, 100, 192, 24, 234, - 200, 186, 125, 231, 212, 188, 11, 29, 51, 189, 70, 147, 176, 231, 81, 16, - 114, 152, 159, 21, 124, 185, 208, 50, 74, 211, 113, 207, 35, 54, 173, 205, - 133, 52, 167, 199, 87, 158, 120, 33, 204, 163, 146, 233, 21, 61, 28, 102, - 48, 232, 184, 15, 219, 238, 240, 215, 222, 239, 3, 110, 180, 95, 103, 147, - 236, 10, 57, 195, 159, 231, 50, 92, 145, 165, 44, 204, 121, 187, 9, 210, - 80, 86, 251, 169, 132, 236, 248, 23, 207, 222, 227, 13, 53, 1, 88, 69, - 105, 13, 238, 202, 251, 194, 245, 14, 38, 1, 245, 157, 212, 162, 182, 217, - 230, 115, 139, 175, 219, 199, 74, 124, 186, 158, 3, 220, 87, 220, 177, 85, - 13, 58, 168, 223, 6, 238, 156, 80, 121, 44, 166, 176, 0, 48, 98, 70, 93, - 78, 50, 192, 16, 186, 2, 233, 105, 105, 120, 195, 17, 100, 141, 214, 158, - 144, 63, 4, 88, 190, 101, 209, 55, 119, 46, 128, 117, 225, 121, 204, 195, - 19, 61, 170, 116, 251, 225, 230, 28, 27, 249, 84, 195, 224, 190, 60, 212, - 83, 3, 148, 204, 4, 103, 50, 233, 175, 207, 47, 51, 216, 79, 251, 150, 81, - 171, 7, 145, 55, 188, 187, 217, 200, 155, 246, 85, 42, 123, 18, 112, 192, - 116, 163, 40, 187, 132, 192, 210, 188, 106, 117, 217, 185, 183, 202, 33, - 11, 205, 10, 61, 52, 15, 66, 131, 121, 112, 26, 96, 166, 241, 1, 68, 206, - 80, 92, 132, 83, 89, 126, 135, 157, 4, 202, 16, 5, 131, 112, 62, 56, 234, - 176, 213, 119, 205, 203, 17, 106, 156, 117, 251, 135, 21, 73, 219, 238, 3, - 88, 21, 71, 136, 118, 0, 7, 106, 151, 200, 221, 179, 206, 50, 198, 27, - 118, 181, 27, 85, 35, 248, 44, 57, 15, 221, 97, 121, 4, 167, 111, 182, - 207, 195, 52, 134, 195, 128, 173, 111, 98, 152, 29, 138, 197, 175, 171, - 247, 194, 20, 134, 209, 232, 94, 17, 203, 139, 30, 237, 187, 243, 16, 180, - 43, 105, 236, 66, 175, 170, 139, 24, 99, 28, 225, 141, 96, 250, 119, 0, - 111, 212, 34, 217, 42, 134, 88, 78, 76, 126, 169, 168, 59, 154, 93, 54, - 43, 161, 29, 111, 124, 59, 225, 52, 86, 147, 38, 151, 161, 36, 119, 204, - 164, 121, 46, 186, 65, 84, 70, 38, 15, 203, 48, 168, 235, 231, 30, 55, 95, - 36, 10, 20, 166, 109, 8, 18, 109, 251, 213, 82, 142, 240, 49, 249, 180, - 78, 69, - ]), + pkcs8: mldsaKeyFixtures.pkcs8['ML-DSA-44'], + spki: mldsaKeyFixtures.spki['ML-DSA-44'], 'raw-public': hexStringToUint8Array( '5598d544c614b154c8bc216824a1c17fe297306b7abf5956bc03f5c7124fa8c0dadadfe3548529bb09b70ede9b89546f8a61ea98340fa32fe3da1314e55d63fc9bd51ef19ed3d5bf9b49d3913bc24b8c03a1958b30ac9bac78ea8e4f4e74d7b832b6a2c05dddb3d846ba5c5d33be3dad69ce09d03436d0fc73b09276170005299779f1f6c1ced4a0b50763dc4e607b8e236b25da8a8be4cfa684572474fbae0a29c4ab1ad45ad5df8d57e83b2ead10f7ad04dba5ea08d9e9a30d0aa01657e802095cb12343376833cce751d13e1f75388d4e6d9476bf5dc13b1e58ed13a90e0b9666d79045f6209f6e314b4ee179b8ceea7eaba42bedf43f534688d5f479b822c9f95f40a5630ec3e71279149c50e785c5005ec316fbffaed5674b583a8a422555a20ff21d3193bfa3aa6dc3163fc5957564245173cb7e3e5667c1b645eee9a23ef8849ed4d0bb7fd4c6a9f51a991ccf554191c817c426403136e9b9489c56e67f986cb8f06d0867e4ce8e494ad634b6cb52c9afbc6f2ae808b1832fed5c78d27c30b9d7892446a2a477009b1439211bdc4dfee9be6a8715c239ee5fa24ea421d2d72b6460e857132b41f0b71183f761f1076f9f28fc2de44c472e55b5362987a290e38079adcf773613c517e7b07dbe204c3c2218a02a49be7c630509d606dcb1ce4fde0a8efa3fb343159f397eef1ceef06b4fb9aee8a89280e577131521efc12ab2987c18cb83c15da202d0e714cbe82f3672ffec61639c0fa04b3c6f3b2319e62b5baaa14a46b3b4fb47c5f0682a27cace0c73f98a37fcd83db9794c89aca6585c821234430dbb3193d44d4a383b7b63cd2489606f94799d0253f6569c9862ac4df4d6e1b8f0799038d5a12b4304a168ca5b86f76c182ebb3fd8327d7811d816e49cfd07b40f82b44847a903ecf70baa204cece185fa14ebc88f59199e319ea4d5dd5178f196d2134fa51823aab6f2ff8fab948c29cfba62e01098e0266eafa96f84c9b27219c432959ec1b465b75c6d8366777b4e6bdf0401ce8c82edcd2412b4c59a1aec8cade66523bd7968154b51e0bad4516b42f4eb405ace272c2ba2bb3fe5d99ab99d187dfc5b883b2fb6c8491389845110eae3d22010a0bcfa1bbea435f4dbc7b19275326348eb259a4833cb3d27e6228475d9a7c92a114c4867ac5da91d4c58b2e22035be3cd28471c61a46b32f22b858b2d001c45988a7212609ff59ca1b5de564c018eac8ba7de7d4bc0b1d33bd4693b0e7511072989f157cb9d0324ad371cf2336adcd8534a7c7579e7821cca392e9153d1c6630e8b80fdbeef0d7deef036eb45f6793ec0a39c39fe7325c91a52ccc79bb09d25056fba984ecf817cfdee30d35015845690deecafbc2f50e2601f59dd4a2b6d9e6738bafdbc74a7cba9e03dc57dcb1550d3aa8df06ee9c50792ca6b0003062465d4e32c010ba02e9696978c311648dd69e903f0458be65d137772e8075e179ccc3133daa74fbe1e61c1bf954c3e0be3cd4530394cc046732e9afcf2f33d84ffb9651ab079137bcbbd9c89bf6552a7b1270c074a328bb84c0d2bc6a75d9b9b7ca210bcd0a3d340f428379701a60a6f10144ce505c8453597e879d04ca100583703e38eab0d577cdcb116a9c75fb871549dbee03581547887600076a97c8ddb3ce32c61b76b51b5523f82c390fdd617904a76fb6cfc33486c380ad6f62981d8ac5afabf7c21486d1e85e11cb8b1eedbbf310b42b69ec42afaa8b18631ce18d60fa77006fd422d92a86584e4c7ea9a83b9a5d362ba11d6f7c3be13456932697a12477cca4792eba415446260fcb30a8ebe71e375f240a14a66d08126dfbd5528ef031f9b44e45' ), @@ -111,138 +23,8 @@ var keyData = { 'ML-DSA-65': { privateUsages: ['sign'], publicUsages: ['verify'], - pkcs8: new Uint8Array([ - 48, 52, 2, 1, 0, 48, 11, 6, 9, 96, 134, 72, 1, 101, 3, 4, 3, 18, 4, 34, - 128, 32, 132, 164, 137, 75, 123, 70, 164, 178, 3, 156, 206, 16, 195, 26, - 133, 186, 176, 195, 102, 48, 254, 35, 29, 66, 103, 17, 67, 152, 38, 7, - 130, 139, - ]), - spki: new Uint8Array([ - 48, 130, 7, 178, 48, 11, 6, 9, 96, 134, 72, 1, 101, 3, 4, 3, 18, 3, 130, - 7, 161, 0, 216, 177, 233, 60, 151, 24, 246, 66, 175, 161, 192, 118, 9, - 177, 87, 232, 5, 216, 49, 254, 251, 160, 51, 216, 250, 171, 229, 104, 149, - 117, 135, 107, 5, 239, 244, 167, 83, 57, 49, 153, 29, 135, 108, 138, 117, - 236, 120, 65, 89, 65, 17, 201, 127, 147, 246, 103, 238, 204, 25, 83, 240, - 29, 173, 127, 140, 1, 88, 40, 43, 134, 51, 19, 125, 131, 224, 50, 167, 82, - 20, 217, 215, 162, 41, 95, 215, 56, 130, 226, 177, 216, 20, 169, 133, 85, - 140, 9, 105, 172, 54, 121, 0, 87, 202, 18, 93, 96, 147, 103, 127, 164, 63, - 197, 97, 49, 230, 125, 53, 80, 64, 20, 239, 29, 90, 118, 102, 221, 177, 6, - 220, 220, 170, 107, 107, 18, 138, 125, 138, 70, 66, 60, 185, 232, 209, 4, - 100, 17, 118, 24, 181, 110, 241, 50, 250, 138, 209, 19, 84, 220, 61, 96, - 80, 128, 81, 101, 160, 9, 5, 53, 33, 112, 60, 59, 195, 79, 115, 190, 101, - 93, 56, 171, 146, 51, 82, 233, 66, 225, 226, 211, 72, 58, 9, 74, 222, 185, - 175, 211, 156, 164, 68, 188, 119, 46, 14, 64, 160, 13, 207, 60, 81, 68, - 108, 148, 59, 88, 88, 92, 88, 171, 249, 204, 160, 137, 222, 234, 168, 233, - 3, 86, 224, 174, 105, 224, 1, 177, 184, 230, 236, 30, 85, 249, 56, 105, - 211, 50, 83, 168, 139, 28, 175, 181, 22, 89, 166, 215, 152, 218, 184, 111, - 65, 24, 82, 71, 185, 100, 172, 66, 178, 6, 215, 164, 252, 56, 40, 198, - 207, 152, 110, 186, 207, 39, 235, 179, 38, 215, 88, 105, 109, 177, 130, - 91, 5, 223, 164, 78, 241, 176, 125, 197, 94, 100, 40, 214, 251, 239, 253, - 88, 154, 14, 75, 254, 94, 210, 86, 244, 51, 95, 168, 139, 213, 73, 87, - 151, 209, 150, 126, 88, 69, 251, 116, 157, 122, 96, 212, 206, 42, 218, 38, - 85, 184, 50, 246, 188, 35, 72, 60, 226, 155, 246, 86, 209, 110, 133, 161, - 129, 126, 80, 154, 238, 64, 64, 170, 156, 177, 225, 52, 87, 42, 88, 154, - 174, 246, 30, 84, 143, 221, 51, 27, 65, 60, 40, 22, 120, 42, 145, 34, 82, - 235, 79, 20, 215, 211, 231, 151, 108, 119, 53, 116, 190, 13, 139, 199, - 189, 84, 54, 186, 222, 90, 116, 253, 227, 207, 104, 209, 118, 42, 144, 94, - 22, 219, 198, 211, 216, 171, 75, 245, 61, 240, 157, 108, 81, 19, 238, 39, - 120, 210, 242, 63, 126, 6, 15, 18, 97, 232, 207, 184, 84, 239, 72, 115, - 90, 95, 112, 78, 45, 201, 13, 102, 208, 151, 146, 253, 153, 177, 115, 14, - 194, 184, 107, 118, 120, 63, 105, 89, 144, 60, 242, 80, 106, 32, 11, 204, - 170, 165, 221, 182, 31, 187, 159, 216, 118, 218, 207, 182, 107, 136, 211, - 162, 231, 196, 128, 83, 251, 192, 189, 149, 1, 245, 36, 146, 159, 11, 116, - 30, 191, 141, 182, 157, 227, 91, 88, 72, 224, 55, 195, 96, 245, 135, 249, - 142, 16, 229, 237, 27, 60, 2, 91, 138, 82, 197, 210, 40, 8, 123, 172, 202, - 207, 119, 199, 190, 102, 40, 141, 174, 93, 211, 219, 134, 105, 26, 103, - 100, 102, 62, 130, 224, 135, 173, 82, 224, 200, 213, 76, 211, 38, 181, 16, - 97, 99, 75, 14, 42, 162, 223, 237, 141, 1, 29, 140, 191, 146, 49, 236, - 179, 88, 202, 220, 124, 239, 231, 131, 101, 134, 111, 28, 54, 151, 172, - 67, 167, 113, 96, 204, 63, 76, 169, 95, 14, 175, 149, 189, 173, 39, 177, - 102, 23, 158, 102, 236, 224, 70, 203, 190, 132, 230, 136, 3, 28, 201, 131, - 148, 164, 219, 181, 208, 26, 239, 111, 86, 35, 102, 133, 114, 113, 180, - 184, 82, 180, 106, 124, 248, 126, 87, 177, 165, 176, 204, 128, 141, 179, - 141, 34, 119, 160, 57, 206, 168, 95, 197, 110, 79, 60, 48, 170, 125, 206, - 147, 137, 156, 85, 46, 7, 193, 228, 150, 22, 46, 147, 51, 153, 157, 248, - 151, 253, 114, 58, 126, 38, 127, 19, 225, 99, 183, 235, 175, 90, 166, 8, - 233, 141, 10, 85, 232, 147, 7, 20, 137, 240, 84, 231, 86, 134, 50, 212, - 201, 6, 253, 18, 150, 114, 160, 140, 2, 254, 189, 152, 14, 68, 110, 50, - 134, 199, 73, 237, 56, 116, 110, 135, 36, 40, 14, 167, 50, 71, 81, 9, 178, - 54, 182, 247, 64, 32, 204, 116, 92, 131, 40, 30, 246, 188, 236, 182, 187, - 132, 239, 124, 136, 238, 146, 137, 247, 87, 52, 15, 78, 108, 135, 178, - 101, 70, 199, 193, 192, 144, 196, 106, 186, 141, 42, 101, 214, 196, 67, - 175, 38, 8, 189, 148, 166, 253, 221, 144, 119, 81, 1, 232, 175, 81, 237, - 13, 188, 220, 230, 47, 115, 184, 179, 0, 51, 118, 39, 22, 114, 232, 88, - 15, 121, 216, 130, 107, 173, 108, 175, 225, 113, 40, 223, 185, 6, 244, - 227, 73, 38, 64, 84, 10, 200, 53, 81, 179, 217, 106, 172, 59, 161, 70, - 180, 70, 48, 56, 46, 233, 133, 245, 57, 120, 154, 167, 49, 109, 188, 152, - 245, 181, 1, 159, 247, 44, 167, 152, 6, 191, 246, 38, 120, 141, 57, 241, - 168, 60, 38, 6, 82, 248, 87, 85, 0, 10, 22, 19, 44, 178, 63, 38, 78, 1, - 210, 166, 140, 3, 199, 112, 135, 155, 36, 13, 204, 124, 47, 5, 190, 103, - 91, 205, 147, 248, 115, 177, 196, 180, 234, 85, 35, 24, 182, 16, 207, 107, - 167, 10, 54, 193, 146, 71, 95, 45, 109, 184, 43, 101, 155, 184, 55, 171, - 196, 136, 89, 227, 84, 183, 31, 0, 137, 230, 146, 250, 6, 27, 225, 241, - 11, 95, 124, 248, 133, 171, 149, 67, 73, 19, 110, 104, 173, 86, 6, 246, - 195, 196, 200, 175, 53, 18, 198, 223, 140, 85, 208, 253, 204, 220, 255, - 232, 88, 238, 20, 97, 24, 52, 13, 3, 179, 62, 151, 101, 67, 33, 79, 253, - 157, 253, 233, 197, 109, 130, 78, 11, 165, 214, 200, 41, 157, 63, 46, 175, - 251, 246, 225, 227, 199, 92, 107, 216, 58, 124, 226, 202, 153, 92, 31, - 250, 182, 92, 99, 0, 110, 18, 78, 228, 166, 190, 67, 88, 245, 155, 139, - 82, 152, 39, 204, 74, 140, 95, 82, 82, 160, 147, 144, 33, 0, 242, 200, 22, - 102, 160, 233, 102, 224, 42, 205, 240, 56, 95, 197, 226, 175, 235, 240, - 125, 10, 51, 12, 246, 150, 234, 173, 95, 132, 173, 174, 1, 161, 23, 39, - 52, 168, 87, 54, 4, 66, 201, 34, 155, 82, 133, 170, 76, 52, 226, 109, 163, - 19, 34, 184, 226, 39, 20, 75, 72, 201, 70, 188, 71, 182, 230, 6, 19, 255, - 8, 145, 193, 63, 81, 150, 24, 72, 89, 168, 74, 98, 173, 133, 67, 227, 44, - 252, 252, 227, 192, 125, 20, 227, 144, 24, 31, 48, 67, 67, 48, 94, 163, - 52, 219, 163, 225, 214, 214, 109, 211, 122, 213, 198, 90, 204, 40, 97, - 211, 121, 17, 28, 132, 246, 110, 230, 51, 197, 42, 162, 143, 199, 158, - 215, 210, 133, 60, 65, 127, 1, 153, 193, 22, 171, 250, 114, 204, 246, 255, - 126, 25, 96, 44, 164, 102, 172, 211, 23, 245, 122, 48, 221, 249, 138, 148, - 134, 206, 135, 246, 42, 235, 198, 89, 189, 45, 125, 204, 69, 193, 48, 29, - 144, 125, 224, 127, 66, 1, 134, 141, 224, 211, 193, 141, 69, 128, 75, 167, - 244, 160, 120, 54, 191, 214, 29, 40, 249, 15, 46, 68, 141, 91, 242, 91, - 80, 252, 109, 122, 154, 64, 153, 56, 65, 254, 106, 18, 4, 172, 171, 136, - 80, 98, 79, 133, 255, 4, 100, 191, 144, 171, 219, 46, 132, 181, 130, 228, - 107, 68, 32, 123, 201, 17, 67, 35, 144, 180, 160, 30, 125, 9, 55, 184, - 172, 0, 159, 250, 232, 83, 168, 162, 102, 158, 121, 208, 177, 116, 163, - 160, 80, 241, 46, 156, 58, 203, 240, 67, 176, 244, 170, 160, 115, 122, - 141, 154, 101, 218, 178, 119, 130, 195, 32, 207, 51, 149, 98, 51, 219, 57, - 121, 216, 156, 101, 218, 184, 220, 204, 41, 181, 149, 63, 80, 194, 11, - 143, 164, 219, 23, 123, 141, 119, 43, 94, 78, 175, 89, 165, 48, 167, 44, - 45, 219, 197, 15, 202, 118, 116, 245, 151, 218, 14, 199, 96, 27, 102, 206, - 198, 123, 222, 178, 210, 20, 200, 38, 25, 124, 58, 102, 92, 197, 107, 51, - 5, 236, 125, 173, 198, 113, 144, 108, 177, 22, 104, 223, 165, 39, 9, 84, - 87, 124, 80, 153, 8, 212, 76, 2, 28, 12, 90, 212, 129, 148, 212, 229, 63, - 29, 200, 113, 171, 154, 107, 189, 202, 22, 147, 7, 32, 253, 70, 37, 224, - 98, 199, 129, 21, 54, 49, 52, 124, 84, 40, 190, 194, 108, 73, 26, 15, 124, - 87, 87, 198, 217, 122, 127, 82, 167, 131, 59, 8, 172, 49, 162, 61, 64, 79, - 196, 205, 65, 110, 75, 130, 128, 197, 182, 251, 110, 141, 197, 184, 166, - 244, 246, 217, 20, 105, 85, 42, 80, 251, 77, 59, 204, 247, 179, 218, 181, - 124, 209, 4, 28, 118, 234, 145, 237, 140, 106, 54, 88, 82, 28, 235, 68, - 221, 109, 139, 11, 166, 182, 63, 142, 194, 255, 213, 219, 116, 158, 31, - 224, 119, 126, 232, 160, 144, 1, 177, 92, 219, 162, 49, 181, 116, 163, - 104, 245, 193, 188, 26, 172, 15, 190, 135, 207, 106, 246, 13, 132, 76, - 189, 160, 25, 123, 26, 20, 48, 203, 59, 209, 69, 235, 103, 253, 160, 108, - 83, 206, 70, 98, 0, 2, 57, 162, 202, 63, 45, 89, 173, 201, 254, 254, 253, - 143, 21, 77, 131, 184, 234, 37, 68, 206, 69, 186, 179, 145, 147, 135, 42, - 137, 152, 253, 213, 240, 13, 122, 161, 218, 186, 180, 213, 162, 150, 231, - 63, 112, 182, 233, 86, 12, 225, 195, 133, 37, 28, 22, 147, 201, 200, 197, - 115, 3, 138, 194, 86, 79, 247, 27, 241, 149, 128, 197, 8, 11, 134, 53, - 118, 175, 248, 253, 114, 91, 31, 192, 253, 209, 111, 31, 228, 244, 184, - 179, 146, 145, 167, 137, 155, 184, 218, 38, 62, 187, 22, 181, 193, 93, 16, - 9, 195, 42, 198, 225, 100, 144, 148, 223, 184, 40, 117, 32, 131, 94, 93, - 83, 88, 125, 95, 220, 20, 206, 7, 228, 78, 54, 238, 178, 196, 38, 245, 95, - 8, 235, 106, 17, 175, 142, 193, 60, 179, 53, 244, 92, 147, 244, 218, 95, - 127, 251, 128, 42, 105, 82, 243, 224, 213, 25, 91, 151, 22, 201, 18, 25, - 230, 165, 85, 25, 249, 170, 160, 171, 210, 209, 32, 154, 124, 245, 60, 30, - 255, 138, 154, 29, 85, 156, 232, 177, 78, 14, 137, 52, 215, 247, 26, 211, - 115, 72, 20, 133, 232, 1, 151, 251, 63, 45, 120, 69, 49, 209, 130, 255, 2, - 218, 21, 251, 16, 86, 30, 62, 136, 92, 149, 60, 6, 125, 129, 145, 235, - 102, 190, 144, 248, 1, 53, 135, 21, 158, 44, 158, 230, 246, 172, 249, 161, - 105, 204, 49, 60, 70, 63, 127, 163, 231, 175, 174, 234, 147, 185, 62, 5, - 244, 156, 4, 31, 39, 156, 176, 154, 251, 166, 143, 212, 43, 30, 97, 50, - 37, 176, 155, 77, 149, 102, - ]), + pkcs8: mldsaKeyFixtures.pkcs8['ML-DSA-65'], + spki: mldsaKeyFixtures.spki['ML-DSA-65'], 'raw-public': hexStringToUint8Array( 'd8b1e93c9718f642afa1c07609b157e805d831fefba033d8faabe5689575876b05eff4a7533931991d876c8a75ec7841594111c97f93f667eecc1953f01dad7f8c0158282b8633137d83e032a75214d9d7a2295fd73882e2b1d814a985558c0969ac36790057ca125d6093677fa43fc56131e67d35504014ef1d5a7666ddb106dcdcaa6b6b128a7d8a46423cb9e8d10464117618b56ef132fa8ad11354dc3d6050805165a009053521703c3bc34f73be655d38ab923352e942e1e2d3483a094adeb9afd39ca444bc772e0e40a00dcf3c51446c943b58585c58abf9cca089deeaa8e90356e0ae69e001b1b8e6ec1e55f93869d33253a88b1cafb51659a6d798dab86f41185247b964ac42b206d7a4fc3828c6cf986ebacf27ebb326d758696db1825b05dfa44ef1b07dc55e6428d6fbeffd589a0e4bfe5ed256f4335fa88bd5495797d1967e5845fb749d7a60d4ce2ada2655b832f6bc23483ce29bf656d16e85a1817e509aee4040aa9cb1e134572a589aaef61e548fdd331b413c2816782a912252eb4f14d7d3e7976c773574be0d8bc7bd5436bade5a74fde3cf68d1762a905e16dbc6d3d8ab4bf53df09d6c5113ee2778d2f23f7e060f1261e8cfb854ef48735a5f704e2dc90d66d09792fd99b1730ec2b86b76783f6959903cf2506a200bccaaa5ddb61fbb9fd876dacfb66b88d3a2e7c48053fbc0bd9501f524929f0b741ebf8db69de35b5848e037c360f587f98e10e5ed1b3c025b8a52c5d228087baccacf77c7be66288dae5dd3db86691a6764663e82e087ad52e0c8d54cd326b51061634b0e2aa2dfed8d011d8cbf9231ecb358cadc7cefe78365866f1c3697ac43a77160cc3f4ca95f0eaf95bdad27b166179e66ece046cbbe84e688031cc98394a4dbb5d01aef6f562366857271b4b852b46a7cf87e57b1a5b0cc808db38d2277a039cea85fc56e4f3c30aa7dce93899c552e07c1e496162e9333999df897fd723a7e267f13e163b7ebaf5aa608e98d0a55e893071489f054e7568632d4c906fd129672a08c02febd980e446e3286c749ed38746e8724280ea732475109b236b6f74020cc745c83281ef6bcecb6bb84ef7c88ee9289f757340f4e6c87b26546c7c1c090c46aba8d2a65d6c443af2608bd94a6fddd90775101e8af51ed0dbcdce62f73b8b3003376271672e8580f79d8826bad6cafe17128dfb906f4e3492640540ac83551b3d96aac3ba146b44630382ee985f539789aa7316dbc98f5b5019ff72ca79806bff626788d39f1a83c260652f85755000a16132cb23f264e01d2a68c03c770879b240dcc7c2f05be675bcd93f873b1c4b4ea552318b610cf6ba70a36c192475f2d6db82b659bb837abc48859e354b71f0089e692fa061be1f10b5f7cf885ab954349136e68ad5606f6c3c4c8af3512c6df8c55d0fdccdcffe858ee146118340d03b33e976543214ffd9dfde9c56d824e0ba5d6c8299d3f2eaffbf6e1e3c75c6bd83a7ce2ca995c1ffab65c63006e124ee4a6be4358f59b8b529827cc4a8c5f5252a093902100f2c81666a0e966e02acdf0385fc5e2afebf07d0a330cf696eaad5f84adae01a1172734a857360442c9229b5285aa4c34e26da31322b8e227144b48c946bc47b6e60613ff0891c13f5196184859a84a62ad8543e32cfcfce3c07d14e390181f304343305ea334dba3e1d6d66dd37ad5c65acc2861d379111c84f66ee633c52aa28fc79ed7d2853c417f0199c116abfa72ccf6ff7e19602ca466acd317f57a30ddf98a9486ce87f62aebc659bd2d7dcc45c1301d907de07f4201868de0d3c18d45804ba7f4a07836bfd61d28f90f2e448d5bf25b50fc6d7a9a40993841fe6a1204acab8850624f85ff0464bf90abdb2e84b582e46b44207bc911432390b4a01e7d0937b8ac009ffae853a8a2669e79d0b174a3a050f12e9c3acbf043b0f4aaa0737a8d9a65dab27782c320cf33956233db3979d89c65dab8dccc29b5953f50c20b8fa4db177b8d772b5e4eaf59a530a72c2ddbc50fca7674f597da0ec7601b66cec67bdeb2d214c826197c3a665cc56b3305ec7dadc671906cb11668dfa5270954577c509908d44c021c0c5ad48194d4e53f1dc871ab9a6bbdca16930720fd4625e062c781153631347c5428bec26c491a0f7c5757c6d97a7f52a7833b08ac31a23d404fc4cd416e4b8280c5b6fb6e8dc5b8a6f4f6d91469552a50fb4d3bccf7b3dab57cd1041c76ea91ed8c6a3658521ceb44dd6d8b0ba6b63f8ec2ffd5db749e1fe0777ee8a09001b15cdba231b574a368f5c1bc1aac0fbe87cf6af60d844cbda0197b1a1430cb3bd145eb67fda06c53ce4662000239a2ca3f2d59adc9fefefd8f154d83b8ea2544ce45bab39193872a8998fdd5f00d7aa1dabab4d5a296e73f70b6e9560ce1c385251c1693c9c8c573038ac2564ff71bf19580c5080b863576aff8fd725b1fc0fdd16f1fe4f4b8b39291a7899bb8da263ebb16b5c15d1009c32ac6e1649094dfb8287520835e5d53587d5fdc14ce07e44e36eeb2c426f55f08eb6a11af8ec13cb335f45c93f4da5f7ffb802a6952f3e0d5195b9716c91219e6a55519f9aaa0abd2d1209a7cf53c1eff8a9a1d559ce8b14e0e8934d7f71ad373481485e80197fb3f2d784531d182ff02da15fb10561e3e885c953c067d8191eb66be90f8013587159e2c9ee6f6acf9a169cc313c463f7fa3e7afaeea93b93e05f49c041f279cb09afba68fd42b1e613225b09b4d9566' ), @@ -260,178 +42,8 @@ var keyData = { 'ML-DSA-87': { privateUsages: ['sign'], publicUsages: ['verify'], - pkcs8: new Uint8Array([ - 48, 52, 2, 1, 0, 48, 11, 6, 9, 96, 134, 72, 1, 101, 3, 4, 3, 19, 4, 34, - 128, 32, 161, 80, 109, 145, 76, 109, 101, 140, 117, 39, 228, 51, 151, 221, - 109, 76, 37, 246, 164, 121, 116, 51, 90, 76, 208, 59, 254, 105, 131, 68, - 18, 81, - ]), - spki: new Uint8Array([ - 48, 130, 10, 50, 48, 11, 6, 9, 96, 134, 72, 1, 101, 3, 4, 3, 19, 3, 130, - 10, 33, 0, 146, 184, 67, 40, 172, 27, 204, 27, 135, 22, 109, 223, 127, 23, - 97, 130, 198, 228, 199, 62, 178, 21, 173, 20, 88, 180, 205, 168, 17, 164, - 135, 92, 85, 146, 76, 194, 152, 80, 239, 157, 33, 21, 239, 182, 176, 254, - 124, 80, 135, 138, 87, 169, 103, 99, 87, 5, 91, 161, 239, 59, 18, 246, - 148, 20, 32, 60, 117, 245, 182, 156, 196, 230, 82, 117, 228, 211, 81, 45, - 115, 217, 23, 95, 138, 95, 103, 124, 32, 89, 187, 48, 251, 103, 81, 234, - 76, 4, 57, 197, 71, 48, 125, 169, 195, 147, 183, 142, 166, 8, 147, 7, 77, - 240, 111, 44, 168, 23, 89, 107, 95, 220, 75, 202, 44, 25, 244, 200, 160, - 0, 174, 111, 107, 204, 22, 36, 122, 191, 101, 33, 52, 252, 14, 47, 25, - 109, 135, 48, 131, 253, 195, 237, 60, 86, 14, 119, 85, 28, 182, 139, 136, - 191, 59, 187, 90, 126, 207, 168, 238, 184, 83, 77, 254, 208, 21, 57, 104, - 188, 228, 134, 82, 249, 190, 249, 163, 120, 111, 68, 225, 210, 131, 29, - 151, 153, 146, 71, 163, 104, 225, 194, 33, 64, 213, 92, 145, 253, 42, 32, - 233, 95, 224, 72, 184, 119, 192, 113, 253, 177, 153, 246, 240, 49, 103, - 170, 229, 82, 69, 186, 36, 252, 29, 124, 255, 25, 148, 5, 160, 159, 105, - 157, 185, 25, 158, 122, 145, 30, 245, 51, 205, 62, 56, 154, 23, 52, 0, - 225, 177, 105, 195, 131, 177, 151, 197, 114, 110, 128, 227, 127, 176, 28, - 252, 217, 56, 61, 136, 148, 190, 124, 108, 129, 62, 243, 235, 37, 70, 228, - 233, 10, 67, 124, 120, 58, 164, 83, 57, 80, 39, 204, 98, 28, 199, 136, 75, - 12, 51, 255, 24, 130, 127, 19, 239, 160, 94, 137, 75, 15, 82, 158, 252, - 163, 43, 236, 193, 234, 27, 74, 69, 14, 179, 171, 10, 169, 27, 138, 172, - 213, 189, 222, 167, 110, 24, 11, 118, 151, 223, 94, 154, 125, 9, 21, 137, - 70, 128, 51, 102, 52, 105, 104, 157, 54, 186, 75, 217, 226, 169, 71, 125, - 177, 253, 218, 85, 236, 242, 25, 215, 147, 181, 104, 242, 82, 75, 50, 165, - 49, 102, 128, 82, 237, 170, 134, 162, 196, 56, 247, 199, 138, 102, 118, - 37, 66, 114, 165, 177, 156, 251, 39, 199, 12, 167, 246, 169, 150, 108, 91, - 192, 42, 68, 192, 244, 255, 107, 18, 191, 7, 73, 19, 174, 28, 116, 66, - 131, 96, 173, 60, 131, 190, 249, 219, 246, 71, 182, 124, 183, 129, 101, - 109, 95, 180, 78, 17, 140, 182, 62, 80, 195, 184, 253, 176, 169, 153, 1, - 29, 83, 39, 252, 150, 41, 219, 176, 48, 151, 108, 60, 255, 239, 0, 85, - 101, 193, 110, 204, 12, 254, 22, 136, 15, 154, 217, 88, 13, 28, 252, 232, - 48, 32, 33, 41, 221, 103, 227, 228, 177, 54, 175, 195, 106, 174, 140, 54, - 128, 108, 214, 228, 215, 118, 226, 206, 171, 21, 155, 162, 152, 135, 203, - 16, 170, 130, 100, 173, 155, 243, 80, 40, 98, 157, 248, 7, 101, 88, 199, - 218, 224, 141, 82, 238, 121, 92, 82, 97, 49, 31, 155, 61, 63, 84, 227, 90, - 143, 164, 59, 216, 101, 19, 35, 134, 2, 20, 18, 197, 97, 215, 169, 85, - 220, 75, 254, 91, 125, 144, 43, 65, 128, 29, 66, 77, 184, 172, 89, 123, - 203, 231, 254, 59, 18, 249, 204, 249, 220, 153, 84, 166, 63, 23, 108, 120, - 145, 216, 67, 223, 123, 248, 15, 253, 63, 191, 126, 84, 95, 98, 141, 66, - 200, 129, 194, 174, 30, 80, 48, 75, 113, 14, 102, 101, 218, 249, 14, 203, - 24, 6, 11, 89, 99, 56, 49, 17, 148, 160, 242, 101, 191, 102, 227, 115, 33, - 107, 71, 235, 6, 141, 68, 161, 162, 165, 227, 159, 82, 253, 54, 157, 214, - 255, 141, 151, 154, 134, 150, 93, 141, 97, 158, 244, 180, 135, 42, 10, 3, - 148, 9, 152, 149, 20, 18, 237, 253, 180, 136, 165, 13, 80, 195, 220, 43, - 3, 178, 10, 127, 144, 2, 207, 209, 246, 40, 110, 38, 133, 9, 22, 180, 11, - 223, 116, 236, 205, 186, 25, 183, 155, 165, 77, 206, 101, 255, 106, 223, - 70, 10, 22, 176, 119, 142, 163, 197, 178, 251, 216, 112, 237, 63, 201, 77, - 219, 196, 2, 176, 48, 15, 207, 91, 74, 236, 21, 8, 205, 126, 77, 28, 13, - 26, 28, 202, 250, 100, 79, 134, 209, 193, 78, 202, 58, 248, 124, 215, 64, - 143, 244, 17, 23, 163, 162, 241, 249, 49, 210, 168, 203, 213, 135, 77, 14, - 29, 35, 193, 234, 58, 12, 106, 165, 163, 251, 192, 115, 251, 7, 198, 189, - 93, 207, 178, 246, 50, 189, 185, 51, 45, 84, 140, 194, 34, 46, 92, 90, - 136, 81, 81, 53, 52, 253, 128, 247, 131, 243, 21, 207, 245, 141, 49, 178, - 213, 214, 211, 8, 17, 234, 133, 225, 104, 197, 186, 224, 117, 1, 173, 104, - 17, 177, 161, 223, 71, 195, 159, 194, 45, 177, 116, 26, 187, 193, 161, - 213, 179, 158, 8, 122, 186, 122, 191, 158, 5, 12, 178, 235, 78, 132, 78, - 189, 16, 86, 110, 73, 51, 129, 255, 242, 110, 63, 6, 53, 209, 110, 132, - 236, 43, 239, 192, 221, 138, 1, 128, 176, 0, 113, 85, 119, 201, 36, 188, - 202, 9, 223, 98, 196, 42, 130, 158, 149, 200, 150, 202, 132, 118, 153, 97, - 54, 195, 154, 15, 45, 246, 129, 144, 255, 231, 75, 25, 56, 47, 178, 98, - 10, 106, 84, 56, 113, 161, 227, 37, 246, 1, 245, 129, 173, 70, 186, 11, - 28, 125, 198, 243, 225, 113, 130, 5, 138, 52, 251, 194, 152, 105, 48, 214, - 13, 246, 228, 75, 236, 194, 223, 177, 64, 150, 97, 167, 20, 27, 74, 76, - 166, 199, 239, 91, 240, 8, 22, 54, 41, 63, 35, 112, 255, 251, 88, 252, - 147, 173, 185, 43, 98, 83, 155, 230, 176, 55, 161, 8, 83, 15, 110, 151, - 241, 110, 168, 203, 190, 198, 218, 152, 144, 150, 58, 123, 11, 123, 250, - 104, 113, 198, 93, 1, 152, 51, 172, 140, 246, 115, 113, 229, 218, 166, - 200, 35, 123, 16, 133, 169, 191, 59, 103, 12, 114, 15, 60, 37, 4, 92, 208, - 54, 31, 79, 56, 225, 6, 11, 74, 107, 79, 225, 239, 16, 73, 249, 234, 197, - 129, 230, 97, 39, 115, 49, 96, 141, 41, 242, 225, 177, 214, 18, 103, 34, - 229, 37, 176, 241, 99, 82, 227, 195, 77, 32, 64, 4, 120, 49, 199, 209, - 139, 2, 4, 222, 233, 45, 151, 141, 142, 252, 41, 124, 231, 13, 144, 63, - 212, 252, 145, 34, 142, 232, 152, 84, 135, 87, 175, 46, 53, 139, 60, 168, - 135, 167, 101, 253, 127, 152, 138, 154, 31, 231, 198, 77, 89, 182, 9, 54, - 103, 119, 100, 218, 245, 44, 191, 74, 30, 152, 84, 22, 62, 159, 131, 163, - 223, 3, 51, 194, 241, 49, 9, 213, 43, 214, 201, 75, 158, 198, 22, 203, - 209, 190, 199, 189, 75, 4, 6, 72, 60, 241, 113, 171, 30, 42, 143, 73, 51, - 72, 206, 110, 175, 203, 195, 199, 15, 155, 208, 166, 121, 26, 132, 59, 44, - 72, 155, 7, 48, 122, 132, 224, 142, 3, 7, 21, 207, 11, 30, 112, 18, 149, - 146, 127, 41, 104, 197, 169, 86, 213, 108, 253, 111, 160, 5, 11, 202, 172, - 233, 32, 5, 52, 92, 124, 152, 162, 11, 88, 28, 166, 248, 141, 251, 38, - 161, 53, 49, 136, 246, 183, 85, 9, 165, 115, 108, 18, 208, 218, 129, 165, - 163, 131, 34, 32, 94, 226, 121, 93, 24, 87, 226, 105, 25, 242, 128, 198, - 78, 26, 237, 21, 92, 33, 121, 8, 119, 131, 140, 193, 14, 60, 139, 130, 19, - 65, 96, 50, 5, 249, 12, 27, 51, 23, 195, 89, 255, 47, 23, 109, 62, 202, - 190, 5, 131, 92, 91, 39, 27, 209, 132, 146, 95, 98, 66, 26, 230, 186, 236, - 186, 162, 149, 81, 143, 221, 21, 79, 171, 236, 21, 161, 19, 135, 10, 213, - 168, 200, 135, 19, 221, 177, 207, 106, 214, 194, 124, 220, 53, 45, 176, - 245, 178, 189, 49, 242, 22, 230, 154, 241, 146, 230, 187, 180, 244, 158, - 145, 197, 225, 51, 150, 140, 26, 175, 78, 142, 243, 232, 221, 137, 205, - 130, 178, 54, 216, 136, 118, 212, 33, 90, 206, 18, 224, 158, 44, 23, 144, - 204, 24, 184, 48, 81, 233, 124, 20, 222, 77, 119, 144, 22, 145, 241, 19, - 206, 135, 252, 164, 114, 84, 37, 175, 107, 67, 243, 183, 137, 213, 53, - 236, 41, 73, 50, 34, 146, 218, 204, 68, 235, 158, 150, 139, 133, 75, 248, - 157, 7, 0, 53, 68, 44, 156, 110, 56, 197, 209, 201, 0, 155, 225, 85, 35, - 169, 193, 231, 36, 31, 142, 101, 168, 29, 192, 31, 128, 81, 191, 253, 184, - 153, 226, 214, 1, 27, 6, 0, 192, 36, 101, 72, 105, 150, 226, 3, 21, 12, - 127, 72, 250, 223, 240, 136, 249, 157, 129, 247, 91, 178, 157, 208, 86, - 146, 23, 176, 150, 35, 211, 155, 22, 207, 119, 168, 167, 122, 180, 183, - 106, 97, 138, 87, 96, 34, 141, 110, 145, 231, 226, 35, 115, 232, 129, 54, - 186, 128, 190, 238, 37, 169, 194, 37, 24, 237, 211, 164, 111, 54, 88, 245, - 125, 67, 78, 194, 11, 194, 235, 217, 87, 203, 14, 220, 189, 107, 68, 94, - 139, 66, 230, 5, 54, 64, 28, 246, 143, 75, 127, 239, 243, 20, 251, 189, - 246, 246, 151, 90, 219, 227, 242, 223, 205, 40, 124, 245, 4, 189, 72, 39, - 145, 110, 96, 120, 164, 27, 117, 146, 177, 30, 76, 173, 106, 130, 228, - 192, 189, 59, 167, 30, 127, 178, 164, 5, 133, 80, 199, 207, 216, 189, 156, - 93, 222, 150, 129, 81, 193, 180, 38, 59, 8, 214, 210, 95, 150, 182, 175, - 148, 43, 153, 169, 66, 62, 135, 140, 159, 89, 195, 253, 3, 132, 180, 164, - 244, 243, 232, 71, 196, 200, 158, 194, 114, 115, 193, 88, 161, 185, 235, - 247, 14, 126, 225, 176, 111, 17, 79, 77, 245, 80, 229, 174, 6, 180, 156, - 217, 85, 174, 201, 255, 237, 85, 83, 53, 188, 153, 98, 91, 193, 21, 211, - 49, 145, 196, 252, 52, 66, 226, 131, 203, 214, 130, 237, 194, 208, 174, - 102, 133, 220, 235, 222, 79, 232, 36, 21, 161, 248, 51, 185, 164, 156, 95, - 121, 65, 57, 233, 183, 29, 199, 105, 104, 12, 90, 195, 186, 81, 199, 176, - 1, 87, 16, 226, 192, 206, 185, 197, 46, 34, 75, 174, 153, 238, 15, 50, 87, - 226, 96, 26, 197, 202, 73, 235, 19, 140, 9, 79, 12, 52, 83, 76, 85, 146, - 234, 24, 151, 179, 178, 118, 58, 162, 223, 103, 69, 244, 231, 135, 167, - 204, 117, 166, 60, 237, 82, 63, 11, 4, 207, 10, 146, 54, 126, 191, 79, - 133, 60, 128, 34, 136, 170, 23, 84, 81, 38, 94, 9, 130, 245, 100, 115, - 209, 34, 228, 158, 101, 216, 135, 208, 207, 191, 169, 115, 252, 144, 139, - 226, 252, 6, 44, 221, 134, 170, 87, 11, 46, 124, 58, 219, 179, 238, 6, 98, - 216, 18, 174, 42, 12, 97, 126, 85, 245, 81, 220, 232, 135, 114, 21, 125, - 135, 225, 182, 245, 228, 223, 242, 62, 158, 35, 76, 6, 110, 25, 184, 206, - 124, 237, 54, 252, 199, 44, 78, 89, 0, 135, 44, 176, 57, 168, 36, 221, - 173, 77, 214, 209, 60, 1, 202, 238, 237, 61, 90, 47, 114, 230, 92, 238, - 235, 18, 151, 220, 243, 225, 163, 159, 139, 189, 253, 62, 225, 182, 202, - 59, 7, 83, 99, 129, 118, 175, 37, 246, 85, 119, 251, 246, 69, 180, 247, - 37, 24, 194, 89, 158, 97, 230, 247, 254, 145, 102, 89, 77, 68, 245, 3, - 103, 83, 28, 45, 168, 30, 189, 151, 112, 120, 215, 84, 90, 198, 85, 85, - 129, 55, 127, 124, 28, 137, 229, 139, 54, 88, 229, 105, 81, 212, 83, 28, - 107, 250, 82, 164, 43, 24, 15, 57, 206, 156, 19, 145, 95, 57, 169, 8, 128, - 211, 29, 213, 195, 148, 27, 73, 186, 221, 242, 11, 167, 78, 246, 133, 18, - 118, 67, 236, 59, 19, 112, 254, 93, 168, 157, 118, 0, 107, 248, 57, 149, - 67, 222, 123, 225, 207, 251, 69, 218, 56, 110, 162, 19, 25, 209, 209, 213, - 200, 158, 70, 9, 100, 208, 77, 48, 255, 151, 200, 0, 68, 230, 70, 120, - 209, 29, 86, 225, 188, 189, 226, 101, 42, 176, 32, 147, 121, 72, 151, 130, - 217, 13, 66, 148, 84, 129, 215, 249, 164, 174, 187, 80, 85, 185, 245, 108, - 169, 119, 59, 178, 144, 229, 63, 194, 132, 250, 131, 82, 161, 125, 126, - 255, 252, 220, 204, 104, 231, 201, 136, 246, 116, 43, 88, 233, 0, 43, 128, - 214, 40, 59, 81, 147, 139, 132, 69, 24, 233, 21, 14, 91, 230, 241, 19, - 138, 163, 55, 13, 221, 47, 64, 140, 248, 6, 38, 164, 16, 219, 63, 33, 180, - 71, 151, 0, 234, 103, 58, 213, 222, 163, 95, 132, 1, 178, 146, 66, 124, - 242, 223, 102, 129, 192, 214, 194, 117, 162, 252, 246, 143, 42, 70, 139, - 97, 168, 64, 141, 190, 115, 126, 93, 175, 59, 49, 9, 184, 88, 201, 100, - 182, 142, 145, 244, 72, 128, 203, 49, 196, 5, 5, 18, 46, 34, 87, 171, 132, - 158, 128, 75, 194, 8, 242, 52, 156, 229, 245, 56, 245, 88, 14, 195, 110, - 166, 51, 158, 245, 195, 120, 17, 166, 66, 100, 212, 188, 243, 2, 236, 90, - 8, 16, 35, 151, 122, 175, 115, 168, 186, 191, 60, 71, 23, 81, 217, 79, - 203, 239, 61, 146, 247, 168, 112, 83, 102, 146, 222, 178, 45, 247, 63, 23, - 181, 3, 136, 208, 62, 154, 203, 35, 250, 238, 61, 98, 207, 90, 169, 175, - 36, 227, 9, 182, 78, 226, 99, 89, 67, 105, 185, 35, 242, 162, 54, 99, 60, - 148, 14, 118, 1, 26, 120, 62, 82, 62, 222, 34, 99, 58, 174, 145, 199, 190, - 21, 182, 117, 238, 13, 170, 29, 67, 149, 44, 90, 94, 181, 125, 182, 186, - 82, 55, 105, 253, 29, 212, 67, 134, 204, 227, 94, 255, 127, 72, 157, 140, - 142, 224, 77, 149, 29, 170, 45, 163, 214, 209, 46, 28, 125, 177, 111, 2, - 92, 121, 252, 166, 204, 227, 173, 51, 60, 162, 243, 202, 207, 103, 30, - 153, 182, 116, 182, 130, 98, 59, 25, 141, 239, 49, 224, 176, 27, 237, 218, - 76, 68, 189, 108, 185, 136, 255, 105, 150, 11, 153, 44, 248, 139, 199, - 178, 235, 85, 115, 121, 144, 87, 221, 50, 222, 238, 16, 20, 51, 190, 93, - 248, 228, 84, 228, 115, 31, 229, 227, 137, 180, 44, 115, 224, 119, 129, - 181, 134, 224, 144, 186, 123, 208, 118, 96, 101, 177, 191, 232, 171, 6, - 17, 247, 187, 173, 84, 70, 249, 19, 191, 116, 172, 126, 131, 216, 123, - 225, 151, 55, 205, 177, 93, 139, 117, - ]), + pkcs8: mldsaKeyFixtures.pkcs8['ML-DSA-87'], + spki: mldsaKeyFixtures.spki['ML-DSA-87'], 'raw-public': hexStringToUint8Array( '92b84328ac1bcc1b87166ddf7f176182c6e4c73eb215ad1458b4cda811a4875c55924cc29850ef9d2115efb6b0fe7c50878a57a9676357055ba1ef3b12f69414203c75f5b69cc4e65275e4d3512d73d9175f8a5f677c2059bb30fb6751ea4c0439c547307da9c393b78ea60893074df06f2ca817596b5fdc4bca2c19f4c8a000ae6f6bcc16247abf652134fc0e2f196d873083fdc3ed3c560e77551cb68b88bf3bbb5a7ecfa8eeb8534dfed0153968bce48652f9bef9a3786f44e1d2831d97999247a368e1c22140d55c91fd2a20e95fe048b877c071fdb199f6f03167aae55245ba24fc1d7cff199405a09f699db9199e7a911ef533cd3e389a173400e1b169c383b197c5726e80e37fb01cfcd9383d8894be7c6c813ef3eb2546e4e90a437c783aa453395027cc621cc7884b0c33ff18827f13efa05e894b0f529efca32becc1ea1b4a450eb3ab0aa91b8aacd5bddea76e180b7697df5e9a7d091589468033663469689d36ba4bd9e2a9477db1fdda55ecf219d793b568f2524b32a531668052edaa86a2c438f7c78a6676254272a5b19cfb27c70ca7f6a9966c5bc02a44c0f4ff6b12bf074913ae1c74428360ad3c83bef9dbf647b67cb781656d5fb44e118cb63e50c3b8fdb0a999011d5327fc9629dbb030976c3cffef005565c16ecc0cfe16880f9ad9580d1cfce830202129dd67e3e4b136afc36aae8c36806cd6e4d776e2ceab159ba29887cb10aa8264ad9bf35028629df8076558c7dae08d52ee795c5261311f9b3d3f54e35a8fa43bd865132386021412c561d7a955dc4bfe5b7d902b41801d424db8ac597bcbe7fe3b12f9ccf9dc9954a63f176c7891d843df7bf80ffd3fbf7e545f628d42c881c2ae1e50304b710e6665daf90ecb18060b596338311194a0f265bf66e373216b47eb068d44a1a2a5e39f52fd369dd6ff8d979a86965d8d619ef4b4872a0a03940998951412edfdb488a50d50c3dc2b03b20a7f9002cfd1f6286e26850916b40bdf74eccdba19b79ba54dce65ff6adf460a16b0778ea3c5b2fbd870ed3fc94ddbc402b0300fcf5b4aec1508cd7e4d1c0d1a1ccafa644f86d1c14eca3af87cd7408ff41117a3a2f1f931d2a8cbd5874d0e1d23c1ea3a0c6aa5a3fbc073fb07c6bd5dcfb2f632bdb9332d548cc2222e5c5a8851513534fd80f783f315cff58d31b2d5d6d30811ea85e168c5bae07501ad6811b1a1df47c39fc22db1741abbc1a1d5b39e087aba7abf9e050cb2eb4e844ebd10566e493381fff26e3f0635d16e84ec2befc0dd8a0180b000715577c924bcca09df62c42a829e95c896ca8476996136c39a0f2df68190ffe74b19382fb2620a6a543871a1e325f601f581ad46ba0b1c7dc6f3e17182058a34fbc2986930d60df6e44becc2dfb1409661a7141b4a4ca6c7ef5bf0081636293f2370fffb58fc93adb92b62539be6b037a108530f6e97f16ea8cbbec6da9890963a7b0b7bfa6871c65d019833ac8cf67371e5daa6c8237b1085a9bf3b670c720f3c25045cd0361f4f38e1060b4a6b4fe1ef1049f9eac581e661277331608d29f2e1b1d6126722e525b0f16352e3c34d2040047831c7d18b0204dee92d978d8efc297ce70d903fd4fc91228ee898548757af2e358b3ca887a765fd7f988a9a1fe7c64d59b60936677764daf52cbf4a1e9854163e9f83a3df0333c2f13109d52bd6c94b9ec616cbd1bec7bd4b0406483cf171ab1e2a8f493348ce6eafcbc3c70f9bd0a6791a843b2c489b07307a84e08e030715cf0b1e701295927f2968c5a956d56cfd6fa0050bcaace92005345c7c98a20b581ca6f88dfb26a1353188f6b75509a5736c12d0da81a5a38322205ee2795d1857e26919f280c64e1aed155c21790877838cc10e3c8b821341603205f90c1b3317c359ff2f176d3ecabe05835c5b271bd184925f62421ae6baecbaa295518fdd154fabec15a113870ad5a8c88713ddb1cf6ad6c27cdc352db0f5b2bd31f216e69af192e6bbb4f49e91c5e133968c1aaf4e8ef3e8dd89cd82b236d88876d4215ace12e09e2c1790cc18b83051e97c14de4d77901691f113ce87fca4725425af6b43f3b789d535ec2949322292dacc44eb9e968b854bf89d070035442c9c6e38c5d1c9009be15523a9c1e7241f8e65a81dc01f8051bffdb899e2d6011b0600c02465486996e203150c7f48fadff088f99d81f75bb29dd0569217b09623d39b16cf77a8a77ab4b76a618a5760228d6e91e7e22373e88136ba80beee25a9c22518edd3a46f3658f57d434ec20bc2ebd957cb0edcbd6b445e8b42e60536401cf68f4b7feff314fbbdf6f6975adbe3f2dfcd287cf504bd4827916e6078a41b7592b11e4cad6a82e4c0bd3ba71e7fb2a4058550c7cfd8bd9c5dde968151c1b4263b08d6d25f96b6af942b99a9423e878c9f59c3fd0384b4a4f4f3e847c4c89ec27273c158a1b9ebf70e7ee1b06f114f4df550e5ae06b49cd955aec9ffed555335bc99625bc115d33191c4fc3442e283cbd682edc2d0ae6685dcebde4fe82415a1f833b9a49c5f794139e9b71dc769680c5ac3ba51c7b0015710e2c0ceb9c52e224bae99ee0f3257e2601ac5ca49eb138c094f0c34534c5592ea1897b3b2763aa2df6745f4e787a7cc75a63ced523f0b04cf0a92367ebf4f853c802288aa175451265e0982f56473d122e49e65d887d0cfbfa973fc908be2fc062cdd86aa570b2e7c3adbb3ee0662d812ae2a0c617e55f551dce88772157d87e1b6f5e4dff23e9e234c066e19b8ce7ced36fcc72c4e5900872cb039a824ddad4dd6d13c01caeeed3d5a2f72e65ceeeb1297dcf3e1a39f8bbdfd3ee1b6ca3b0753638176af25f65577fbf645b4f72518c2599e61e6f7fe9166594d44f50367531c2da81ebd977078d7545ac6555581377f7c1c89e58b3658e56951d4531c6bfa52a42b180f39ce9c13915f39a90880d31dd5c3941b49baddf20ba74ef685127643ec3b1370fe5da89d76006bf8399543de7be1cffb45da386ea21319d1d1d5c89e460964d04d30ff97c80044e64678d11d56e1bcbde2652ab0209379489782d90d42945481d7f9a4aebb5055b9f56ca9773bb290e53fc284fa8352a17d7efffcdccc68e7c988f6742b58e9002b80d6283b51938b844518e9150e5be6f1138aa3370ddd2f408cf80626a410db3f21b4479700ea673ad5dea35f8401b292427cf2df6681c0d6c275a2fcf68f2a468b61a8408dbe737e5daf3b3109b858c964b68e91f44880cb31c40505122e2257ab849e804bc208f2349ce5f538f5580ec36ea6339ef5c37811a64264d4bcf302ec5a081023977aaf73a8babf3c471751d94fcbef3d92f7a870536692deb22df73f17b50388d03e9acb23faee3d62cf5aa9af24e309b64ee263594369b923f2a236633c940e76011a783e523ede22633aae91c7be15b675ee0daa1d43952c5a5eb57db6ba523769fd1dd44386cce35eff7f489d8c8ee04d951daa2da3d6d12e1c7db16f025c79fca6cce3ad333ca2f3cacf671e99b674b682623b198def31e0b01bedda4c44bd6cb988ff69960b992cf88bc7b2eb5573799057dd32deee101433be5df8e454e4731fe5e389b42c73e07781b586e090ba7bd0766065b1bfe8ab0611f7bbad5446f913bf74ac7e83d87be19737cdb15d8b75' ), diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/ML-KEM_importKey.js b/test/fixtures/wpt/WebCryptoAPI/import_export/ML-KEM_importKey.js deleted file mode 100644 index d9257ac69825..000000000000 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/ML-KEM_importKey.js +++ /dev/null @@ -1,130 +0,0 @@ -var subtle = crypto.subtle; - -function runTests(algorithmName) { - var algorithm = { name: algorithmName }; - var data = keyData[algorithmName]; - var jwkData = { - jwk: { kty: data.jwk.kty, alg: data.jwk.alg, pub: data.jwk.pub }, - }; - - [true, false].forEach(function (extractable) { - // Test public keys first - allValidUsages(data.publicUsages, true).forEach(function (usages) { - ['spki', 'jwk', 'raw-public'].forEach(function (format) { - if (format === 'jwk') { - // Not all fields used for public keys - testFormat( - format, - algorithm, - jwkData, - algorithmName, - usages, - extractable - ); - } else { - testFormat( - format, - algorithm, - data, - algorithmName, - usages, - extractable - ); - } - }); - }); - - // Next, test private keys - allValidUsages(data.privateUsages).forEach(function (usages) { - ['pkcs8', 'jwk', 'raw-seed'].forEach(function (format) { - testFormat(format, algorithm, data, algorithmName, usages, extractable); - }); - }); - }); -} - -// Test importKey with a given key format and other parameters. If -// extrable is true, export the key and verify that it matches the input. -function testFormat(format, algorithm, keyData, keySize, usages, extractable) { - [algorithm, algorithm.name].forEach((alg) => { - promise_test(function (test) { - return subtle - .importKey(format, keyData[format], alg, extractable, usages) - .then( - function (key) { - assert_equals( - key.constructor, - CryptoKey, - 'Imported a CryptoKey object' - ); - assert_goodCryptoKey( - key, - algorithm, - extractable, - usages, - format === 'pkcs8' || - format === 'raw-seed' || - (format === 'jwk' && keyData[format].priv) - ? 'private' - : 'public' - ); - if (!extractable) { - return; - } - - return subtle.exportKey(format, key).then( - function (result) { - if (format !== 'jwk') { - assert_true( - equalBuffers(keyData[format], result), - 'Round trip works' - ); - } else { - assert_true( - equalJwk(keyData[format], result), - 'Round trip works' - ); - } - }, - function (err) { - assert_unreached( - 'Threw an unexpected error: ' + err.toString() - ); - } - ); - }, - function (err) { - assert_unreached('Threw an unexpected error: ' + err.toString()); - } - ); - }, 'Good parameters: ' + - keySize.toString() + - ' bits ' + - parameterString(format, keyData[format], alg, extractable, usages)); - }); -} - -// Helper methods follow: - -// Convert method parameters to a string to uniquely name each test -function parameterString(format, data, algorithm, extractable, usages) { - if ('byteLength' in data) { - data = 'buffer(' + data.byteLength.toString() + ')'; - } else { - data = 'object(' + Object.keys(data).join(', ') + ')'; - } - var result = - '(' + - objectToString(format) + - ', ' + - objectToString(data) + - ', ' + - objectToString(algorithm) + - ', ' + - objectToString(extractable) + - ', ' + - objectToString(usages) + - ')'; - - return result; -} diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/ML-KEM_importKey.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/import_export/ML-KEM_importKey.tentative.https.any.js index 8b459c17e2d3..11d80c76bc55 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/ML-KEM_importKey.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/ML-KEM_importKey.tentative.https.any.js @@ -2,7 +2,7 @@ // META: timeout=long // META: script=../util/helpers.js // META: script=ML-KEM_importKey_fixtures.js -// META: script=ML-KEM_importKey.js +// META: script=ml_importKey.js runTests("ML-KEM-512"); runTests("ML-KEM-768"); diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey.https.any.js b/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey.https.any.js index 3b78bab4e741..473fab2887e7 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey.https.any.js @@ -1,6 +1,7 @@ // META: title=WebCryptoAPI: importKey() for EC keys // META: timeout=long // META: script=../util/helpers.js +// META: script=../util/ec_key_fixtures.js // Test importKey and exportKey for EC algorithms. Only "happy paths" are // currently tested - those where the operation should succeed. @@ -9,56 +10,7 @@ var curves = ['P-256', 'P-384', 'P-521']; - var keyData = { - "P-521": { - spki: new Uint8Array([48, 129, 155, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 3, 129, 134, 0, 4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56, 251]), - spki_compressed: new Uint8Array([48, 88, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 3, 68, 0, 3, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63]), - raw: new Uint8Array([4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56, 251]), - raw_compressed: new Uint8Array([3, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63]), - pkcs8: new Uint8Array([48, 129, 238, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 4, 129, 214, 48, 129, 211, 2, 1, 1, 4, 66, 0, 244, 8, 117, 131, 104, 186, 147, 15, 48, 247, 106, 224, 84, 254, 92, 210, 206, 127, 218, 44, 159, 118, 166, 212, 54, 207, 117, 214, 108, 68, 11, 254, 99, 49, 199, 193, 114, 161, 36, 120, 25, 60, 130, 81, 72, 123, 201, 18, 99, 250, 80, 33, 127, 133, 255, 99, 111, 89, 205, 84, 110, 58, 180, 131, 180, 161, 129, 137, 3, 129, 134, 0, 4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56, 251]), - pkcs8_private_only: new Uint8Array([48, 96, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 4, 73, 48, 71, 2, 1, 1, 4, 66, 0, 244, 8, 117, 131, 104, 186, 147, 15, 48, 247, 106, 224, 84, 254, 92, 210, 206, 127, 218, 44, 159, 118, 166, 212, 54, 207, 117, 214, 108, 68, 11, 254, 99, 49, 199, 193, 114, 161, 36, 120, 25, 60, 130, 81, 72, 123, 201, 18, 99, 250, 80, 33, 127, 133, 255, 99, 111, 89, 205, 84, 110, 58, 180, 131, 180]), - jwk: { - kty: "EC", - crv: "P-521", - x: "AVb0efjfHiCn_8BM5CDD4VSuJRmWvuQvA0uE1Bt0PzTkXzEbgTqc3sjNpZu7vTHUYLMpJSHnwbci5WZ8A9svrnU_", - y: "AVAXNs_iRzlDINjkr8L9ObWpMxBhuB4iQSgrnheJGCK1t54FL0WXtZZD_Tk3nFG9USXE9IvD8CXOPNNpUyhsyzj7", - d: "APQIdYNoupMPMPdq4FT-XNLOf9osn3am1DbPddZsRAv-YzHHwXKhJHgZPIJRSHvJEmP6UCF_hf9jb1nNVG46tIO0" - } - }, - - "P-256": { - spki: new Uint8Array([48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97, 232]), - spki_compressed: new Uint8Array([48, 57, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 34, 0, 2, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209]), - raw: new Uint8Array([4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97, 232]), - raw_compressed: new Uint8Array([2, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209]), - pkcs8: new Uint8Array([48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 19, 211, 58, 45, 90, 191, 156, 249, 235, 178, 31, 248, 96, 212, 174, 254, 110, 86, 231, 119, 144, 244, 222, 233, 180, 8, 132, 235, 211, 53, 68, 234, 161, 68, 3, 66, 0, 4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97, 232]), - pkcs8_private_only: new Uint8Array([48, 65, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 4, 39, 48, 37, 2, 1, 1, 4, 32, 19, 211, 58, 45, 90, 191, 156, 249, 235, 178, 31, 248, 96, 212, 174, 254, 110, 86, 231, 119, 144, 244, 222, 233, 180, 8, 132, 235, 211, 53, 68, 234]), - jwk: { - kty: "EC", - crv: "P-256", - x: "0hCwpvnZ8BKGgFi0P6T0cQGFQ7ugDJJQ35JXwqyuXdE", - y: "zgN1UtSBRQzjm00QlXAbF1v6s0uObAmeGPHBmDWDYeg", - d: "E9M6LVq_nPnrsh_4YNSu_m5W53eQ9N7ptAiE69M1ROo" - } - }, - - "P-384": { - spki: new Uint8Array([48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172, 232]), - spki_compressed: new Uint8Array([48, 70, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 50, 0, 2, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53]), - raw: new Uint8Array([4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172, 232]), - raw_compressed: new Uint8Array([2, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53]), - pkcs8: new Uint8Array([48, 129, 182, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 4, 129, 158, 48, 129, 155, 2, 1, 1, 4, 48, 69, 55, 181, 153, 7, 132, 211, 194, 210, 46, 150, 168, 249, 47, 161, 170, 73, 46, 232, 115, 229, 118, 164, 21, 130, 225, 68, 24, 60, 152, 136, 209, 14, 107, 158, 180, 206, 212, 178, 204, 64, 18, 228, 172, 94, 168, 64, 115, 161, 100, 3, 98, 0, 4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172, 232]), - pkcs8_private_only: new Uint8Array([48, 78, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 4, 55, 48, 53, 2, 1, 1, 4, 48, 69, 55, 181, 153, 7, 132, 211, 194, 210, 46, 150, 168, 249, 47, 161, 170, 73, 46, 232, 115, 229, 118, 164, 21, 130, 225, 68, 24, 60, 152, 136, 209, 14, 107, 158, 180, 206, 212, 178, 204, 64, 18, 228, 172, 94, 168, 64, 115]), - jwk: { - kty: "EC", - crv: "P-384", - x: "IZwU1mYXs27G2IVrOFtzp000T9iude8EZDXdpU47RL1fvevR0I3Wni19wdwhjLQ1", - y: "vSgTjMd4M3qEL2vWGyQOdCSfJGZ8KlgQp2v8KOAzX4imUB3sAZdtqFr7AIactqzo", - d: "RTe1mQeE08LSLpao-S-hqkku6HPldqQVguFEGDyYiNEOa560ztSyzEAS5KxeqEBz" - } - }, - - }; + var keyData = ecKeyData; // combinations to test var testVectors = [ diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey_failures_ECDH.https.any.js b/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey_failures_ECDH.https.any.js index 423d399f19de..260e49791a51 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey_failures_ECDH.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey_failures_ECDH.https.any.js @@ -1,6 +1,7 @@ // META: title=WebCryptoAPI: importKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=../util/ec_key_fixtures.js // META: script=ec_importKey_failures_fixtures.js // META: script=importKey_failures.js diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey_failures_ECDSA.https.any.js b/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey_failures_ECDSA.https.any.js index 527940798a42..96116d5462df 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey_failures_ECDSA.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey_failures_ECDSA.https.any.js @@ -1,6 +1,7 @@ // META: title=WebCryptoAPI: importKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=../util/ec_key_fixtures.js // META: script=ec_importKey_failures_fixtures.js // META: script=importKey_failures.js diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey_failures_fixtures.js b/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey_failures_fixtures.js index dc0e11d551a9..a37a72cb28d5 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey_failures_fixtures.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey_failures_fixtures.js @@ -1,17 +1,41 @@ -// Setup: define the correct behaviors that should be sought, and create -// helper functions that generate all possible test parameters for -// different situations. +function ecPrivateJwk(namedCurve) { + return Object.assign({}, ecKeyData[namedCurve].jwk); +} + function getValidKeyData(algorithm) { - return validKeyData[algorithm.namedCurve]; + var key = ecKeyData[algorithm.namedCurve]; + return [ + {format: "spki", data: key.spki}, + {format: "raw", data: key.raw}, + {format: "pkcs8", data: key.pkcs8}, + {format: "jwk", data: ecPrivateJwk(algorithm.namedCurve)} + ]; } function getBadKeyLengthData(algorithm) { - return badKeyLengthData[algorithm.namedCurve]; + var key = ecKeyData[algorithm.namedCurve]; + var jwk = ecPrivateJwk(algorithm.namedCurve); + jwk.x = jwk.x.slice(0, -1); + return [ + {format: "spki", data: key.spki.slice(0, -1)}, + {format: "raw", data: key.raw.slice(0, -1)}, + {format: "pkcs8", data: key.pkcs8.slice(0, -1)}, + {format: "jwk", data: jwk} + ]; } function getMissingJWKFieldKeyData(algorithm) { - // The curve doesn't affect when testing for missing JWK fields. - return missingJWKFieldKeyData["P-521"]; + var missingX = ecPrivateJwk("P-521"); + var missingKty = ecPrivateJwk("P-521"); + var missingCrv = ecPrivateJwk("P-521"); + delete missingX.x; + delete missingKty.kty; + delete missingCrv.crv; + return [ + {param: "x", data: missingX}, + {param: "kty", data: missingKty}, + {param: "crv", data: missingCrv} + ]; } function getMismatchedJWKKeyData(algorithm) { @@ -20,206 +44,15 @@ function getMismatchedJWKKeyData(algorithm) { } function getMismatchedKtyField(algorithm) { - return mismatchedKtyField[algorithm.namedCurve]; + return "OKP"; } function getMismatchedCrvField(algorithm) { - return mismatchedCrvField[algorithm.namedCurve]; -} - -var validKeyData = { - "P-521": [ - { - format: "spki", - data: new Uint8Array([48, 129, 155, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 3, 129, 134, 0, 4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56, 251]), - }, - { - format: "raw", - data: new Uint8Array([4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56, 251]), - }, - { - format:"pkcs8", - data: new Uint8Array([48, 129, 238, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 4, 129, 214, 48, 129, 211, 2, 1, 1, 4, 66, 0, 244, 8, 117, 131, 104, 186, 147, 15, 48, 247, 106, 224, 84, 254, 92, 210, 206, 127, 218, 44, 159, 118, 166, 212, 54, 207, 117, 214, 108, 68, 11, 254, 99, 49, 199, 193, 114, 161, 36, 120, 25, 60, 130, 81, 72, 123, 201, 18, 99, 250, 80, 33, 127, 133, 255, 99, 111, 89, 205, 84, 110, 58, 180, 131, 180, 161, 129, 137, 3, 129, 134, 0, 4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56, 251]), - }, - { - format: "jwk", - data: { - kty: "EC", - crv: "P-521", - x: "AVb0efjfHiCn_8BM5CDD4VSuJRmWvuQvA0uE1Bt0PzTkXzEbgTqc3sjNpZu7vTHUYLMpJSHnwbci5WZ8A9svrnU_", - y: "AVAXNs_iRzlDINjkr8L9ObWpMxBhuB4iQSgrnheJGCK1t54FL0WXtZZD_Tk3nFG9USXE9IvD8CXOPNNpUyhsyzj7", - d: "APQIdYNoupMPMPdq4FT-XNLOf9osn3am1DbPddZsRAv-YzHHwXKhJHgZPIJRSHvJEmP6UCF_hf9jb1nNVG46tIO0" - } - } - ], - "P-256": [ - { - format: "spki", - data: new Uint8Array([48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97, 232]), - }, - { - format: "raw", - data: new Uint8Array([4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97, 232]), - }, - { - format: "pkcs8", - data: new Uint8Array([48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 19, 211, 58, 45, 90, 191, 156, 249, 235, 178, 31, 248, 96, 212, 174, 254, 110, 86, 231, 119, 144, 244, 222, 233, 180, 8, 132, 235, 211, 53, 68, 234, 161, 68, 3, 66, 0, 4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97, 232]), - }, - { - format: "jwk", - data: { - kty: "EC", - crv: "P-256", - x: "0hCwpvnZ8BKGgFi0P6T0cQGFQ7ugDJJQ35JXwqyuXdE", - y: "zgN1UtSBRQzjm00QlXAbF1v6s0uObAmeGPHBmDWDYeg", - d: "E9M6LVq_nPnrsh_4YNSu_m5W53eQ9N7ptAiE69M1ROo" - } - }, - ], - "P-384": [ - { - format: "spki", - data: new Uint8Array([48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172, 232]), - }, - { - format: "raw", - data: new Uint8Array([4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172, 232]), - }, - { - format: "pkcs8", - data: new Uint8Array([48, 129, 182, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 4, 129, 158, 48, 129, 155, 2, 1, 1, 4, 48, 69, 55, 181, 153, 7, 132, 211, 194, 210, 46, 150, 168, 249, 47, 161, 170, 73, 46, 232, 115, 229, 118, 164, 21, 130, 225, 68, 24, 60, 152, 136, 209, 14, 107, 158, 180, 206, 212, 178, 204, 64, 18, 228, 172, 94, 168, 64, 115, 161, 100, 3, 98, 0, 4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172, 232]), - }, - { - format: "jwk", - data: { - kty: "EC", - crv: "P-384", - x: "IZwU1mYXs27G2IVrOFtzp000T9iude8EZDXdpU47RL1fvevR0I3Wni19wdwhjLQ1", - y: "vSgTjMd4M3qEL2vWGyQOdCSfJGZ8KlgQp2v8KOAzX4imUB3sAZdtqFr7AIactqzo", - d: "RTe1mQeE08LSLpao-S-hqkku6HPldqQVguFEGDyYiNEOa560ztSyzEAS5KxeqEBz" - } - } - ] -}; - -// Removed just the last byte. -var badKeyLengthData = { - "P-521": [ - { - format: "spki", - data: new Uint8Array([48, 129, 155, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 3, 129, 134, 0, 4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56]), - }, - { - format: "raw", - data: new Uint8Array([4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56]), - }, - { - format:"pkcs8", - data: new Uint8Array([48, 129, 238, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 4, 129, 214, 48, 129, 211, 2, 1, 1, 4, 66, 0, 244, 8, 117, 131, 104, 186, 147, 15, 48, 247, 106, 224, 84, 254, 92, 210, 206, 127, 218, 44, 159, 118, 166, 212, 54, 207, 117, 214, 108, 68, 11, 254, 99, 49, 199, 193, 114, 161, 36, 120, 25, 60, 130, 81, 72, 123, 201, 18, 99, 250, 80, 33, 127, 133, 255, 99, 111, 89, 205, 84, 110, 58, 180, 131, 180, 161, 129, 137, 3, 129, 134, 0, 4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56]), - }, - { - format: "jwk", - data: { - kty: "EC", - crv: "P-521", - x: "AVb0efjfHiCn_8BM5CDD4VSuJRmWvuQvA0uE1Bt0PzTkXzEbgTqc3sjNpZu7vTHUYLMpJSHnwbci5WZ8A9svrnU", - y: "AVAXNs_iRzlDINjkr8L9ObWpMxBhuB4iQSgrnheJGCK1t54FL0WXtZZD_Tk3nFG9USXE9IvD8CXOPNNpUyhsyzj7", - d: "APQIdYNoupMPMPdq4FT-XNLOf9osn3am1DbPddZsRAv-YzHHwXKhJHgZPIJRSHvJEmP6UCF_hf9jb1nNVG46tIO0" - } - } - ], - "P-256": [ - { - format: "spki", - data: new Uint8Array([48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97]), - }, - { - format: "raw", - data: new Uint8Array([4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97]), - }, - { - format: "pkcs8", - data: new Uint8Array([48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 19, 211, 58, 45, 90, 191, 156, 249, 235, 178, 31, 248, 96, 212, 174, 254, 110, 86, 231, 119, 144, 244, 222, 233, 180, 8, 132, 235, 211, 53, 68, 234, 161, 68, 3, 66, 0, 4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97]), - }, - { - format: "jwk", - data: { - kty: "EC", - crv: "P-256", - x: "0hCwpvnZ8BKGgFi0P6T0cQGFQ7ugDJJQ35JXwqyuXd", - y: "zgN1UtSBRQzjm00QlXAbF1v6s0uObAmeGPHBmDWDYeg", - d: "E9M6LVq_nPnrsh_4YNSu_m5W53eQ9N7ptAiE69M1ROo" - } - }, - ], - "P-384": [ - { - format: "spki", - data: new Uint8Array([48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172]), - }, - { - format: "raw", - data: new Uint8Array([4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172]), - }, - { - format: "pkcs8", - data: new Uint8Array([48, 129, 182, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 4, 129, 158, 48, 129, 155, 2, 1, 1, 4, 48, 69, 55, 181, 153, 7, 132, 211, 194, 210, 46, 150, 168, 249, 47, 161, 170, 73, 46, 232, 115, 229, 118, 164, 21, 130, 225, 68, 24, 60, 152, 136, 209, 14, 107, 158, 180, 206, 212, 178, 204, 64, 18, 228, 172, 94, 168, 64, 115, 161, 100, 3, 98, 0, 4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172]), - }, - { - format: "jwk", - data: { - kty: "EC", - crv: "P-384", - x: "IZwU1mYXs27G2IVrOFtzp000T9iude8EZDXdpU47RL1fvevR0I3Wni19wdwhjLQ", - y: "vSgTjMd4M3qEL2vWGyQOdCSfJGZ8KlgQp2v8KOAzX4imUB3sAZdtqFr7AIactqzo", - d: "RTe1mQeE08LSLpao-S-hqkku6HPldqQVguFEGDyYiNEOa560ztSyzEAS5KxeqEBz" - } - } - ] -}; - -var missingJWKFieldKeyData = { - "P-521": [ - { - param: "x", - data: { - kty: "EC", - crv: "P-521", - y: "AVAXNs_iRzlDINjkr8L9ObWpMxBhuB4iQSgrnheJGCK1t54FL0WXtZZD_Tk3nFG9USXE9IvD8CXOPNNpUyhsyzj7", - d: "APQIdYNoupMPMPdq4FT-XNLOf9osn3am1DbPddZsRAv-YzHHwXKhJHgZPIJRSHvJEmP6UCF_hf9jb1nNVG46tIO0" - } - }, - { - param: "kty", - data: { - crv: "P-521", - x: "AVb0efjfHiCn_8BM5CDD4VSuJRmWvuQvA0uE1Bt0PzTkXzEbgTqc3sjNpZu7vTHUYLMpJSHnwbci5WZ8A9svrnU_", - y: "AVAXNs_iRzlDINjkr8L9ObWpMxBhuB4iQSgrnheJGCK1t54FL0WXtZZD_Tk3nFG9USXE9IvD8CXOPNNpUyhsyzj7", - d: "APQIdYNoupMPMPdq4FT-XNLOf9osn3am1DbPddZsRAv-YzHHwXKhJHgZPIJRSHvJEmP6UCF_hf9jb1nNVG46tIO0" - } - }, - { - param: "crv", - data: { - kty: "EC", - x: "AVb0efjfHiCn_8BM5CDD4VSuJRmWvuQvA0uE1Bt0PzTkXzEbgTqc3sjNpZu7vTHUYLMpJSHnwbci5WZ8A9svrnU_", - y: "AVAXNs_iRzlDINjkr8L9ObWpMxBhuB4iQSgrnheJGCK1t54FL0WXtZZD_Tk3nFG9USXE9IvD8CXOPNNpUyhsyzj7", - d: "APQIdYNoupMPMPdq4FT-XNLOf9osn3am1DbPddZsRAv-YzHHwXKhJHgZPIJRSHvJEmP6UCF_hf9jb1nNVG46tIO0" - } - } - ] -}; - -// The 'kty' field doesn't match the key algorithm. -var mismatchedKtyField = { - "P-521": "OKP", - "P-256": "OKP", - "P-384": "OKP", + return mismatchedEcCurves[algorithm.namedCurve]; } -// The 'kty' field doesn't match the key algorithm. -var mismatchedCrvField = { +var mismatchedEcCurves = { "P-521": "P-256", "P-256": "P-384", - "P-384": "P-521", -} + "P-384": "P-521" +}; diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/importKey_failures.js b/test/fixtures/wpt/WebCryptoAPI/import_export/importKey_failures.js index f45da96cf6b0..7581614f0dcb 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/importKey_failures.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/importKey_failures.js @@ -1,8 +1,6 @@ function run_test(algorithmNames) { var subtle = crypto.subtle; // Change to test prefixed implementations - setup({explicit_timeout: true}); - // These tests check that importKey and exportKey throw an error, and that // the error is of the right type, for a wide set of incorrect parameters. @@ -79,16 +77,15 @@ function run_test(algorithmNames) { }, testTag + ": importKey" + parameterString(format, algorithm, extractable, usages, keyData)); } - // Don't create an exhaustive list of all invalid usages, - // because there would usually be nearly 2**8 of them, - // way too many to test. Instead, create every singleton + // Don't create an exhaustive list of all invalid usages because + // there would be too many to test. Instead, create every singleton // of an illegal usage, and "poison" every valid usage // with an illegal one. function invalidUsages(validUsages, mandatoryUsages) { var results = []; var illegalUsages = []; - ["encrypt", "decrypt", "sign", "verify", "wrapKey", "unwrapKey", "deriveKey", "deriveBits"].forEach(function(usage) { + allKeyUsages.forEach(function(usage) { if (!validUsages.includes(usage)) { illegalUsages.push(usage); } diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/ML-DSA_importKey.js b/test/fixtures/wpt/WebCryptoAPI/import_export/ml_importKey.js similarity index 98% rename from test/fixtures/wpt/WebCryptoAPI/import_export/ML-DSA_importKey.js rename to test/fixtures/wpt/WebCryptoAPI/import_export/ml_importKey.js index d9257ac69825..a33c3a85b912 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/ML-DSA_importKey.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/ml_importKey.js @@ -1,5 +1,6 @@ var subtle = crypto.subtle; +// Shared ML-DSA and ML-KEM import/export tests. function runTests(algorithmName) { var algorithm = { name: algorithmName }; var data = keyData[algorithmName]; diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_Ed25519.https.any.js b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_Ed25519.https.any.js index 49656489d425..b6b378651951 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_Ed25519.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_Ed25519.https.any.js @@ -1,6 +1,7 @@ // META: title=WebCryptoAPI: importKey() for OKP keys // META: timeout=long // META: script=../util/helpers.js +// META: script=../util/okp_key_fixtures.js // META: script=okp_importKey_fixtures.js // META: script=okp_importKey.js diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_Ed448.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_Ed448.tentative.https.any.js index 5bb7460c1fbc..8498ce4ef8f3 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_Ed448.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_Ed448.tentative.https.any.js @@ -1,6 +1,7 @@ // META: title=WebCryptoAPI: importKey() for OKP keys // META: timeout=long // META: script=../util/helpers.js +// META: script=../util/okp_key_fixtures.js // META: script=okp_importKey_fixtures.js // META: script=okp_importKey.js diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_X25519.https.any.js b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_X25519.https.any.js index de1431d6cc24..5d629c082730 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_X25519.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_X25519.https.any.js @@ -1,6 +1,7 @@ // META: title=WebCryptoAPI: importKey() for OKP keys // META: timeout=long // META: script=../util/helpers.js +// META: script=../util/okp_key_fixtures.js // META: script=okp_importKey_fixtures.js // META: script=okp_importKey.js diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_X448.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_X448.tentative.https.any.js index f8552be3c826..09361ed9b8d6 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_X448.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_X448.tentative.https.any.js @@ -1,6 +1,7 @@ // META: title=WebCryptoAPI: importKey() for OKP keys // META: timeout=long // META: script=../util/helpers.js +// META: script=../util/okp_key_fixtures.js // META: script=okp_importKey_fixtures.js // META: script=okp_importKey.js diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed25519.https.any.js b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed25519.https.any.js index e07b796df83d..0b541d77016f 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed25519.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed25519.https.any.js @@ -1,6 +1,7 @@ // META: title=WebCryptoAPI: importKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=../util/okp_key_fixtures.js // META: script=okp_importKey_failures_fixtures.js // META: script=importKey_failures.js diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.tentative.https.any.js index 8ff3de5c79d3..726d5c1e3772 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.tentative.https.any.js @@ -1,6 +1,7 @@ // META: title=WebCryptoAPI: importKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=../util/okp_key_fixtures.js // META: script=okp_importKey_failures_fixtures.js // META: script=importKey_failures.js diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X25519.https.any.js b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X25519.https.any.js index a0116bee8885..d4c9c105bc3b 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X25519.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X25519.https.any.js @@ -1,6 +1,7 @@ // META: title=WebCryptoAPI: importKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=../util/okp_key_fixtures.js // META: script=okp_importKey_failures_fixtures.js // META: script=importKey_failures.js diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.tentative.https.any.js index eccce68fac73..2b575d7ab4d7 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.tentative.https.any.js @@ -1,6 +1,7 @@ // META: title=WebCryptoAPI: importKey() for Failures // META: timeout=long // META: script=../util/helpers.js +// META: script=../util/okp_key_fixtures.js // META: script=okp_importKey_failures_fixtures.js // META: script=importKey_failures.js diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_fixtures.js b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_fixtures.js index 6a7f583e0165..01c65d60d44d 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_fixtures.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_fixtures.js @@ -1,438 +1,85 @@ -// Setup: define the correct behaviors that should be sought, and create -// helper functions that generate all possible test parameters for -// different situations. +function algorithmName(algorithm) { + return algorithm.name || algorithm; +} + +function privateJwk(name) { + return Object.assign({}, okpKeyData[name].jwk); +} + +function publicJwk(name) { + var jwk = privateJwk(name); + delete jwk.d; + return jwk; +} + function getValidKeyData(algorithm) { - return validKeyData[algorithm.name || algorithm]; + var name = algorithmName(algorithm); + var key = okpKeyData[name]; + return [ + {format: "spki", data: key.spki}, + {format: "pkcs8", data: key.pkcs8}, + {format: "raw", data: key.raw}, + {format: "jwk", data: privateJwk(name)}, + {format: "jwk", data: publicJwk(name)} + ]; } function getBadKeyLengthData(algorithm) { - return badKeyLengthData[algorithm.name || algorithm]; + var name = algorithmName(algorithm); + var key = okpKeyData[name]; + var badPrivateJwk = privateJwk(name); + var badPublicJwk = publicJwk(name); + badPrivateJwk.d = badPrivateJwk.d.slice(0, -1); + badPublicJwk.x = badPublicJwk.x.slice(0, -1); + return [ + {format: "spki", data: key.spki.slice(0, -1)}, + {format: "pkcs8", data: key.pkcs8.slice(0, -1)}, + {format: "raw", data: key.raw.slice(0, -1)}, + {format: "jwk", data: badPrivateJwk}, + {format: "jwk", data: badPublicJwk} + ]; } function getMissingJWKFieldKeyData(algorithm) { - return missingJWKFieldKeyData[algorithm.name || algorithm]; + var name = algorithmName(algorithm); + var missingX = privateJwk(name); + var missingKty = privateJwk(name); + var missingCrv = name === "Ed448" ? privateJwk(name) : publicJwk(name); + delete missingX.x; + delete missingKty.kty; + delete missingCrv.crv; + return [ + {param: "x", data: missingX}, + {param: "kty", data: missingKty}, + {param: "crv", data: missingCrv} + ]; } function getMismatchedJWKKeyData(algorithm) { - return mismatchedJWKKeyData[algorithm.name || algorithm]; + var name = algorithmName(algorithm); + var jwk = privateJwk(name); + jwk.x = mismatchedPublicKeys[name]; + return [jwk]; } function getMismatchedKtyField(algorithm) { - return mismatchedKtyField[algorithm.name || algorithm]; + return "EC"; } function getMismatchedCrvField(algorithm) { - return mismatchedCrvField[algorithm.name || algorithm]; + return mismatchedCurves[algorithmName(algorithm)]; } -var validKeyData = { - "Ed25519": [ - { - format: "spki", - data: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 112, 3, 33, 0, 216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61, 204]) - }, - { - format: "pkcs8", - data: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32, 243, 200, 244, 196, 141, 248, 120, 20, 110, 140, 211, 191, 109, 244, 229, 14, 56, 155, 167, 7, 78, 21, 194, 53, 45, 205, 93, 48, 141, 76, 168, 31]) - }, - { - format: "raw", - data: new Uint8Array([216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61, 204]) - }, - { - format: "jwk", - data: { - crv: "Ed25519", - d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8", - x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPcw", - kty: "OKP" - }, - }, - { - format: "jwk", - data: { - crv: "Ed25519", - x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPcw", - kty: "OKP" - }, - } - ], - "Ed448": [ - { - format: "spki", - data: new Uint8Array([48, 67, 48, 5, 6, 3, 43, 101, 113, 3, 58, 0, 171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90, 128]), - }, - { - format: "pkcs8", - data: new Uint8Array([48, 71, 2, 1, 0, 48, 5, 6, 3, 43, 101, 113, 4, 59, 4, 57, 14, 255, 3, 69, 140, 40, 224, 23, 156, 82, 29, 227, 18, 201, 105, 183, 131, 67, 72, 236, 171, 153, 26, 96, 227, 178, 233, 167, 158, 76, 217, 228, 128, 239, 41, 23, 18, 210, 200, 61, 4, 114, 114, 213, 201, 244, 40, 102, 79, 105, 109, 38, 112, 69, 143, 29, 46]), - }, - { - format: "raw", - data: new Uint8Array([171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90, 128]), - }, - { - format: "jwk", - data: { - crv: "Ed448", - d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u", - x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA", - kty: "OKP" - }, - }, - { - format: "jwk", - data: { - crv: "Ed448", - x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA", - kty: "OKP" - }, - }, - ], - "X25519": [ - { - format: "spki", - data: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151, 6]), - }, - { - format: "pkcs8", - data: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 110, 4, 34, 4, 32, 200, 131, 142, 118, 208, 87, 223, 183, 216, 201, 90, 105, 225, 56, 22, 10, 221, 99, 115, 253, 113, 164, 210, 118, 187, 86, 227, 168, 27, 100, 255, 97]), - }, - { - format: "raw", - data: new Uint8Array([28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151, 6]), - }, - { - format: "jwk", - data: { - crv: "X25519", - d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2E", - x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY", - kty: "OKP" - }, - }, - { - format: "jwk", - data: { - crv: "X25519", - x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY", - kty: "OKP" - }, - }, - ], - "X448": [ - { - format: "spki", - data: new Uint8Array([48, 66, 48, 5, 6, 3, 43, 101, 111, 3, 57, 0, 182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206, 111]), - }, - { - format: "pkcs8", - data: new Uint8Array([48, 70, 2, 1, 0, 48, 5, 6, 3, 43, 101, 111, 4, 58, 4, 56, 88, 199, 210, 154, 62, 181, 25, 178, 157, 0, 207, 177, 145, 187, 100, 252, 109, 138, 66, 216, 241, 113, 118, 39, 43, 137, 242, 39, 45, 24, 25, 41, 92, 101, 37, 192, 130, 150, 113, 176, 82, 239, 7, 39, 83, 15, 24, 142, 49, 208, 204, 83, 191, 38, 146, 158]), - }, - { - format: "raw", - data: new Uint8Array([182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206, 111]), - }, - { - format: "jwk", - data: { - crv: "X448", - d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp4", - x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8", - kty: "OKP" - }, - }, - { - format: "jwk", - data: { - crv: "X448", - x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8", - kty: "OKP" - }, - }, - ], -}; - -// Removed just the last byte. -var badKeyLengthData = { - "Ed25519": [ - { - format: "spki", - data: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 112, 3, 33, 0, 216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61]) - }, - { - format: "pkcs8", - data: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32, 243, 200, 244, 196, 141, 248, 120, 20, 110, 140, 211, 191, 109, 244, 229, 14, 56, 155, 167, 7, 78, 21, 194, 53, 45, 205, 93, 48, 141, 76, 168]) - }, - { - format: "raw", - data: new Uint8Array([216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61]) - }, - { - format: "jwk", - data: { - crv: "Ed25519", - d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB", - x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPcw", - kty: "OKP" - } - }, - { - format: "jwk", - data: { - crv: "Ed25519", - x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPc", - kty: "OKP" - } - } - ], - "Ed448": [ - { - format: "spki", - data: new Uint8Array([48, 67, 48, 5, 6, 3, 43, 101, 113, 3, 58, 0, 171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90]), - }, - { - format: "pkcs8", - data: new Uint8Array([48, 71, 2, 1, 0, 48, 5, 6, 3, 43, 101, 113, 4, 59, 4, 57, 14, 255, 3, 69, 140, 40, 224, 23, 156, 82, 29, 227, 18, 201, 105, 183, 131, 67, 72, 236, 171, 153, 26, 96, 227, 178, 233, 167, 158, 76, 217, 228, 128, 239, 41, 23, 18, 210, 200, 61, 4, 114, 114, 213, 201, 244, 40, 102, 79, 105, 109, 38, 112, 69, 143, 29]), - }, - { - format: "raw", - data: new Uint8Array([171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90]), - }, - { - format: "jwk", - data: { - crv: "Ed448", - d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0", - x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA", - kty: "OKP" - }, - }, - { - format: "jwk", - data: { - crv: "Ed448", - x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalq", - kty: "OKP" - }, - }, - ], - "X25519": [ - { - format: "spki", - data: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151]), - }, - { - format: "pkcs8", - data: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 110, 4, 34, 4, 32, 200, 131, 142, 118, 208, 87, 223, 183, 216, 201, 90, 105, 225, 56, 22, 10, 221, 99, 115, 253, 113, 164, 210, 118, 187, 86, 227, 168, 27, 100, 255]), - }, - { - format: "raw", - data: new Uint8Array([28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151]), - }, - { - format: "jwk", - data: { - crv: "X25519", - x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lw", - kty: "OKP" - } - }, - { - format: "jwk", - data: { - crv: "X25519", - d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2", - x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY", - kty: "OKP" - }, - }, - ], - "X448": [ - { - format: "spki", - data: new Uint8Array([48, 66, 48, 5, 6, 3, 43, 101, 111, 3, 57, 0, 182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206]), - }, - { - format: "pkcs8", - data: new Uint8Array([48, 70, 2, 1, 0, 48, 5, 6, 3, 43, 101, 111, 4, 58, 4, 56, 88, 199, 210, 154, 62, 181, 25, 178, 157, 0, 207, 177, 145, 187, 100, 252, 109, 138, 66, 216, 241, 113, 118, 39, 43, 137, 242, 39, 45, 24, 25, 41, 92, 101, 37, 192, 130, 150, 113, 176, 82, 239, 7, 39, 83, 15, 24, 142, 49, 208, 204, 83, 191, 38, 146]), - }, - { - format: "raw", - data: new Uint8Array([182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206]), - }, - { - format: "jwk", - data: { - crv: "X448", - d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp", - x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8", - kty: "OKP" - }, - }, - { - format: "jwk", - data: { - crv: "X448", - x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm", - kty: "OKP" - }, - }, - ], +var mismatchedPublicKeys = { + "Ed25519": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", + "Ed448": "X9dEm1m0Yf0s54fsYWrUah2hNCSFpw4fig6nXYDpZ3jt8SR2m0bHBhvWeD3x5Q9s0foavq_oJWGA", + "X25519": "hSDwCYkwp1R0i33ctD73Wg2_Og0mOBr066SpjqqbTmo", + "X448": "mwj3zDG34+Z9ItWuoSEHSic70rg94Jxj+qc9LCLF2bvINmRyQdlT1AxbEtqIEg1TF3+A5TLEH6A" }; -var missingJWKFieldKeyData = { - "Ed25519": [ - { - param: "x", - data: { - crv: "Ed25519", - d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8", - kty: "OKP" - }, - }, - { - param: "kty", - data: { - crv: "Ed25519", - x: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", - d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8", - }, - }, - { - param: "crv", - data: { - x: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", - kty: "OKP" - }, - } - ], - "Ed448": [ - { - param: "x", - data: { - crv: "Ed448", - d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u", - kty: "OKP" - } - }, - { - param: "kty", - data: { - crv: "Ed448", - d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u", - x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA", - } - }, - { - param: "crv", - data: { - d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u", - x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA", - kty: "OKP" - } - } - ], - "X25519": [ - { - param: "x", - data: { - crv: "X25519", - d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2E", - kty: "OKP" - }, - }, - { - param: "kty", - data: { - crv: "X25519", - d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2E", - x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY", - }, - }, - { - param: "crv", - data: { - x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY", - kty: "OKP" - }, - } - ], - "X448": [ - { - param: "x", - data: { - crv: "X448", - d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp4", - kty: "OKP" - } - }, - { - param: "kty", - data: { - crv: "X448", - d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp4", - x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8", - } - }, - { - param: "crv", - data: { - x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8", - kty: "OKP" - } - } - ], -}; - -// The public key doesn't match the private key. -var mismatchedJWKKeyData = { - "Ed25519": [ - { - crv: "Ed25519", - d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8", - x: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", - kty: "OKP" - }, - ], - "Ed448": [ - { - crv: "Ed448", - d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u", - x: "X9dEm1m0Yf0s54fsYWrUah2hNCSFpw4fig6nXYDpZ3jt8SR2m0bHBhvWeD3x5Q9s0foavq_oJWGA", - kty: "OKP" - }, - ], - "X25519": [ - { - crv: "X25519", - d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2E", - x: "hSDwCYkwp1R0i33ctD73Wg2_Og0mOBr066SpjqqbTmo", - kty: "OKP" - }, - ], - "X448": [ - { - - crv: "X448", - kty: "OKP", - d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp4", - x: "mwj3zDG34+Z9ItWuoSEHSic70rg94Jxj+qc9LCLF2bvINmRyQdlT1AxbEtqIEg1TF3+A5TLEH6A", - }, - ], -} - -// The 'kty' field doesn't match the key algorithm. -var mismatchedKtyField = { - "Ed25519": "EC", - "X25519": "EC", - "Ed448": "EC", - "X448": "EC", -} - -// The 'kty' field doesn't match the key algorithm. -var mismatchedCrvField = { +var mismatchedCurves = { "Ed25519": "X25519", "X25519": "Ed25519", "Ed448": "X448", - "X448": "Ed448", -} + "X448": "Ed448" +}; diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_fixtures.js b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_fixtures.js index 58b41d52601e..5fe0f05c42b4 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_fixtures.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_fixtures.js @@ -1,58 +1 @@ -var keyData = { - "Ed25519": { - privateUsages: ["sign"], - publicUsages: ["verify"], - spki: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 112, 3, 33, 0, 216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61, 204]), - raw: new Uint8Array([216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61, 204]), - pkcs8: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32, 243, 200, 244, 196, 141, 248, 120, 20, 110, 140, 211, 191, 109, 244, 229, 14, 56, 155, 167, 7, 78, 21, 194, 53, 45, 205, 93, 48, 141, 76, 168, 31]), - jwk: { - crv: "Ed25519", - d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8", - x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPcw", - kty: "OKP" - } - }, - - "Ed448": { - privateUsages: ["sign"], - publicUsages: ["verify"], - spki: new Uint8Array([48, 67, 48, 5, 6, 3, 43, 101, 113, 3, 58, 0, 171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90, 128]), - raw: new Uint8Array([171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90, 128]), - pkcs8: new Uint8Array([48, 71, 2, 1, 0, 48, 5, 6, 3, 43, 101, 113, 4, 59, 4, 57, 14, 255, 3, 69, 140, 40, 224, 23, 156, 82, 29, 227, 18, 201, 105, 183, 131, 67, 72, 236, 171, 153, 26, 96, 227, 178, 233, 167, 158, 76, 217, 228, 128, 239, 41, 23, 18, 210, 200, 61, 4, 114, 114, 213, 201, 244, 40, 102, 79, 105, 109, 38, 112, 69, 143, 29, 46]), - jwk: { - crv: "Ed448", - d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u", - x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA", - kty: "OKP" - } - }, - - "X25519": { - privateUsages: ["deriveKey", "deriveBits"], - publicUsages: [], - spki: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151, 6]), - raw: new Uint8Array([28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151, 6]), - pkcs8: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 110, 4, 34, 4, 32, 200, 131, 142, 118, 208, 87, 223, 183, 216, 201, 90, 105, 225, 56, 22, 10, 221, 99, 115, 253, 113, 164, 210, 118, 187, 86, 227, 168, 27, 100, 255, 97]), - jwk: { - crv: "X25519", - d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2E", - x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY", - kty: "OKP" - } - }, - - "X448": { - privateUsages: ["deriveKey", "deriveBits"], - publicUsages: [], - spki: new Uint8Array([48, 66, 48, 5, 6, 3, 43, 101, 111, 3, 57, 0, 182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206, 111]), - raw: new Uint8Array([182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206, 111]), - pkcs8: new Uint8Array([48, 70, 2, 1, 0, 48, 5, 6, 3, 43, 101, 111, 4, 58, 4, 56, 88, 199, 210, 154, 62, 181, 25, 178, 157, 0, 207, 177, 145, 187, 100, 252, 109, 138, 66, 216, 241, 113, 118, 39, 43, 137, 242, 39, 45, 24, 25, 41, 92, 101, 37, 192, 130, 150, 113, 176, 82, 239, 7, 39, 83, 15, 24, 142, 49, 208, 204, 83, 191, 38, 146, 158]), - jwk: { - crv: "X448", - d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp4", - x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8", - kty: "OKP" - } - }, - -}; +var keyData = okpKeyData; diff --git a/test/fixtures/wpt/WebCryptoAPI/sign_verify/ecdsa.https.any.js b/test/fixtures/wpt/WebCryptoAPI/sign_verify/ecdsa.https.any.js index 3f1e2e5ea9d8..2af5e05048e4 100644 --- a/test/fixtures/wpt/WebCryptoAPI/sign_verify/ecdsa.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/sign_verify/ecdsa.https.any.js @@ -1,6 +1,7 @@ // META: title=WebCryptoAPI: sign() and verify() Using ECDSA // META: script=../util/helpers.js // META: script=ecdsa_vectors.js +// META: script=signature.js // META: script=ecdsa.js // META: timeout=long diff --git a/test/fixtures/wpt/WebCryptoAPI/sign_verify/ecdsa.js b/test/fixtures/wpt/WebCryptoAPI/sign_verify/ecdsa.js index cc13b1bd9c3c..a1a744aaa824 100644 --- a/test/fixtures/wpt/WebCryptoAPI/sign_verify/ecdsa.js +++ b/test/fixtures/wpt/WebCryptoAPI/sign_verify/ecdsa.js @@ -1,658 +1,71 @@ - function run_test() { - setup({explicit_done: true}); - - var subtle = self.crypto.subtle; // Change to test prefixed implementations - - // When are all these tests really done? When all the promises they use have resolved. - var all_promises = []; - - // Source file [algorithm_name]_vectors.js provides the getTestVectors method - // for the algorithm that drives these tests. - var testVectors = getTestVectors(); - var invalidTestVectors = getInvalidTestVectors(); - - // Test verification first, because signing tests rely on that working - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName, hash: vector.hashName}; - promise_test(function(test) { - var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification"); - }); - - all_promises.push(promise); - }); - - // Test verification with an altered buffer during call - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - var signature = copyBuffer(vector.signature); - signature[0] = 255 - signature[0]; - var algorithm = { - hash: vector.hashName, - get name() { - signature[0] = vector.signature[0]; - return vector.algorithmName; - } - }; - var operation = subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification with altered signature during call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification with altered signature during call"); - }); - - all_promises.push(promise); - }); - - // Test verification with an altered buffer after call - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName, hash: vector.hashName}; - promise_test(function(test) { - var signature = copyBuffer(vector.signature); - var operation = subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - signature[0] = 255 - signature[0]; - return operation; - }, vector.name + " verification with altered signature after call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification with altered signature after call"); - }); - - all_promises.push(promise); - }); - - // Test verification with a transferred buffer during call - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - var signature = copyBuffer(vector.signature); - var algorithm = { - get name() { - signature.buffer.transfer(); - return vector.algorithmName; - }, - hash: vector.hashName - }; - var operation = subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature is NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification with transferred signature during call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification with transferred signature during call"); - }); - - all_promises.push(promise); - }); - - // Test verification with a transferred buffer after call - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName, hash: vector.hashName}; - promise_test(function(test) { - var signature = copyBuffer(vector.signature); - var operation = subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - signature.buffer.transfer(); - return operation; - }, vector.name + " verification with transferred signature after call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification with transferred signature after call"); - }); - - all_promises.push(promise); - }); - - // Check for successful verification even if plaintext is altered during call. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - var plaintext = copyBuffer(vector.plaintext); - plaintext[0] = 255 - plaintext[0]; - var algorithm = { - hash: vector.hashName, - get name() { - plaintext[0] = vector.plaintext[0]; - return vector.algorithmName; - } - }; - var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " with altered plaintext during call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " with altered plaintext during call"); - }); - - all_promises.push(promise); - }); - - // Check for successful verification even if plaintext is altered after call. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName, hash: vector.hashName}; - promise_test(function(test) { - var plaintext = copyBuffer(vector.plaintext); - var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - plaintext[0] = 255 - plaintext[0]; - return operation; - }, vector.name + " with altered plaintext after call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " with altered plaintext after call"); - }); - - all_promises.push(promise); - }); - - // Check for failed verification if plaintext is transferred during call. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - var plaintext = copyBuffer(vector.plaintext); - var algorithm = { - get name() { - plaintext.buffer.transfer(); - return vector.algorithmName; - }, - hash: vector.hashName - }; - var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature is NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " with transferred plaintext during call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " with transferred plaintext during call"); - }); - - all_promises.push(promise); - }); - - // Check for successful verification even if plaintext is transferred after call. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName, hash: vector.hashName}; - promise_test(function(test) { - var plaintext = copyBuffer(vector.plaintext); - var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - plaintext.buffer.transfer(); - return operation; - }, vector.name + " with transferred plaintext after call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " with transferred plaintext after call"); - }); - - all_promises.push(promise); - }); - - // Check for failures due to using privateKey to verify. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName, hash: vector.hashName}; - promise_test(function(test) { - return subtle.verify(algorithm, vector.privateKey, vector.signature, vector.plaintext) - .then(function(plaintext) { - assert_unreached("Should have thrown error for using privateKey to verify in " + vector.name + ": '" + err.message + "'"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); - }); - }, vector.name + " using privateKey to verify"); - - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " using privateKey to verify"); - }); - - all_promises.push(promise); - }); - - // Check for failures due to using publicKey to sign. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName, hash: vector.hashName}; - promise_test(function(test) { - return subtle.sign(algorithm, vector.publicKey, vector.plaintext) - .then(function(signature) { - assert_unreached("Should have thrown error for using publicKey to sign in " + vector.name + ": '" + err.message + "'"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); - }); - }, vector.name + " using publicKey to sign"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " using publicKey to sign"); - }); - - all_promises.push(promise); - }); - - // Check for failures due to no "verify" usage. - testVectors.forEach(function(originalVector) { - var vector = Object.assign({}, originalVector); - - var promise = importVectorKeys(vector, [], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName, hash: vector.hashName}; - promise_test(function(test) { - return subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext) - .then(function(plaintext) { - assert_unreached("Should have thrown error for no verify usage in " + vector.name + ": '" + err.message + "'"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); - }); - }, vector.name + " no verify usage"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " no verify usage"); - }); - - all_promises.push(promise); - }); - - // Check for successful signing and verification. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName, hash: vector.hashName}; - promise_test(function(test) { - return subtle.sign(algorithm, vector.privateKey, vector.plaintext) - .then(function(signature) { - // Can we verify the signature? - return subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Round trip verification works"); - return signature; - }, function(err) { - assert_unreached("verify error for test " + vector.name + ": '" + err.message + "'"); - }); - }, function(err) { - assert_unreached("sign error for test " + vector.name + ": '" + err.message + "'"); - }); - }, vector.name + " round trip"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested signing or verifying - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " round trip"); - }); - - all_promises.push(promise); - }); - - // Test signing with the wrong algorithm - testVectors.forEach(function(vector) { - // Want to get the key for the wrong algorithm - var promise = subtle.generateKey({name: "HMAC", hash: "SHA-1"}, false, ["sign", "verify"]) - .then(function(wrongKey) { - var algorithm = {name: vector.algorithmName, hash: vector.hashName}; - return importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - var operation = subtle.sign(algorithm, wrongKey, vector.plaintext) - .then(function(signature) { - assert_unreached("Signing should not have succeeded for " + vector.name); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); - }); - - return operation; - }, vector.name + " signing with wrong algorithm name"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " signing with wrong algorithm name"); - }); - }, function(err) { - promise_test(function(test) { - assert_unreached("Generate wrong key for test " + vector.name + " failed: '" + err.message + "'"); - }, "generate wrong key step: " + vector.name + " signing with wrong algorithm name"); - }); - - all_promises.push(promise); - }); - - // Test verification with the wrong algorithm - testVectors.forEach(function(vector) { - // Want to get the key for the wrong algorithm - var promise = subtle.generateKey({name: "HMAC", hash: "SHA-1"}, false, ["sign", "verify"]) - .then(function(wrongKey) { - return importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName, hash: vector.hashName}; - promise_test(function(test) { - var operation = subtle.verify(algorithm, wrongKey, vector.signature, vector.plaintext) - .then(function(signature) { - assert_unreached("Verifying should not have succeeded for " + vector.name); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verifying with wrong algorithm name"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verifying with wrong algorithm name"); - }); - }, function(err) { - promise_test(function(test) { - assert_unreached("Generate wrong key for test " + vector.name + " failed: '" + err.message + "'"); - }, "generate wrong key step: " + vector.name + " verifying with wrong algorithm name"); - }); - - all_promises.push(promise); - }); - - // Test verification fails with wrong signature - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName, hash: vector.hashName}; - var signature = copyBuffer(vector.signature); - signature[0] = 255 - signature[0]; - promise_test(function(test) { - var operation = subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification failure due to altered signature"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification failure due to altered signature"); - }); - - all_promises.push(promise); - }); - - // Test verification fails with wrong hash - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var hashName = "SHA-1"; - if (vector.hashName === "SHA-1") { - hashName = "SHA-256" + const subtle = self.crypto.subtle; + const normalize = vector => ({...vector, data: vector.plaintext}); + const testVectors = getTestVectors().map(normalize); + const invalidTestVectors = getInvalidTestVectors().map(normalize); + const algorithmIdentifier = vector => ({ + name: vector.algorithmName, + hash: vector.hashName, + }); + const importAlgorithm = vector => ({ + name: vector.algorithmName, + namedCurve: vector.namedCurve, + }); + + runSignatureTests({ + vectors: testVectors, + invalidVectors: invalidTestVectors, + algorithmIdentifier, + importAlgorithm, + dataLabel: "plaintext", + }); + + testVectors.forEach(function(vector) { + promise_test(async function() { + const key = await subtle.importKey( + vector.publicKeyFormat, + vector.publicKeyBuffer, + importAlgorithm(vector), + false, + ["verify"] + ); + const hash = vector.hashName === "SHA-1" ? "SHA-256" : "SHA-1"; + const isVerified = await subtle.verify( + {name: vector.algorithmName, hash}, + key, + vector.signature, + vector.data + ); + assert_false(isVerified, "Signature NOT verified"); + }, vector.name + " verification failure due to wrong hash"); + + promise_test(async function() { + const key = await subtle.importKey( + vector.publicKeyFormat, + vector.publicKeyBuffer, + importAlgorithm(vector), + false, + ["verify"] + ); + const hash = vector.hashName.substring(0, 3) + + vector.hashName.substring(4); + let error; + try { + await subtle.verify( + {name: vector.algorithmName, hash}, + key, + vector.signature, + vector.data + ); + } catch (caught) { + error = caught; } - var algorithm = {name: vector.algorithmName, hash: hashName}; - promise_test(function(test) { - var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification failure due to wrong hash"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification failure due to wrong hash"); - }); - - all_promises.push(promise); - }); - - // Test verification fails with bad hash name - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - // use the wrong name for the hash - var hashName = vector.hashName.substring(0, 3) + vector.hashName.substring(4); - var algorithm = {name: vector.algorithmName, hash: hashName}; - promise_test(function(test) { - var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext) - .then(function(is_verified) { - assert_unreached("Verification should throw an error"); - }, function(err) { - assert_equals(err.name, "NotSupportedError", "Correctly throws NotSupportedError for illegal hash name") - }); - - return operation; - }, vector.name + " verification failure due to bad hash name"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification failure due to bad hash name"); - }); - - all_promises.push(promise); - }); - - // Test verification fails with short (odd length) signature - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName, hash: vector.hashName}; - var signature = vector.signature.slice(1); // Skip the first byte - promise_test(function(test) { - var operation = subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification failure due to shortened signature"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification failure due to shortened signature"); - }); - - all_promises.push(promise); - }); - - // Test verification fails with wrong plaintext - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName, hash: vector.hashName}; - var plaintext = copyBuffer(vector.plaintext); - plaintext[0] = 255 - plaintext[0]; - promise_test(function(test) { - var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification failure due to altered plaintext"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification failure due to altered plaintext"); - }); - - all_promises.push(promise); + assert_not_equals(error, undefined, "Verification should throw"); + assert_equals( + error.name, + "NotSupportedError", + "Correctly throws NotSupportedError for illegal hash name" + ); + }, vector.name + " verification failure due to bad hash name"); }); - - // Test invalid signatures - invalidTestVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName, hash: vector.hashName}; - promise_test(function(test) { - var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature unexpectedly verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification"); - }); - - all_promises.push(promise); - }); - - promise_test(function() { - return Promise.all(all_promises) - .then(function() {done();}) - .catch(function() {done();}) - }, "setup"); - - // A test vector has all needed fields for signing and verifying, EXCEPT that the - // key field may be null. This function replaces that null with the Correct - // CryptoKey object. - // - // Returns a Promise that yields an updated vector on success. - function importVectorKeys(vector, publicKeyUsages, privateKeyUsages) { - var publicPromise, privatePromise; - - if (vector.publicKey !== null) { - publicPromise = new Promise(function(resolve, reject) { - resolve(vector); - }); - } else { - publicPromise = subtle.importKey(vector.publicKeyFormat, vector.publicKeyBuffer, {name: vector.algorithmName, namedCurve: vector.namedCurve}, false, publicKeyUsages) - .then(function(key) { - vector.publicKey = key; - return vector; - }); // Returns a copy of the sourceBuffer it is sent. - } - - if (vector.privateKey !== null) { - privatePromise = new Promise(function(resolve, reject) { - resolve(vector); - }); - } else { - privatePromise = subtle.importKey(vector.privateKeyFormat, vector.privateKeyBuffer, {name: vector.algorithmName, namedCurve: vector.namedCurve}, false, privateKeyUsages) - .then(function(key) { - vector.privateKey = key; - return vector; - }); - } - - return Promise.all([publicPromise, privatePromise]); - } - - return; } diff --git a/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa.js b/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa.js index 77961566d9a6..a60ceda96a6c 100644 --- a/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa.js +++ b/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa.js @@ -1,337 +1,10 @@ - function run_test(algorithmName) { - var subtle = self.crypto.subtle; // Change to test prefixed implementations - - // Source file [algorithm_name]_vectors.js provides the getTestVectors method - // for the algorithm that drives these tests. - var testVectors = getTestVectors(algorithmName); - - testVectors.forEach(function(vector) { - var algorithm = {name: vector.algorithmName}; - - // Test verification first, because signing tests rely on that working - promise_test(async() => { - let isVerified = false; - let key; - try { - key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); - isVerified = await subtle.verify(algorithm, key, vector.signature, vector.data) - } catch (err) { - assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }; - assert_true(isVerified, "Signature verified"); - }, vector.name + " verification"); - - // Test verification with an altered buffer during call - promise_test(async() => { - let isVerified = false; - let key; - try { - key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); - var signature = copyBuffer(vector.signature); - signature[0] = 255 - signature[0]; - isVerified = await subtle.verify({ - get name() { - signature[0] = vector.signature[0]; - return vector.algorithmName; - } - }, key, signature, vector.data); - } catch (err) { - assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }; - assert_true(isVerified, "Signature verified"); - }, vector.name + " verification with altered signature during call"); - - // Test verification with an altered buffer after call - promise_test(async() => { - let isVerified = false; - let key; - try { - key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); - var signature = copyBuffer(vector.signature); - [isVerified] = await Promise.all([ - subtle.verify(algorithm, key, signature, vector.data), - signature[0] = 255 - signature[0] - ]); - } catch (err) { - assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }; - assert_true(isVerified, "Signature verified"); - }, vector.name + " verification with altered signature after call"); - - // Test verification with a transferred buffer during call - promise_test(async() => { - let isVerified = false; - let key; - try { - key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); - var signature = copyBuffer(vector.signature); - isVerified = await subtle.verify({ - get name() { - signature.buffer.transfer(); - return vector.algorithmName; - } - }, key, signature, vector.data); - } catch (err) { - assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }; - assert_false(isVerified, "Signature is NOT verified"); - }, vector.name + " verification with transferred signature during call"); - - // Test verification with a transferred buffer after call - promise_test(async() => { - let isVerified = false; - let key; - try { - key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); - var signature = copyBuffer(vector.signature); - var operation = subtle.verify(algorithm, key, signature, vector.data); - signature.buffer.transfer(); - isVerified = await operation; - } catch (err) { - assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }; - assert_true(isVerified, "Signature verified"); - }, vector.name + " verification with transferred signature after call"); - - // Check for successful verification even if data is altered during call. - promise_test(async() => { - let isVerified = false; - let key; - try { - key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); - var data = copyBuffer(vector.data); - data[0] = 255 - data[0]; - isVerified = await subtle.verify({ - get name() { - data[0] = vector.data[0]; - return vector.algorithmName; - } - }, key, vector.signature, data); - } catch (err) { - assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }; - assert_true(isVerified, "Signature verified"); - }, vector.name + " with altered data during call"); - - // Check for successful verification even if data is altered after call. - promise_test(async() => { - let isVerified = false; - let key; - try { - key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); - var data = copyBuffer(vector.data); - [isVerified] = await Promise.all([ - subtle.verify(algorithm, key, vector.signature, data), - data[0] = 255 - data[0] - ]); - } catch (err) { - assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }; - assert_true(isVerified, "Signature verified"); - }, vector.name + " with altered data after call"); - - // Check for failed verification if data is transferred during call. - promise_test(async() => { - let isVerified = false; - let key; - try { - key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); - var data = copyBuffer(vector.data); - isVerified = await subtle.verify({ - get name() { - data.buffer.transfer(); - return vector.algorithmName; - } - }, key, vector.signature, data); - } catch (err) { - assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }; - assert_false(isVerified, "Signature is NOT verified"); - }, vector.name + " with transferred data during call"); - - // Check for successful verification even if data is transferred after call. - promise_test(async() => { - let isVerified = false; - let key; - try { - key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); - var data = copyBuffer(vector.data); - var operation = subtle.verify(algorithm, key, vector.signature, data); - data.buffer.transfer(); - isVerified = await operation; - } catch (err) { - assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }; - assert_true(isVerified, "Signature verified"); - }, vector.name + " with transferred data after call"); - - // Check for failures due to using privateKey to verify. - promise_test(async() => { - let isVerified = false; - let key; - try { - key = await subtle.importKey("pkcs8", vector.privateKeyBuffer, algorithm, false, ["sign"]); - isVerified = await subtle.verify(algorithm, key, vector.signature, vector.data) - assert_unreached("Should have thrown error for using privateKey to verify in " + vector.name); - } catch (err) { - if (err instanceof AssertionError) - throw err; - assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); - assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); - }; - assert_false(isVerified, "Signature verified"); - }, vector.name + " using privateKey to verify"); - - // Check for failures due to using publicKey to sign. - promise_test(async() => { - let isVerified = false; - let key; - try { - key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); - let signature = await subtle.sign(algorithm, key, vector.data); - assert_unreached("Should have thrown error for using publicKey to sign in " + vector.name); - } catch (err) { - if (err instanceof AssertionError) - throw err; - assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); - assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); - }; - }, vector.name + " using publicKey to sign"); - - // Check for failures due to no "verify" usage. - promise_test(async() => { - let isVerified = false; - let key; - try { - key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, []); - isVerified = await subtle.verify(algorithm, key, vector.signature, vector.data) - assert_unreached("Should have thrown error for no verify usage in " + vector.name); - } catch (err) { - if (err instanceof AssertionError) - throw err; - assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); - assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); - }; - assert_false(isVerified, "Signature verified"); - }, vector.name + " no verify usage"); - - // Check for successful signing and verification. - var algorithm = {name: vector.algorithmName}; - promise_test(async() => { - let isVerified = false; - let privateKey, publicKey; - let signature; - try { - privateKey = await subtle.importKey("pkcs8", vector.privateKeyBuffer, algorithm, false, ["sign"]); - publicKey = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); - signature = await subtle.sign(algorithm, privateKey, vector.data); - isVerified = await subtle.verify(algorithm, publicKey, vector.signature, vector.data) - } catch (err) { - assert_false(publicKey === undefined || privateKey === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); - assert_false(signature === undefined, "sign error for test " + vector.name + ": '" + err.message + "'"); - assert_unreached("verify error for test " + vector.name + ": '" + err.message + "'"); - }; - assert_true(isVerified, "Round trip verification works"); - }, vector.name + " round trip"); - - // Test signing with the wrong algorithm - var algorithm = {name: vector.algorithmName}; - promise_test(async() => { - let wrongKey; - try { - wrongKey = await subtle.generateKey({name: "HMAC", hash: "SHA-1"}, false, ["sign", "verify"]) - let signature = await subtle.sign(algorithm, wrongKey, vector.data); - assert_unreached("Signing should not have succeeded for " + vector.name); - } catch (err) { - if (err instanceof AssertionError) - throw err; - assert_false(wrongKey === undefined, "Generate wrong key for test " + vector.name + " failed: '" + err.message + "'"); - assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); - }; - }, vector.name + " signing with wrong algorithm name"); - - // Test verification with the wrong algorithm - var algorithm = {name: vector.algorithmName}; - promise_test(async() => { - let wrongKey; - try { - wrongKey = await subtle.generateKey({name: "HMAC", hash: "SHA-1"}, false, ["sign", "verify"]) - let isVerified = await subtle.verify(algorithm, wrongKey, vector.signature, vector.data) - assert_unreached("Verifying should not have succeeded for " + vector.name); - } catch (err) { - if (err instanceof AssertionError) - throw err; - assert_false(wrongKey === undefined, "Generate wrong key for test " + vector.name + " failed: '" + err.message + "'"); - assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); - }; - }, vector.name + " verifying with wrong algorithm name"); - - // Test verification fails with wrong signature - var algorithm = {name: vector.algorithmName}; - promise_test(async() => { - let key; - let isVerified = true; - var signature = copyBuffer(vector.signature); - signature[0] = 255 - signature[0]; - try { - key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); - isVerified = await subtle.verify(algorithm, key, signature, vector.data) - } catch (err) { - assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }; - assert_false(isVerified, "Signature verified"); - }, vector.name + " verification failure due to altered signature"); - - // Test verification fails with short (odd length) signature - promise_test(async() => { - let key; - let isVerified = true; - var signature = vector.signature.slice(1); // Skip the first byte - try { - key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); - isVerified = await subtle.verify(algorithm, key, signature, vector.data) - } catch (err) { - assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }; - assert_false(isVerified, "Signature verified"); - }, vector.name + " verification failure due to shortened signature"); - - // Test verification fails with wrong data - promise_test(async() => { - let key; - let isVerified = true; - var data = copyBuffer(vector.data); - data[0] = 255 - data[0]; - try { - key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); - isVerified = await subtle.verify(algorithm, key, vector.signature, data) - } catch (err) { - assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }; - assert_false(isVerified, "Signature verified"); - }, vector.name + " verification failure due to altered data"); - - // Test that generated keys are valid for signing and verifying. - promise_test(async() => { - let key = await subtle.generateKey(algorithm, false, ["sign", "verify"]); - let signature = await subtle.sign(algorithm, key.privateKey, vector.data); - let isVerified = await subtle.verify(algorithm, key.publicKey, signature, vector.data); - assert_true(isVerified, "Verificaton failed."); - }, "Sign and verify using generated " + vector.algorithmName + " keys."); + runSignatureTests({ + vectors: getTestVectors(algorithmName), + algorithmIdentifier(vector) { + return {name: vector.algorithmName}; + }, + katFirst: true, + generatedKeys: true, }); - - return; } diff --git a/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa_curve25519.https.any.js b/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa_curve25519.https.any.js index b012b64733ef..a4f32cbaeb7e 100644 --- a/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa_curve25519.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa_curve25519.https.any.js @@ -1,6 +1,7 @@ // META: title=WebCryptoAPI: sign() and verify() Using EdDSA // META: script=../util/helpers.js // META: script=eddsa_vectors.js +// META: script=signature.js // META: script=eddsa.js // META: timeout=long diff --git a/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa_curve448.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa_curve448.tentative.https.any.js index 281bb63ad659..8dd43dfeb172 100644 --- a/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa_curve448.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa_curve448.tentative.https.any.js @@ -1,6 +1,7 @@ // META: title=WebCryptoAPI: sign() and verify() Using EdDSA // META: script=../util/helpers.js // META: script=eddsa_vectors.js +// META: script=signature.js // META: script=eddsa.js // META: timeout=long diff --git a/test/fixtures/wpt/WebCryptoAPI/sign_verify/hmac.https.any.js b/test/fixtures/wpt/WebCryptoAPI/sign_verify/hmac.https.any.js index a6c88f80ed99..070611181e58 100644 --- a/test/fixtures/wpt/WebCryptoAPI/sign_verify/hmac.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/sign_verify/hmac.https.any.js @@ -1,6 +1,7 @@ // META: title=WebCryptoAPI: sign() and verify() Using HMAC // META: script=../util/helpers.js // META: script=hmac_vectors.js +// META: script=mac.js // META: script=hmac.js // META: timeout=long diff --git a/test/fixtures/wpt/WebCryptoAPI/sign_verify/hmac.js b/test/fixtures/wpt/WebCryptoAPI/sign_verify/hmac.js index 929d9464e171..05b9cedfb94c 100644 --- a/test/fixtures/wpt/WebCryptoAPI/sign_verify/hmac.js +++ b/test/fixtures/wpt/WebCryptoAPI/sign_verify/hmac.js @@ -1,494 +1,11 @@ - function run_test() { - setup({explicit_done: true}); - - var subtle = self.crypto.subtle; // Change to test prefixed implementations - - // When are all these tests really done? When all the promises they use have resolved. - var all_promises = []; - - // Source file hmac_vectors.js provides the getTestVectors method - // for the algorithm that drives these tests. - var testVectors = getTestVectors(); - - // Test verification first, because signing tests rely on that working - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - promise_test(function(test) { - var operation = subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, vector.signature, vector.plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification"); - }); - - all_promises.push(promise); - }); - - // Test verification with an altered buffer during call - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - promise_test(function(test) { - var signature = copyBuffer(vector.signature); - signature[0] = 255 - signature[0]; - var operation = subtle.verify({ - get name() { - signature[0] = vector.signature[0]; - return "HMAC"; - }, - hash: vector.hash - }, vector.key, signature, vector.plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature is not verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification with altered signature during call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification with altered signature during call"); - }); - - all_promises.push(promise); - }); - - // Test verification with an altered buffer after call - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - promise_test(function(test) { - var signature = copyBuffer(vector.signature); - var operation = subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, signature, vector.plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature is not verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - signature[0] = 255 - signature[0]; - return operation; - }, vector.name + " verification with altered signature after call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification with altered signature after call"); - }); - - all_promises.push(promise); - }); - - // Test verification with a transferred buffer during call - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - promise_test(function(test) { - var signature = copyBuffer(vector.signature); - var operation = subtle.verify({ - get name() { - signature.buffer.transfer(); - return "HMAC"; - }, - hash: vector.hash - }, vector.key, signature, vector.plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature is NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification with transferred signature during call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification with transferred signature during call"); - }); - - all_promises.push(promise); - }); - - // Test verification with a transferred buffer after call - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - promise_test(function(test) { - var signature = copyBuffer(vector.signature); - var operation = subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, signature, vector.plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature is not verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - signature.buffer.transfer(); - return operation; - }, vector.name + " verification with transferred signature after call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification with transferred signature after call"); - }); - - all_promises.push(promise); - }); - - // Check for successful verification even if plaintext is altered during call. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - promise_test(function(test) { - var plaintext = copyBuffer(vector.plaintext); - plaintext[0] = 255 - plaintext[0]; - var operation = subtle.verify({ - hash: vector.hash, - get name() { - plaintext[0] = vector.plaintext[0]; - return "HMAC"; - } - }, vector.key, vector.signature, plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " with altered plaintext during call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " with altered plaintext during call"); - }); - - all_promises.push(promise); - }); - - // Check for successful verification even if plaintext is altered after call. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - promise_test(function(test) { - var plaintext = copyBuffer(vector.plaintext); - var operation = subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, vector.signature, plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - plaintext[0] = 255 - plaintext[0]; - return operation; - }, vector.name + " with altered plaintext after call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " with altered plaintext after call"); - }); - - all_promises.push(promise); - }); - - // Check for failed verification if plaintext is transferred during call. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - promise_test(function(test) { - var plaintext = copyBuffer(vector.plaintext); - var operation = subtle.verify({ - get name() { - plaintext.buffer.transfer(); - return "HMAC"; - }, - hash: vector.hash - }, vector.key, vector.signature, plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature is NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " with transferred plaintext during call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " with transferred plaintext during call"); - }); - - all_promises.push(promise); - }); - - // Check for successful verification even if plaintext is transferred after call. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - promise_test(function(test) { - var plaintext = copyBuffer(vector.plaintext); - var operation = subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, vector.signature, plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - plaintext.buffer.transfer(); - return operation; - }, vector.name + " with transferred plaintext after call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " with transferred plaintext after call"); - }); - - all_promises.push(promise); - }); - - // Check for failures due to no "verify" usage. - testVectors.forEach(function(originalVector) { - var vector = Object.assign({}, originalVector); - - var promise = importVectorKeys(vector, ["sign"]) - .then(function(vector) { - promise_test(function(test) { - return subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, vector.signature, vector.plaintext) - .then(function(plaintext) { - assert_unreached("Should have thrown error for no verify usage in " + vector.name + ": '" + err.message + "'"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); - }); - }, vector.name + " no verify usage"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " no verify usage"); - }); - - all_promises.push(promise); - }); - - // Check for successful signing and verification. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vectors) { - promise_test(function(test) { - return subtle.sign({name: "HMAC", hash: vector.hash}, vector.key, vector.plaintext) - .then(function(signature) { - assert_true(equalBuffers(signature, vector.signature), "Signing did not give the expected output"); - // Can we get the verify the new signature? - return subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, signature, vector.plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Round trip verifies"); - return signature; - }, function(err) { - assert_unreached("verify error for test " + vector.name + ": '" + err.message + "'"); - }); - }); - }, vector.name + " round trip"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested signing or verifying - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " round trip"); - }); - - all_promises.push(promise); - }); - - // Test signing with the wrong algorithm - testVectors.forEach(function(vector) { - // Want to get the key for the wrong algorithm - var promise = subtle.generateKey({name: "ECDSA", namedCurve: "P-256", hash: "SHA-256"}, false, ["sign", "verify"]) - .then(function(wrongKey) { - return importVectorKeys(vector, ["verify", "sign"]) - .then(function(vectors) { - promise_test(function(test) { - var operation = subtle.sign({name: "HMAC", hash: vector.hash}, wrongKey.privateKey, vector.plaintext) - .then(function(signature) { - assert_unreached("Signing should not have succeeded for " + vector.name); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); - }); - - return operation; - }, vector.name + " signing with wrong algorithm name"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " signing with wrong algorithm name"); - }); - }, function(err) { - promise_test(function(test) { - assert_unreached("Generate wrong key for test " + vector.name + " failed: '" + err.message + "'"); - }, "generate wrong key step: " + vector.name + " signing with wrong algorithm name"); - }); - - all_promises.push(promise); - }); - - // Test verification with the wrong algorithm - testVectors.forEach(function(vector) { - // Want to get the key for the wrong algorithm - var promise = subtle.generateKey({name: "ECDSA", namedCurve: "P-256", hash: "SHA-256"}, false, ["sign", "verify"]) - .then(function(wrongKey) { - return importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - promise_test(function(test) { - var operation = subtle.verify({name: "HMAC", hash: vector.hash}, wrongKey.publicKey, vector.signature, vector.plaintext) - .then(function(signature) { - assert_unreached("Verifying should not have succeeded for " + vector.name); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verifying with wrong algorithm name"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verifying with wrong algorithm name"); - }); - }, function(err) { - promise_test(function(test) { - assert_unreached("Generate wrong key for test " + vector.name + " failed: '" + err.message + "'"); - }, "generate wrong key step: " + vector.name + " verifying with wrong algorithm name"); - }); - - all_promises.push(promise); - }); - - // Verification should fail if the plaintext is changed - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - var plaintext = copyBuffer(vector.plaintext); - plaintext[0] = 255 - plaintext[0]; - promise_test(function(test) { - var operation = subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, vector.signature, plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature is NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification failure due to wrong plaintext"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification failure due to wrong plaintext"); - }); - - all_promises.push(promise); - }); - - // Verification should fail if the signature is changed - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - var signature = copyBuffer(vector.signature); - signature[0] = 255 - signature[0]; - promise_test(function(test) { - var operation = subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, signature, vector.plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature is NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification failure due to wrong signature"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification failure due to wrong signature"); - }); - - all_promises.push(promise); - }); - - // Verification should fail if the signature is wrong length - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - var signature = vector.signature.slice(1); // Drop first byte - promise_test(function(test) { - var operation = subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, signature, vector.plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature is NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification failure due to short signature"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification failure due to short signature"); - }); - - all_promises.push(promise); - }); - - - - promise_test(function() { - return Promise.all(all_promises) - .then(function() {done();}) - .catch(function() {done();}) - }, "setup"); - - // A test vector has all needed fields for signing and verifying, EXCEPT that the - // key field may be null. This function replaces that null with the Correct - // CryptoKey object. - // - // Returns a Promise that yields an updated vector on success. - function importVectorKeys(vector, keyUsages) { - if (vector.key !== null) { - return new Promise(function(resolve, reject) { - resolve(vector); - }); - } else { - return subtle.importKey("raw", vector.keyBuffer, {name: "HMAC", hash: vector.hash}, false, keyUsages) - .then(function(key) { - vector.key = key; - return vector; - }); + runMacTests({ + importFormat: "raw", + importAlgorithm: function(vector) { + return {name: "HMAC", hash: vector.hash}; + }, + operationAlgorithm: function(vector) { + return {name: "HMAC", hash: vector.hash}; } - } - - return; + }); } diff --git a/test/fixtures/wpt/WebCryptoAPI/sign_verify/kmac.js b/test/fixtures/wpt/WebCryptoAPI/sign_verify/kmac.js index d9d82d150b39..ac30a5559d8c 100644 --- a/test/fixtures/wpt/WebCryptoAPI/sign_verify/kmac.js +++ b/test/fixtures/wpt/WebCryptoAPI/sign_verify/kmac.js @@ -1,586 +1,25 @@ function run_test() { - setup({explicit_done: true}); - - var subtle = self.crypto.subtle; // Change to test prefixed implementations - - // When are all these tests really done? When all the promises they use have resolved. - var all_promises = []; - - // Source file kmac_vectors.js provides the getTestVectors method - // for the algorithm that drives these tests. - var testVectors = getTestVectors(); - - // Test verification first, because signing tests rely on that working - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - promise_test(function(test) { - var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; - if (vector.customization !== undefined) { - algorithmParams.customization = vector.customization; - } - var operation = subtle.verify(algorithmParams, vector.key, vector.signature, vector.plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification"); - }); - - all_promises.push(promise); - }); - - // Test verification with an altered buffer during call - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - promise_test(function(test) { - var signature = copyBuffer(vector.signature); - signature[0] = 255 - signature[0]; - var algorithmParams = { - outputLength: vector.outputLength, - get name() { - signature[0] = vector.signature[0]; - return vector.algorithm; - } - }; - if (vector.customization !== undefined) { - algorithmParams.customization = vector.customization; - } - var operation = subtle.verify(algorithmParams, vector.key, signature, vector.plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature is not verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification with altered signature during call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification with altered signature during call"); - }); - - all_promises.push(promise); - }); - - // Test verification with an altered buffer after call - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - promise_test(function(test) { - var signature = copyBuffer(vector.signature); - var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; - if (vector.customization !== undefined) { - algorithmParams.customization = vector.customization; - } - var operation = subtle.verify(algorithmParams, vector.key, signature, vector.plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature is not verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - signature[0] = 255 - signature[0]; - return operation; - }, vector.name + " verification with altered signature after call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification with altered signature after call"); - }); - - all_promises.push(promise); - }); - - // Test verification with a transferred buffer during call - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - promise_test(function(test) { - var signature = copyBuffer(vector.signature); - var algorithmParams = { - get name() { - signature.buffer.transfer(); - return vector.algorithm; - }, - outputLength: vector.outputLength - }; - if (vector.customization !== undefined) { - algorithmParams.customization = vector.customization; - } - var operation = subtle.verify(algorithmParams, vector.key, signature, vector.plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature is NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification with transferred signature during call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification with transferred signature during call"); - }); - - all_promises.push(promise); - }); - - // Test verification with a transferred buffer after call - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - promise_test(function(test) { - var signature = copyBuffer(vector.signature); - var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; - if (vector.customization !== undefined) { - algorithmParams.customization = vector.customization; - } - var operation = subtle.verify(algorithmParams, vector.key, signature, vector.plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature is not verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - signature.buffer.transfer(); - return operation; - }, vector.name + " verification with transferred signature after call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification with transferred signature after call"); - }); - - all_promises.push(promise); - }); - - // Check for successful verification even if plaintext is altered during call. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - promise_test(function(test) { - var plaintext = copyBuffer(vector.plaintext); - plaintext[0] = 255 - plaintext[0]; - var algorithmParams = { - outputLength: vector.outputLength, - get name() { - plaintext[0] = vector.plaintext[0]; - return vector.algorithm; - } - }; - if (vector.customization !== undefined) { - algorithmParams.customization = vector.customization; - } - var operation = subtle.verify(algorithmParams, vector.key, vector.signature, plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " with altered plaintext during call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " with altered plaintext during call"); - }); - - all_promises.push(promise); - }); - - // Check for successful verification even if plaintext is altered after call. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - promise_test(function(test) { - var plaintext = copyBuffer(vector.plaintext); - var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; - if (vector.customization !== undefined) { - algorithmParams.customization = vector.customization; - } - var operation = subtle.verify(algorithmParams, vector.key, vector.signature, plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - plaintext[0] = 255 - plaintext[0]; - return operation; - }, vector.name + " with altered plaintext after call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " with altered plaintext after call"); - }); - - all_promises.push(promise); - }); - - // Check for failed verification if plaintext is transferred during call. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - promise_test(function(test) { - var plaintext = copyBuffer(vector.plaintext); - var algorithmParams = { - get name() { - plaintext.buffer.transfer(); - return vector.algorithm; - }, - outputLength: vector.outputLength - }; - if (vector.customization !== undefined) { - algorithmParams.customization = vector.customization; - } - var operation = subtle.verify(algorithmParams, vector.key, vector.signature, plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature is NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " with transferred plaintext during call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " with transferred plaintext during call"); - }); - - all_promises.push(promise); - }); - - // Check for successful verification even if plaintext is transferred after call. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - promise_test(function(test) { - var plaintext = copyBuffer(vector.plaintext); - var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; - if (vector.customization !== undefined) { - algorithmParams.customization = vector.customization; - } - var operation = subtle.verify(algorithmParams, vector.key, vector.signature, plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - plaintext.buffer.transfer(); - return operation; - }, vector.name + " with transferred plaintext after call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " with transferred plaintext after call"); - }); - - all_promises.push(promise); - }); - - // Check for failures due to no "verify" usage. - testVectors.forEach(function(originalVector) { - var vector = Object.assign({}, originalVector); - - var promise = importVectorKeys(vector, ["sign"]) - .then(function(vector) { - promise_test(function(test) { - var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; - if (vector.customization !== undefined) { - algorithmParams.customization = vector.customization; - } - return subtle.verify(algorithmParams, vector.key, vector.signature, vector.plaintext) - .then(function(plaintext) { - assert_unreached("Should have thrown error for no verify usage in " + vector.name + ": '" + err.message + "'"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); - }); - }, vector.name + " no verify usage"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " no verify usage"); - }); - - all_promises.push(promise); - }); - - // Check for successful signing and verification. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vectors) { - promise_test(function(test) { - var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; - if (vector.customization !== undefined) { - algorithmParams.customization = vector.customization; - } - return subtle.sign(algorithmParams, vector.key, vector.plaintext) - .then(function(signature) { - assert_true(equalBuffers(signature, vector.signature), "Signing did not give the expected output"); - // Can we get the verify the new signature? - return subtle.verify(algorithmParams, vector.key, signature, vector.plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Round trip verifies"); - return signature; - }, function(err) { - assert_unreached("verify error for test " + vector.name + ": '" + err.message + "'"); - }); - }); - }, vector.name + " round trip"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested signing or verifying - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " round trip"); - }); - - all_promises.push(promise); - }); - - // Test signing with the wrong algorithm - testVectors.forEach(function(vector) { - // Want to get the key for the wrong algorithm - var promise = subtle.generateKey({name: "ECDSA", namedCurve: "P-256", hash: "SHA-256"}, false, ["sign", "verify"]) - .then(function(wrongKey) { - return importVectorKeys(vector, ["verify", "sign"]) - .then(function(vectors) { - promise_test(function(test) { - var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; - if (vector.customization !== undefined) { - algorithmParams.customization = vector.customization; - } - var operation = subtle.sign(algorithmParams, wrongKey.privateKey, vector.plaintext) - .then(function(signature) { - assert_unreached("Signing should not have succeeded for " + vector.name); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); - }); - - return operation; - }, vector.name + " signing with wrong algorithm name"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " signing with wrong algorithm name"); - }); - }, function(err) { - promise_test(function(test) { - assert_unreached("Generate wrong key for test " + vector.name + " failed: '" + err.message + "'"); - }, "generate wrong key step: " + vector.name + " signing with wrong algorithm name"); - }); - - all_promises.push(promise); - }); - - // Test verification with the wrong algorithm - testVectors.forEach(function(vector) { - // Want to get the key for the wrong algorithm - var promise = subtle.generateKey({name: "ECDSA", namedCurve: "P-256", hash: "SHA-256"}, false, ["sign", "verify"]) - .then(function(wrongKey) { - return importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - promise_test(function(test) { - var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; - if (vector.customization !== undefined) { - algorithmParams.customization = vector.customization; - } - var operation = subtle.verify(algorithmParams, wrongKey.publicKey, vector.signature, vector.plaintext) - .then(function(signature) { - assert_unreached("Verifying should not have succeeded for " + vector.name); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verifying with wrong algorithm name"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verifying with wrong algorithm name"); - }); - }, function(err) { - promise_test(function(test) { - assert_unreached("Generate wrong key for test " + vector.name + " failed: '" + err.message + "'"); - }, "generate wrong key step: " + vector.name + " verifying with wrong algorithm name"); - }); - - all_promises.push(promise); - }); - - // Verification should fail if the plaintext is changed - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - var plaintext = copyBuffer(vector.plaintext); - plaintext[0] = 255 - plaintext[0]; - promise_test(function(test) { - var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; - if (vector.customization !== undefined) { - algorithmParams.customization = vector.customization; - } - var operation = subtle.verify(algorithmParams, vector.key, vector.signature, plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature is NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification failure due to wrong plaintext"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification failure due to wrong plaintext"); - }); - - all_promises.push(promise); - }); - - // Verification should fail if the signature is changed - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - var signature = copyBuffer(vector.signature); - signature[0] = 255 - signature[0]; - promise_test(function(test) { - var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; - if (vector.customization !== undefined) { - algorithmParams.customization = vector.customization; - } - var operation = subtle.verify(algorithmParams, vector.key, signature, vector.plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature is NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification failure due to wrong signature"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification failure due to wrong signature"); - }); - - all_promises.push(promise); - }); - - // Verification should fail if the signature is wrong length - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - var signature = vector.signature.slice(1); // Drop first byte - promise_test(function(test) { - var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; - if (vector.customization !== undefined) { - algorithmParams.customization = vector.customization; - } - var operation = subtle.verify(algorithmParams, vector.key, signature, vector.plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature is NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification failure due to short signature"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification failure due to short signature"); - }); - - all_promises.push(promise); - }); - - // Test verification failure due to wrong length parameter - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify", "sign"]) - .then(function(vector) { - promise_test(function(test) { - var differentLength = vector.outputLength === 256 ? 512 : 256; - var algorithmParams = {name: vector.algorithm, outputLength: differentLength}; - if (vector.customization !== undefined) { - algorithmParams.customization = vector.customization; - } - var operation = subtle.verify(algorithmParams, vector.key, vector.signature, vector.plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature is NOT verified with wrong length"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification failure due to wrong length parameter"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification failure due to wrong length parameter"); - }); - - all_promises.push(promise); - }); - - promise_test(function() { - return Promise.all(all_promises) - .then(function() {done();}) - .catch(function() {done();}) - }, "setup"); - - // A test vector has all needed fields for signing and verifying, EXCEPT that the - // key field may be null. This function replaces that null with the Correct - // CryptoKey object. - // - // Returns a Promise that yields an updated vector on success. - function importVectorKeys(vector, keyUsages) { - if (vector.key !== null) { - return new Promise(function(resolve, reject) { - resolve(vector); - }); - } else { - return subtle.importKey("raw-secret", vector.keyBuffer, {name: vector.algorithm}, false, keyUsages) - .then(function(key) { - vector.key = key; - return vector; - }); + function operationAlgorithm(vector) { + var algorithm = { + name: vector.algorithm, + outputLength: vector.outputLength + }; + if (vector.customization !== undefined) { + algorithm.customization = vector.customization; } + return algorithm; } - return; + runMacTests({ + importFormat: "raw-secret", + importAlgorithm: function(vector) { + return {name: vector.algorithm}; + }, + operationAlgorithm: operationAlgorithm, + wrongVerificationAlgorithm: function(vector) { + var algorithm = operationAlgorithm(vector); + algorithm.outputLength = vector.outputLength === 256 ? 512 : 256; + return algorithm; + } + }); } diff --git a/test/fixtures/wpt/WebCryptoAPI/sign_verify/kmac.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/sign_verify/kmac.tentative.https.any.js index 3d34c5752137..0a57ba7a3f80 100644 --- a/test/fixtures/wpt/WebCryptoAPI/sign_verify/kmac.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/sign_verify/kmac.tentative.https.any.js @@ -1,6 +1,7 @@ // META: title=WebCryptoAPI: sign() and verify() Using KMAC // META: script=../util/helpers.js // META: script=kmac_vectors.js +// META: script=mac.js // META: script=kmac.js // META: timeout=long diff --git a/test/fixtures/wpt/WebCryptoAPI/sign_verify/mac.js b/test/fixtures/wpt/WebCryptoAPI/sign_verify/mac.js new file mode 100644 index 000000000000..27787c91d8a2 --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/sign_verify/mac.js @@ -0,0 +1,514 @@ + +function runMacTests(options) { + setup({explicit_done: true}); + + var subtle = self.crypto.subtle; // Change to test prefixed implementations + + // When are all these tests really done? When all the promises they use have resolved. + var all_promises = []; + + // The algorithm-specific vector source provides getTestVectors(). + var testVectors = getTestVectors(); + + function operationAlgorithm(vector, nameGetter) { + var algorithm = options.operationAlgorithm(vector); + if (nameGetter !== undefined) { + Object.defineProperty(algorithm, "name", { + enumerable: true, + get: nameGetter + }); + } + return algorithm; + } + + // Test verification first, because signing tests rely on that working + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify", "sign"]) + .then(function(vector) { + promise_test(function(test) { + var operation = subtle.verify(operationAlgorithm(vector), vector.key, vector.signature, vector.plaintext) + .then(function(is_verified) { + assert_true(is_verified, "Signature verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); + }); + + return operation; + }, vector.name + " verification"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification"); + }); + + all_promises.push(promise); + }); + + // Test verification with an altered buffer during call + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify", "sign"]) + .then(function(vector) { + promise_test(function(test) { + var signature = copyBuffer(vector.signature); + signature[0] = 255 - signature[0]; + var operation = subtle.verify(operationAlgorithm(vector, function() { + signature[0] = vector.signature[0]; + return options.operationAlgorithm(vector).name; + }), vector.key, signature, vector.plaintext) + .then(function(is_verified) { + assert_true(is_verified, "Signature is not verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); + }); + + return operation; + }, vector.name + " verification with altered signature during call"); + }, function(err) { + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification with altered signature during call"); + }); + + all_promises.push(promise); + }); + + // Test verification with an altered buffer after call + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify", "sign"]) + .then(function(vector) { + promise_test(function(test) { + var signature = copyBuffer(vector.signature); + var operation = subtle.verify(operationAlgorithm(vector), vector.key, signature, vector.plaintext) + .then(function(is_verified) { + assert_true(is_verified, "Signature is not verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); + }); + + signature[0] = 255 - signature[0]; + return operation; + }, vector.name + " verification with altered signature after call"); + }, function(err) { + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification with altered signature after call"); + }); + + all_promises.push(promise); + }); + + // Test verification with a transferred buffer during call + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify", "sign"]) + .then(function(vector) { + promise_test(function(test) { + var signature = copyBuffer(vector.signature); + var operation = subtle.verify(operationAlgorithm(vector, function() { + signature.buffer.transfer(); + return options.operationAlgorithm(vector).name; + }), vector.key, signature, vector.plaintext) + .then(function(is_verified) { + assert_false(is_verified, "Signature is NOT verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); + }); + + return operation; + }, vector.name + " verification with transferred signature during call"); + }, function(err) { + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification with transferred signature during call"); + }); + + all_promises.push(promise); + }); + + // Test verification with a transferred buffer after call + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify", "sign"]) + .then(function(vector) { + promise_test(function(test) { + var signature = copyBuffer(vector.signature); + var operation = subtle.verify(operationAlgorithm(vector), vector.key, signature, vector.plaintext) + .then(function(is_verified) { + assert_true(is_verified, "Signature is not verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); + }); + + signature.buffer.transfer(); + return operation; + }, vector.name + " verification with transferred signature after call"); + }, function(err) { + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification with transferred signature after call"); + }); + + all_promises.push(promise); + }); + + // Check for successful verification even if plaintext is altered during call. + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify", "sign"]) + .then(function(vector) { + promise_test(function(test) { + var plaintext = copyBuffer(vector.plaintext); + plaintext[0] = 255 - plaintext[0]; + var operation = subtle.verify(operationAlgorithm(vector, function() { + plaintext[0] = vector.plaintext[0]; + return options.operationAlgorithm(vector).name; + }), vector.key, vector.signature, plaintext) + .then(function(is_verified) { + assert_true(is_verified, "Signature verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); + }); + + return operation; + }, vector.name + " with altered plaintext during call"); + }, function(err) { + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " with altered plaintext during call"); + }); + + all_promises.push(promise); + }); + + // Check for successful verification even if plaintext is altered after call. + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify", "sign"]) + .then(function(vector) { + promise_test(function(test) { + var plaintext = copyBuffer(vector.plaintext); + var operation = subtle.verify(operationAlgorithm(vector), vector.key, vector.signature, plaintext) + .then(function(is_verified) { + assert_true(is_verified, "Signature verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); + }); + + plaintext[0] = 255 - plaintext[0]; + return operation; + }, vector.name + " with altered plaintext after call"); + }, function(err) { + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " with altered plaintext after call"); + }); + + all_promises.push(promise); + }); + + // Check for failed verification if plaintext is transferred during call. + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify", "sign"]) + .then(function(vector) { + promise_test(function(test) { + var plaintext = copyBuffer(vector.plaintext); + var operation = subtle.verify(operationAlgorithm(vector, function() { + plaintext.buffer.transfer(); + return options.operationAlgorithm(vector).name; + }), vector.key, vector.signature, plaintext) + .then(function(is_verified) { + assert_false(is_verified, "Signature is NOT verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); + }); + + return operation; + }, vector.name + " with transferred plaintext during call"); + }, function(err) { + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " with transferred plaintext during call"); + }); + + all_promises.push(promise); + }); + + // Check for successful verification even if plaintext is transferred after call. + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify", "sign"]) + .then(function(vector) { + promise_test(function(test) { + var plaintext = copyBuffer(vector.plaintext); + var operation = subtle.verify(operationAlgorithm(vector), vector.key, vector.signature, plaintext) + .then(function(is_verified) { + assert_true(is_verified, "Signature verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); + }); + + plaintext.buffer.transfer(); + return operation; + }, vector.name + " with transferred plaintext after call"); + }, function(err) { + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " with transferred plaintext after call"); + }); + + all_promises.push(promise); + }); + + // Check for failures due to no "verify" usage. + testVectors.forEach(function(originalVector) { + var vector = Object.assign({}, originalVector); + + var promise = importVectorKeys(vector, ["sign"]) + .then(function(vector) { + promise_test(function(test) { + return subtle.verify(operationAlgorithm(vector), vector.key, vector.signature, vector.plaintext) + .then(function(plaintext) { + assert_unreached("Should have thrown error for no verify usage in " + vector.name + ": '" + err.message + "'"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); + }); + }, vector.name + " no verify usage"); + }, function(err) { + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " no verify usage"); + }); + + all_promises.push(promise); + }); + + // Check for successful signing and verification. + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify", "sign"]) + .then(function(vectors) { + promise_test(function(test) { + return subtle.sign(operationAlgorithm(vector), vector.key, vector.plaintext) + .then(function(signature) { + assert_true(equalBuffers(signature, vector.signature), "Signing did not give the expected output"); + // Can we get the verify the new signature? + return subtle.verify(operationAlgorithm(vector), vector.key, signature, vector.plaintext) + .then(function(is_verified) { + assert_true(is_verified, "Round trip verifies"); + return signature; + }, function(err) { + assert_unreached("verify error for test " + vector.name + ": '" + err.message + "'"); + }); + }); + }, vector.name + " round trip"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested signing or verifying + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " round trip"); + }); + + all_promises.push(promise); + }); + + // Test signing with the wrong algorithm + testVectors.forEach(function(vector) { + // Want to get the key for the wrong algorithm + var promise = subtle.generateKey({name: "ECDSA", namedCurve: "P-256", hash: "SHA-256"}, false, ["sign", "verify"]) + .then(function(wrongKey) { + return importVectorKeys(vector, ["verify", "sign"]) + .then(function(vectors) { + promise_test(function(test) { + var operation = subtle.sign(operationAlgorithm(vector), wrongKey.privateKey, vector.plaintext) + .then(function(signature) { + assert_unreached("Signing should not have succeeded for " + vector.name); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); + }); + + return operation; + }, vector.name + " signing with wrong algorithm name"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " signing with wrong algorithm name"); + }); + }, function(err) { + promise_test(function(test) { + assert_unreached("Generate wrong key for test " + vector.name + " failed: '" + err.message + "'"); + }, "generate wrong key step: " + vector.name + " signing with wrong algorithm name"); + }); + + all_promises.push(promise); + }); + + // Test verification with the wrong algorithm + testVectors.forEach(function(vector) { + // Want to get the key for the wrong algorithm + var promise = subtle.generateKey({name: "ECDSA", namedCurve: "P-256", hash: "SHA-256"}, false, ["sign", "verify"]) + .then(function(wrongKey) { + return importVectorKeys(vector, ["verify", "sign"]) + .then(function(vector) { + promise_test(function(test) { + var operation = subtle.verify(operationAlgorithm(vector), wrongKey.publicKey, vector.signature, vector.plaintext) + .then(function(signature) { + assert_unreached("Verifying should not have succeeded for " + vector.name); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); + }); + + return operation; + }, vector.name + " verifying with wrong algorithm name"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verifying with wrong algorithm name"); + }); + }, function(err) { + promise_test(function(test) { + assert_unreached("Generate wrong key for test " + vector.name + " failed: '" + err.message + "'"); + }, "generate wrong key step: " + vector.name + " verifying with wrong algorithm name"); + }); + + all_promises.push(promise); + }); + + // Verification should fail if the plaintext is changed + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify", "sign"]) + .then(function(vector) { + var plaintext = copyBuffer(vector.plaintext); + plaintext[0] = 255 - plaintext[0]; + promise_test(function(test) { + var operation = subtle.verify(operationAlgorithm(vector), vector.key, vector.signature, plaintext) + .then(function(is_verified) { + assert_false(is_verified, "Signature is NOT verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); + }); + + return operation; + }, vector.name + " verification failure due to wrong plaintext"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification failure due to wrong plaintext"); + }); + + all_promises.push(promise); + }); + + // Verification should fail if the signature is changed + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify", "sign"]) + .then(function(vector) { + var signature = copyBuffer(vector.signature); + signature[0] = 255 - signature[0]; + promise_test(function(test) { + var operation = subtle.verify(operationAlgorithm(vector), vector.key, signature, vector.plaintext) + .then(function(is_verified) { + assert_false(is_verified, "Signature is NOT verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); + }); + + return operation; + }, vector.name + " verification failure due to wrong signature"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification failure due to wrong signature"); + }); + + all_promises.push(promise); + }); + + // Verification should fail if the signature is wrong length + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify", "sign"]) + .then(function(vector) { + var signature = vector.signature.slice(1); // Drop first byte + promise_test(function(test) { + var operation = subtle.verify(operationAlgorithm(vector), vector.key, signature, vector.plaintext) + .then(function(is_verified) { + assert_false(is_verified, "Signature is NOT verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); + }); + + return operation; + }, vector.name + " verification failure due to short signature"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification failure due to short signature"); + }); + + all_promises.push(promise); + }); + + if (options.wrongVerificationAlgorithm !== undefined) { + // Test verification failure due to algorithm-specific parameters. + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify", "sign"]) + .then(function(vector) { + promise_test(function(test) { + var operation = subtle.verify(options.wrongVerificationAlgorithm(vector), vector.key, vector.signature, vector.plaintext) + .then(function(is_verified) { + assert_false(is_verified, "Signature is NOT verified with wrong length"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); + }); + + return operation; + }, vector.name + " verification failure due to wrong length parameter"); + + }, function(err) { + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification failure due to wrong length parameter"); + }); + + all_promises.push(promise); + }); + } + + + + promise_test(function() { + return Promise.all(all_promises).finally(done); + }, "setup"); + + // A test vector has all needed fields for signing and verifying, EXCEPT that the + // key field may be null. This function replaces that null with the Correct + // CryptoKey object. + // + // Returns a Promise that yields an updated vector on success. + function importVectorKeys(vector, keyUsages) { + if (vector.key !== null) { + return Promise.resolve(vector); + } else { + return subtle.importKey(options.importFormat, vector.keyBuffer, options.importAlgorithm(vector), false, keyUsages) + .then(function(key) { + vector.key = key; + return vector; + }); + } + } + + return; +} diff --git a/test/fixtures/wpt/WebCryptoAPI/sign_verify/mldsa.js b/test/fixtures/wpt/WebCryptoAPI/sign_verify/mldsa.js index 10879273c1c3..a2a4ef276043 100644 --- a/test/fixtures/wpt/WebCryptoAPI/sign_verify/mldsa.js +++ b/test/fixtures/wpt/WebCryptoAPI/sign_verify/mldsa.js @@ -1,1038 +1,10 @@ function run_test() { - setup({ explicit_done: true }); - - var subtle = self.crypto.subtle; // Change to test prefixed implementations - - // When are all these tests really done? When all the promises they use have resolved. - var all_promises = []; - - // Source file [algorithm_name]_vectors.js provides the getTestVectors method - // for the algorithm that drives these tests. - var testVectors = getTestVectors(); - var invalidTestVectors = getInvalidTestVectors(); - - // Test verification first, because signing tests rely on that working - testVectors.forEach(function (vector) { - var promise = importVectorKeys(vector, ['verify'], ['sign']).then( - function (vectors) { - var algorithm = vector.algorithmName; - promise_test(function (test) { - var operation = subtle - .verify(algorithm, vector.publicKey, vector.signature, vector.data) - .then( - function (is_verified) { - assert_true(is_verified, 'Signature verified'); - }, - function (err) { - assert_unreached( - 'Verification should not throw error ' + - vector.name + - ': ' + - err.message + - "'" - ); - } - ); - - return operation; - }, vector.name + ' verification'); - }, - function (err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function (test) { - assert_unreached( - 'importVectorKeys failed for ' + - vector.name + - ". Message: ''" + - err.message + - "''" - ); - }, 'importVectorKeys step: ' + vector.name + ' verification'); - } - ); - - all_promises.push(promise); + runSignatureTests({ + vectors: getTestVectors(), + invalidVectors: getInvalidTestVectors(), + algorithmIdentifier(vector) { + return vector.algorithmName; + }, + dataLabel: 'plaintext', }); - - // Test verification with an altered buffer during call - testVectors.forEach(function (vector) { - var promise = importVectorKeys(vector, ['verify'], ['sign']).then( - function (vectors) { - promise_test(function (test) { - var signature = copyBuffer(vector.signature); - signature[0] = 255 - signature[0]; - var operation = subtle - .verify( - { - get name() { - signature[0] = vector.signature[0]; - return vector.algorithmName; - }, - }, - vector.publicKey, - signature, - vector.data - ) - .then( - function (is_verified) { - assert_true(is_verified, 'Signature verified'); - }, - function (err) { - assert_unreached( - 'Verification should not throw error ' + - vector.name + - ': ' + - err.message + - "'" - ); - } - ); - - return operation; - }, vector.name + ' verification with altered signature during call'); - }, - function (err) { - promise_test(function (test) { - assert_unreached( - 'importVectorKeys failed for ' + - vector.name + - ". Message: ''" + - err.message + - "''" - ); - }, 'importVectorKeys step: ' + - vector.name + - ' verification with altered signature during call'); - } - ); - - all_promises.push(promise); - }); - - // Test verification with an altered buffer after call - testVectors.forEach(function (vector) { - var promise = importVectorKeys(vector, ['verify'], ['sign']).then( - function (vectors) { - var algorithm = vector.algorithmName; - promise_test(function (test) { - var signature = copyBuffer(vector.signature); - var operation = subtle - .verify(algorithm, vector.publicKey, signature, vector.data) - .then( - function (is_verified) { - assert_true(is_verified, 'Signature verified'); - }, - function (err) { - assert_unreached( - 'Verification should not throw error ' + - vector.name + - ': ' + - err.message + - "'" - ); - } - ); - - signature[0] = 255 - signature[0]; - return operation; - }, vector.name + ' verification with altered signature after call'); - }, - function (err) { - promise_test(function (test) { - assert_unreached( - 'importVectorKeys failed for ' + - vector.name + - ". Message: ''" + - err.message + - "''" - ); - }, 'importVectorKeys step: ' + - vector.name + - ' verification with altered signature after call'); - } - ); - - all_promises.push(promise); - }); - - // Test verification with a transferred buffer during call - testVectors.forEach(function (vector) { - var promise = importVectorKeys(vector, ['verify'], ['sign']).then( - function (vectors) { - promise_test(function (test) { - var signature = copyBuffer(vector.signature); - var operation = subtle - .verify( - { - get name() { - signature.buffer.transfer(); - return vector.algorithmName; - }, - }, - vector.publicKey, - signature, - vector.data - ) - .then( - function (is_verified) { - assert_false(is_verified, 'Signature is NOT verified'); - }, - function (err) { - assert_unreached( - 'Verification should not throw error ' + - vector.name + - ': ' + - err.message + - "'" - ); - } - ); - - return operation; - }, vector.name + ' verification with transferred signature during call'); - }, - function (err) { - promise_test(function (test) { - assert_unreached( - 'importVectorKeys failed for ' + - vector.name + - ". Message: ''" + - err.message + - "''" - ); - }, 'importVectorKeys step: ' + - vector.name + - ' verification with transferred signature during call'); - } - ); - - all_promises.push(promise); - }); - - // Test verification with a transferred buffer after call - testVectors.forEach(function (vector) { - var promise = importVectorKeys(vector, ['verify'], ['sign']).then( - function (vectors) { - var algorithm = vector.algorithmName; - promise_test(function (test) { - var signature = copyBuffer(vector.signature); - var operation = subtle - .verify(algorithm, vector.publicKey, signature, vector.data) - .then( - function (is_verified) { - assert_true(is_verified, 'Signature verified'); - }, - function (err) { - assert_unreached( - 'Verification should not throw error ' + - vector.name + - ': ' + - err.message + - "'" - ); - } - ); - - signature.buffer.transfer(); - return operation; - }, vector.name + ' verification with transferred signature after call'); - }, - function (err) { - promise_test(function (test) { - assert_unreached( - 'importVectorKeys failed for ' + - vector.name + - ". Message: ''" + - err.message + - "''" - ); - }, 'importVectorKeys step: ' + - vector.name + - ' verification with transferred signature after call'); - } - ); - - all_promises.push(promise); - }); - - // Check for successful verification even if plaintext is altered during call. - testVectors.forEach(function (vector) { - var promise = importVectorKeys(vector, ['verify'], ['sign']).then( - function (vectors) { - promise_test(function (test) { - var plaintext = copyBuffer(vector.data); - plaintext[0] = 255 - plaintext[0]; - var operation = subtle - .verify( - { - get name() { - plaintext[0] = vector.data[0]; - return vector.algorithmName; - }, - }, - vector.publicKey, - vector.signature, - plaintext - ) - .then( - function (is_verified) { - assert_true(is_verified, 'Signature verified'); - }, - function (err) { - assert_unreached( - 'Verification should not throw error ' + - vector.name + - ': ' + - err.message + - "'" - ); - } - ); - - return operation; - }, vector.name + ' with altered plaintext during call'); - }, - function (err) { - promise_test(function (test) { - assert_unreached( - 'importVectorKeys failed for ' + - vector.name + - ". Message: ''" + - err.message + - "''" - ); - }, 'importVectorKeys step: ' + - vector.name + - ' with altered plaintext during call'); - } - ); - - all_promises.push(promise); - }); - - // Check for successful verification even if plaintext is altered after call. - testVectors.forEach(function (vector) { - var promise = importVectorKeys(vector, ['verify'], ['sign']).then( - function (vectors) { - var algorithm = vector.algorithmName; - promise_test(function (test) { - var plaintext = copyBuffer(vector.data); - var operation = subtle - .verify(algorithm, vector.publicKey, vector.signature, plaintext) - .then( - function (is_verified) { - assert_true(is_verified, 'Signature verified'); - }, - function (err) { - assert_unreached( - 'Verification should not throw error ' + - vector.name + - ': ' + - err.message + - "'" - ); - } - ); - - plaintext[0] = 255 - plaintext[0]; - return operation; - }, vector.name + ' with altered plaintext after call'); - }, - function (err) { - promise_test(function (test) { - assert_unreached( - 'importVectorKeys failed for ' + - vector.name + - ". Message: ''" + - err.message + - "''" - ); - }, 'importVectorKeys step: ' + - vector.name + - ' with altered plaintext after call'); - } - ); - - all_promises.push(promise); - }); - - // Check for failed verification if plaintext is transferred during call. - testVectors.forEach(function (vector) { - var promise = importVectorKeys(vector, ['verify'], ['sign']).then( - function (vectors) { - promise_test(function (test) { - var plaintext = copyBuffer(vector.data); - var operation = subtle - .verify( - { - get name() { - plaintext.buffer.transfer(); - return vector.algorithmName; - }, - }, - vector.publicKey, - vector.signature, - plaintext - ) - .then( - function (is_verified) { - assert_false(is_verified, 'Signature is NOT verified'); - }, - function (err) { - assert_unreached( - 'Verification should not throw error ' + - vector.name + - ': ' + - err.message + - "'" - ); - } - ); - - return operation; - }, vector.name + ' with transferred plaintext during call'); - }, - function (err) { - promise_test(function (test) { - assert_unreached( - 'importVectorKeys failed for ' + - vector.name + - ". Message: ''" + - err.message + - "''" - ); - }, 'importVectorKeys step: ' + - vector.name + - ' with transferred plaintext during call'); - } - ); - - all_promises.push(promise); - }); - - // Check for successful verification even if plaintext is transferred after call. - testVectors.forEach(function (vector) { - var promise = importVectorKeys(vector, ['verify'], ['sign']).then( - function (vectors) { - var algorithm = vector.algorithmName; - promise_test(function (test) { - var plaintext = copyBuffer(vector.data); - var operation = subtle - .verify(algorithm, vector.publicKey, vector.signature, plaintext) - .then( - function (is_verified) { - assert_true(is_verified, 'Signature verified'); - }, - function (err) { - assert_unreached( - 'Verification should not throw error ' + - vector.name + - ': ' + - err.message + - "'" - ); - } - ); - - plaintext.buffer.transfer(); - return operation; - }, vector.name + ' with transferred plaintext after call'); - }, - function (err) { - promise_test(function (test) { - assert_unreached( - 'importVectorKeys failed for ' + - vector.name + - ". Message: ''" + - err.message + - "''" - ); - }, 'importVectorKeys step: ' + - vector.name + - ' with transferred plaintext after call'); - } - ); - - all_promises.push(promise); - }); - - // Check for failures due to using privateKey to verify. - testVectors.forEach(function (vector) { - var promise = importVectorKeys(vector, ['verify'], ['sign']).then( - function (vectors) { - var algorithm = vector.algorithmName; - promise_test(function (test) { - return subtle - .verify(algorithm, vector.privateKey, vector.signature, vector.data) - .then( - function (plaintext) { - assert_unreached( - 'Should have thrown error for using privateKey to verify in ' + - vector.name + - ': ' + - err.message + - "'" - ); - }, - function (err) { - assert_equals( - err.name, - 'InvalidAccessError', - "Should throw InvalidAccessError instead of '" + - err.message + - "'" - ); - } - ); - }, vector.name + ' using privateKey to verify'); - }, - function (err) { - promise_test(function (test) { - assert_unreached( - 'importVectorKeys failed for ' + - vector.name + - ". Message: ''" + - err.message + - "''" - ); - }, 'importVectorKeys step: ' + - vector.name + - ' using privateKey to verify'); - } - ); - - all_promises.push(promise); - }); - - // Check for failures due to using publicKey to sign. - testVectors.forEach(function (vector) { - var promise = importVectorKeys(vector, ['verify'], ['sign']).then( - function (vectors) { - var algorithm = vector.algorithmName; - promise_test(function (test) { - return subtle.sign(algorithm, vector.publicKey, vector.data).then( - function (signature) { - assert_unreached( - 'Should have thrown error for using publicKey to sign in ' + - vector.name + - ': ' + - err.message + - "'" - ); - }, - function (err) { - assert_equals( - err.name, - 'InvalidAccessError', - "Should throw InvalidAccessError instead of '" + - err.message + - "'" - ); - } - ); - }, vector.name + ' using publicKey to sign'); - }, - function (err) { - promise_test(function (test) { - assert_unreached( - 'importVectorKeys failed for ' + - vector.name + - ". Message: ''" + - err.message + - "''" - ); - }, 'importVectorKeys step: ' + - vector.name + - ' using publicKey to sign'); - } - ); - - all_promises.push(promise); - }); - - // Check for failures due to no "verify" usage. - testVectors.forEach(function (originalVector) { - var vector = Object.assign({}, originalVector); - - var promise = importVectorKeys(vector, [], ['sign']).then( - function (vectors) { - var algorithm = vector.algorithmName; - promise_test(function (test) { - return subtle - .verify(algorithm, vector.publicKey, vector.signature, vector.data) - .then( - function (plaintext) { - assert_unreached( - 'Should have thrown error for no verify usage in ' + - vector.name + - ': ' + - err.message + - "'" - ); - }, - function (err) { - assert_equals( - err.name, - 'InvalidAccessError', - "Should throw InvalidAccessError instead of '" + - err.message + - "'" - ); - } - ); - }, vector.name + ' no verify usage'); - }, - function (err) { - promise_test(function (test) { - assert_unreached( - 'importVectorKeys failed for ' + - vector.name + - ". Message: ''" + - err.message + - "''" - ); - }, 'importVectorKeys step: ' + vector.name + ' no verify usage'); - } - ); - - all_promises.push(promise); - }); - - // Check for successful signing and verification. - testVectors.forEach(function (vector) { - var promise = importVectorKeys(vector, ['verify'], ['sign']).then( - function (vectors) { - var algorithm = vector.algorithmName; - promise_test(function (test) { - return subtle.sign(algorithm, vector.privateKey, vector.data).then( - function (signature) { - // Can we verify the signature? - return subtle - .verify(algorithm, vector.publicKey, signature, vector.data) - .then( - function (is_verified) { - assert_true(is_verified, 'Round trip verification works'); - return signature; - }, - function (err) { - assert_unreached( - 'verify error for test ' + - vector.name + - ': ' + - err.message + - "'" - ); - } - ); - }, - function (err) { - assert_unreached( - 'sign error for test ' + vector.name + ": '" + err.message + "'" - ); - } - ); - }, vector.name + ' round trip'); - }, - function (err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested signing or verifying - promise_test(function (test) { - assert_unreached( - 'importVectorKeys failed for ' + - vector.name + - ". Message: ''" + - err.message + - "''" - ); - }, 'importVectorKeys step: ' + vector.name + ' round trip'); - } - ); - - all_promises.push(promise); - }); - - // Test signing with the wrong algorithm - testVectors.forEach(function (vector) { - // Want to get the key for the wrong algorithm - var promise = subtle - .generateKey({ name: 'HMAC', hash: 'SHA-1' }, false, ['sign', 'verify']) - .then( - function (wrongKey) { - var algorithm = vector.algorithmName; - return importVectorKeys(vector, ['verify'], ['sign']).then( - function (vectors) { - promise_test(function (test) { - var operation = subtle - .sign(algorithm, wrongKey, vector.data) - .then( - function (signature) { - assert_unreached( - 'Signing should not have succeeded for ' + vector.name - ); - }, - function (err) { - assert_equals( - err.name, - 'InvalidAccessError', - "Should have thrown InvalidAccessError instead of '" + - err.message + - "'" - ); - } - ); - - return operation; - }, vector.name + ' signing with wrong algorithm name'); - }, - function (err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function (test) { - assert_unreached( - 'importVectorKeys failed for ' + - vector.name + - ". Message: ''" + - err.message + - "''" - ); - }, 'importVectorKeys step: ' + - vector.name + - ' signing with wrong algorithm name'); - } - ); - }, - function (err) { - promise_test(function (test) { - assert_unreached( - 'Generate wrong key for test ' + - vector.name + - " failed: '" + - err.message + - "'" - ); - }, 'generate wrong key step: ' + - vector.name + - ' signing with wrong algorithm name'); - } - ); - - all_promises.push(promise); - }); - - // Test verification with the wrong algorithm - testVectors.forEach(function (vector) { - // Want to get the key for the wrong algorithm - var promise = subtle - .generateKey({ name: 'HMAC', hash: 'SHA-1' }, false, ['sign', 'verify']) - .then( - function (wrongKey) { - return importVectorKeys(vector, ['verify'], ['sign']).then( - function (vectors) { - var algorithm = vector.algorithmName; - promise_test(function (test) { - var operation = subtle - .verify(algorithm, wrongKey, vector.signature, vector.data) - .then( - function (signature) { - assert_unreached( - 'Verifying should not have succeeded for ' + vector.name - ); - }, - function (err) { - assert_equals( - err.name, - 'InvalidAccessError', - "Should have thrown InvalidAccessError instead of '" + - err.message + - "'" - ); - } - ); - - return operation; - }, vector.name + ' verifying with wrong algorithm name'); - }, - function (err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function (test) { - assert_unreached( - 'importVectorKeys failed for ' + - vector.name + - ". Message: ''" + - err.message + - "''" - ); - }, 'importVectorKeys step: ' + - vector.name + - ' verifying with wrong algorithm name'); - } - ); - }, - function (err) { - promise_test(function (test) { - assert_unreached( - 'Generate wrong key for test ' + - vector.name + - " failed: '" + - err.message + - "'" - ); - }, 'generate wrong key step: ' + - vector.name + - ' verifying with wrong algorithm name'); - } - ); - - all_promises.push(promise); - }); - - // Test verification fails with wrong signature - testVectors.forEach(function (vector) { - var promise = importVectorKeys(vector, ['verify'], ['sign']).then( - function (vectors) { - var algorithm = vector.algorithmName; - var signature = copyBuffer(vector.signature); - signature[0] = 255 - signature[0]; - promise_test(function (test) { - var operation = subtle - .verify(algorithm, vector.publicKey, signature, vector.data) - .then( - function (is_verified) { - assert_false(is_verified, 'Signature NOT verified'); - }, - function (err) { - assert_unreached( - 'Verification should not throw error ' + - vector.name + - ': ' + - err.message + - "'" - ); - } - ); - - return operation; - }, vector.name + ' verification failure due to altered signature'); - }, - function (err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function (test) { - assert_unreached( - 'importVectorKeys failed for ' + - vector.name + - ". Message: ''" + - err.message + - "''" - ); - }, 'importVectorKeys step: ' + - vector.name + - ' verification failure due to altered signature'); - } - ); - - all_promises.push(promise); - }); - - // Test verification fails with short (odd length) signature - testVectors.forEach(function (vector) { - var promise = importVectorKeys(vector, ['verify'], ['sign']).then( - function (vectors) { - var algorithm = vector.algorithmName; - var signature = vector.signature.slice(1); // Skip the first byte - promise_test(function (test) { - var operation = subtle - .verify(algorithm, vector.publicKey, signature, vector.data) - .then( - function (is_verified) { - assert_false(is_verified, 'Signature NOT verified'); - }, - function (err) { - assert_unreached( - 'Verification should not throw error ' + - vector.name + - ': ' + - err.message + - "'" - ); - } - ); - - return operation; - }, vector.name + ' verification failure due to shortened signature'); - }, - function (err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function (test) { - assert_unreached( - 'importVectorKeys failed for ' + - vector.name + - ". Message: ''" + - err.message + - "''" - ); - }, 'importVectorKeys step: ' + - vector.name + - ' verification failure due to shortened signature'); - } - ); - - all_promises.push(promise); - }); - - // Test verification fails with wrong plaintext - testVectors.forEach(function (vector) { - var promise = importVectorKeys(vector, ['verify'], ['sign']).then( - function (vectors) { - var algorithm = vector.algorithmName; - var plaintext = copyBuffer(vector.data); - plaintext[0] = 255 - plaintext[0]; - promise_test(function (test) { - var operation = subtle - .verify(algorithm, vector.publicKey, vector.signature, plaintext) - .then( - function (is_verified) { - assert_false(is_verified, 'Signature NOT verified'); - }, - function (err) { - assert_unreached( - 'Verification should not throw error ' + - vector.name + - ': ' + - err.message + - "'" - ); - } - ); - - return operation; - }, vector.name + ' verification failure due to altered plaintext'); - }, - function (err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function (test) { - assert_unreached( - 'importVectorKeys failed for ' + - vector.name + - ". Message: ''" + - err.message + - "''" - ); - }, 'importVectorKeys step: ' + - vector.name + - ' verification failure due to altered plaintext'); - } - ); - - all_promises.push(promise); - }); - - // Test invalid signatures - invalidTestVectors.forEach(function (vector) { - var promise = importVectorKeys(vector, ['verify'], ['sign']).then( - function (vectors) { - var algorithm = vector.algorithmName; - promise_test(function (test) { - var operation = subtle - .verify(algorithm, vector.publicKey, vector.signature, vector.data) - .then( - function (is_verified) { - assert_false(is_verified, 'Signature unexpectedly verified'); - }, - function (err) { - assert_unreached( - 'Verification should not throw error ' + - vector.name + - ': ' + - err.message + - "'" - ); - } - ); - - return operation; - }, vector.name + ' verification'); - }, - function (err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function (test) { - assert_unreached( - 'importVectorKeys failed for ' + - vector.name + - ". Message: ''" + - err.message + - "''" - ); - }, 'importVectorKeys step: ' + vector.name + ' verification'); - } - ); - - all_promises.push(promise); - }); - - promise_test(function () { - return Promise.all(all_promises) - .then(function () { - done(); - }) - .catch(function () { - done(); - }); - }, 'setup'); - - // A test vector has all needed fields for signing and verifying, EXCEPT that the - // key field may be null. This function replaces that null with the Correct - // CryptoKey object. - // - // Returns a Promise that yields an updated vector on success. - function importVectorKeys(vector, publicKeyUsages, privateKeyUsages) { - var publicPromise, privatePromise; - - if (vector.publicKey !== null) { - publicPromise = new Promise(function (resolve, reject) { - resolve(vector); - }); - } else { - publicPromise = subtle - .importKey( - vector.publicKeyFormat, - vector.publicKeyBuffer, - { name: vector.algorithmName }, - false, - publicKeyUsages - ) - .then(function (key) { - vector.publicKey = key; - return vector; - }); // Returns a copy of the sourceBuffer it is sent. - } - - if (vector.privateKey !== null) { - privatePromise = new Promise(function (resolve, reject) { - resolve(vector); - }); - } else { - privatePromise = subtle - .importKey( - vector.privateKeyFormat, - vector.privateKeyBuffer, - { name: vector.algorithmName }, - false, - privateKeyUsages - ) - .then(function (key) { - vector.privateKey = key; - return vector; - }); - } - - return Promise.all([publicPromise, privatePromise]); - } - - return; } diff --git a/test/fixtures/wpt/WebCryptoAPI/sign_verify/mldsa.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/sign_verify/mldsa.tentative.https.any.js index be336b349846..253cc85e258f 100644 --- a/test/fixtures/wpt/WebCryptoAPI/sign_verify/mldsa.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/sign_verify/mldsa.tentative.https.any.js @@ -1,6 +1,8 @@ // META: title=WebCryptoAPI: sign() and verify() Using ML-DSA // META: script=../util/helpers.js +// META: script=../util/mldsa_key_fixtures.js // META: script=mldsa_vectors.js +// META: script=signature.js // META: script=mldsa.js // META: timeout=long diff --git a/test/fixtures/wpt/WebCryptoAPI/sign_verify/mldsa_vectors.js b/test/fixtures/wpt/WebCryptoAPI/sign_verify/mldsa_vectors.js index a035821b7e35..021060a1f35b 100644 --- a/test/fixtures/wpt/WebCryptoAPI/sign_verify/mldsa_vectors.js +++ b/test/fixtures/wpt/WebCryptoAPI/sign_verify/mldsa_vectors.js @@ -1,393 +1,4 @@ -// PKCS#8 private keys for ML-DSA variants -var pkcs8 = { - 'ML-DSA-44': new Uint8Array([ - 48, 52, 2, 1, 0, 48, 11, 6, 9, 96, 134, 72, 1, 101, 3, 4, 3, 17, 4, 34, 128, - 32, 153, 21, 95, 99, 48, 150, 218, 124, 190, 8, 122, 137, 72, 184, 79, 118, - 123, 16, 249, 1, 200, 35, 194, 64, 177, 221, 43, 200, 112, 5, 201, 62, - ]), - 'ML-DSA-65': new Uint8Array([ - 48, 52, 2, 1, 0, 48, 11, 6, 9, 96, 134, 72, 1, 101, 3, 4, 3, 18, 4, 34, 128, - 32, 132, 164, 137, 75, 123, 70, 164, 178, 3, 156, 206, 16, 195, 26, 133, - 186, 176, 195, 102, 48, 254, 35, 29, 66, 103, 17, 67, 152, 38, 7, 130, 139, - ]), - 'ML-DSA-87': new Uint8Array([ - 48, 52, 2, 1, 0, 48, 11, 6, 9, 96, 134, 72, 1, 101, 3, 4, 3, 19, 4, 34, 128, - 32, 161, 80, 109, 145, 76, 109, 101, 140, 117, 39, 228, 51, 151, 221, 109, - 76, 37, 246, 164, 121, 116, 51, 90, 76, 208, 59, 254, 105, 131, 68, 18, 81, - ]), -}; - -// SPKI public keys for ML-DSA variants -var spki = { - 'ML-DSA-44': new Uint8Array([ - 48, 130, 5, 50, 48, 11, 6, 9, 96, 134, 72, 1, 101, 3, 4, 3, 17, 3, 130, 5, - 33, 0, 85, 152, 213, 68, 198, 20, 177, 84, 200, 188, 33, 104, 36, 161, 193, - 127, 226, 151, 48, 107, 122, 191, 89, 86, 188, 3, 245, 199, 18, 79, 168, - 192, 218, 218, 223, 227, 84, 133, 41, 187, 9, 183, 14, 222, 155, 137, 84, - 111, 138, 97, 234, 152, 52, 15, 163, 47, 227, 218, 19, 20, 229, 93, 99, 252, - 155, 213, 30, 241, 158, 211, 213, 191, 155, 73, 211, 145, 59, 194, 75, 140, - 3, 161, 149, 139, 48, 172, 155, 172, 120, 234, 142, 79, 78, 116, 215, 184, - 50, 182, 162, 192, 93, 221, 179, 216, 70, 186, 92, 93, 51, 190, 61, 173, - 105, 206, 9, 208, 52, 54, 208, 252, 115, 176, 146, 118, 23, 0, 5, 41, 151, - 121, 241, 246, 193, 206, 212, 160, 181, 7, 99, 220, 78, 96, 123, 142, 35, - 107, 37, 218, 138, 139, 228, 207, 166, 132, 87, 36, 116, 251, 174, 10, 41, - 196, 171, 26, 212, 90, 213, 223, 141, 87, 232, 59, 46, 173, 16, 247, 173, 4, - 219, 165, 234, 8, 217, 233, 163, 13, 10, 160, 22, 87, 232, 2, 9, 92, 177, - 35, 67, 55, 104, 51, 204, 231, 81, 209, 62, 31, 117, 56, 141, 78, 109, 148, - 118, 191, 93, 193, 59, 30, 88, 237, 19, 169, 14, 11, 150, 102, 215, 144, 69, - 246, 32, 159, 110, 49, 75, 78, 225, 121, 184, 206, 234, 126, 171, 164, 43, - 237, 244, 63, 83, 70, 136, 213, 244, 121, 184, 34, 201, 249, 95, 64, 165, - 99, 14, 195, 231, 18, 121, 20, 156, 80, 231, 133, 197, 0, 94, 195, 22, 251, - 255, 174, 213, 103, 75, 88, 58, 138, 66, 37, 85, 162, 15, 242, 29, 49, 147, - 191, 163, 170, 109, 195, 22, 63, 197, 149, 117, 100, 36, 81, 115, 203, 126, - 62, 86, 103, 193, 182, 69, 238, 233, 162, 62, 248, 132, 158, 212, 208, 187, - 127, 212, 198, 169, 245, 26, 153, 28, 207, 85, 65, 145, 200, 23, 196, 38, - 64, 49, 54, 233, 185, 72, 156, 86, 230, 127, 152, 108, 184, 240, 109, 8, - 103, 228, 206, 142, 73, 74, 214, 52, 182, 203, 82, 201, 175, 188, 111, 42, - 232, 8, 177, 131, 47, 237, 92, 120, 210, 124, 48, 185, 215, 137, 36, 70, - 162, 164, 119, 0, 155, 20, 57, 33, 27, 220, 77, 254, 233, 190, 106, 135, 21, - 194, 57, 238, 95, 162, 78, 164, 33, 210, 215, 43, 100, 96, 232, 87, 19, 43, - 65, 240, 183, 17, 131, 247, 97, 241, 7, 111, 159, 40, 252, 45, 228, 76, 71, - 46, 85, 181, 54, 41, 135, 162, 144, 227, 128, 121, 173, 207, 119, 54, 19, - 197, 23, 231, 176, 125, 190, 32, 76, 60, 34, 24, 160, 42, 73, 190, 124, 99, - 5, 9, 214, 6, 220, 177, 206, 79, 222, 10, 142, 250, 63, 179, 67, 21, 159, - 57, 126, 239, 28, 238, 240, 107, 79, 185, 174, 232, 168, 146, 128, 229, 119, - 19, 21, 33, 239, 193, 42, 178, 152, 124, 24, 203, 131, 193, 93, 162, 2, 208, - 231, 20, 203, 232, 47, 54, 114, 255, 236, 97, 99, 156, 15, 160, 75, 60, 111, - 59, 35, 25, 230, 43, 91, 170, 161, 74, 70, 179, 180, 251, 71, 197, 240, 104, - 42, 39, 202, 206, 12, 115, 249, 138, 55, 252, 216, 61, 185, 121, 76, 137, - 172, 166, 88, 92, 130, 18, 52, 67, 13, 187, 49, 147, 212, 77, 74, 56, 59, - 123, 99, 205, 36, 137, 96, 111, 148, 121, 157, 2, 83, 246, 86, 156, 152, 98, - 172, 77, 244, 214, 225, 184, 240, 121, 144, 56, 213, 161, 43, 67, 4, 161, - 104, 202, 91, 134, 247, 108, 24, 46, 187, 63, 216, 50, 125, 120, 17, 216, - 22, 228, 156, 253, 7, 180, 15, 130, 180, 72, 71, 169, 3, 236, 247, 11, 170, - 32, 76, 236, 225, 133, 250, 20, 235, 200, 143, 89, 25, 158, 49, 158, 164, - 213, 221, 81, 120, 241, 150, 210, 19, 79, 165, 24, 35, 170, 182, 242, 255, - 143, 171, 148, 140, 41, 207, 186, 98, 224, 16, 152, 224, 38, 110, 175, 169, - 111, 132, 201, 178, 114, 25, 196, 50, 149, 158, 193, 180, 101, 183, 92, 109, - 131, 102, 119, 123, 78, 107, 223, 4, 1, 206, 140, 130, 237, 205, 36, 18, - 180, 197, 154, 26, 236, 140, 173, 230, 101, 35, 189, 121, 104, 21, 75, 81, - 224, 186, 212, 81, 107, 66, 244, 235, 64, 90, 206, 39, 44, 43, 162, 187, 63, - 229, 217, 154, 185, 157, 24, 125, 252, 91, 136, 59, 47, 182, 200, 73, 19, - 137, 132, 81, 16, 234, 227, 210, 32, 16, 160, 188, 250, 27, 190, 164, 53, - 244, 219, 199, 177, 146, 117, 50, 99, 72, 235, 37, 154, 72, 51, 203, 61, 39, - 230, 34, 132, 117, 217, 167, 201, 42, 17, 76, 72, 103, 172, 93, 169, 29, 76, - 88, 178, 226, 32, 53, 190, 60, 210, 132, 113, 198, 26, 70, 179, 47, 34, 184, - 88, 178, 208, 1, 196, 89, 136, 167, 33, 38, 9, 255, 89, 202, 27, 93, 229, - 100, 192, 24, 234, 200, 186, 125, 231, 212, 188, 11, 29, 51, 189, 70, 147, - 176, 231, 81, 16, 114, 152, 159, 21, 124, 185, 208, 50, 74, 211, 113, 207, - 35, 54, 173, 205, 133, 52, 167, 199, 87, 158, 120, 33, 204, 163, 146, 233, - 21, 61, 28, 102, 48, 232, 184, 15, 219, 238, 240, 215, 222, 239, 3, 110, - 180, 95, 103, 147, 236, 10, 57, 195, 159, 231, 50, 92, 145, 165, 44, 204, - 121, 187, 9, 210, 80, 86, 251, 169, 132, 236, 248, 23, 207, 222, 227, 13, - 53, 1, 88, 69, 105, 13, 238, 202, 251, 194, 245, 14, 38, 1, 245, 157, 212, - 162, 182, 217, 230, 115, 139, 175, 219, 199, 74, 124, 186, 158, 3, 220, 87, - 220, 177, 85, 13, 58, 168, 223, 6, 238, 156, 80, 121, 44, 166, 176, 0, 48, - 98, 70, 93, 78, 50, 192, 16, 186, 2, 233, 105, 105, 120, 195, 17, 100, 141, - 214, 158, 144, 63, 4, 88, 190, 101, 209, 55, 119, 46, 128, 117, 225, 121, - 204, 195, 19, 61, 170, 116, 251, 225, 230, 28, 27, 249, 84, 195, 224, 190, - 60, 212, 83, 3, 148, 204, 4, 103, 50, 233, 175, 207, 47, 51, 216, 79, 251, - 150, 81, 171, 7, 145, 55, 188, 187, 217, 200, 155, 246, 85, 42, 123, 18, - 112, 192, 116, 163, 40, 187, 132, 192, 210, 188, 106, 117, 217, 185, 183, - 202, 33, 11, 205, 10, 61, 52, 15, 66, 131, 121, 112, 26, 96, 166, 241, 1, - 68, 206, 80, 92, 132, 83, 89, 126, 135, 157, 4, 202, 16, 5, 131, 112, 62, - 56, 234, 176, 213, 119, 205, 203, 17, 106, 156, 117, 251, 135, 21, 73, 219, - 238, 3, 88, 21, 71, 136, 118, 0, 7, 106, 151, 200, 221, 179, 206, 50, 198, - 27, 118, 181, 27, 85, 35, 248, 44, 57, 15, 221, 97, 121, 4, 167, 111, 182, - 207, 195, 52, 134, 195, 128, 173, 111, 98, 152, 29, 138, 197, 175, 171, 247, - 194, 20, 134, 209, 232, 94, 17, 203, 139, 30, 237, 187, 243, 16, 180, 43, - 105, 236, 66, 175, 170, 139, 24, 99, 28, 225, 141, 96, 250, 119, 0, 111, - 212, 34, 217, 42, 134, 88, 78, 76, 126, 169, 168, 59, 154, 93, 54, 43, 161, - 29, 111, 124, 59, 225, 52, 86, 147, 38, 151, 161, 36, 119, 204, 164, 121, - 46, 186, 65, 84, 70, 38, 15, 203, 48, 168, 235, 231, 30, 55, 95, 36, 10, 20, - 166, 109, 8, 18, 109, 251, 213, 82, 142, 240, 49, 249, 180, 78, 69, - ]), - 'ML-DSA-65': new Uint8Array([ - 48, 130, 7, 178, 48, 11, 6, 9, 96, 134, 72, 1, 101, 3, 4, 3, 18, 3, 130, 7, - 161, 0, 216, 177, 233, 60, 151, 24, 246, 66, 175, 161, 192, 118, 9, 177, 87, - 232, 5, 216, 49, 254, 251, 160, 51, 216, 250, 171, 229, 104, 149, 117, 135, - 107, 5, 239, 244, 167, 83, 57, 49, 153, 29, 135, 108, 138, 117, 236, 120, - 65, 89, 65, 17, 201, 127, 147, 246, 103, 238, 204, 25, 83, 240, 29, 173, - 127, 140, 1, 88, 40, 43, 134, 51, 19, 125, 131, 224, 50, 167, 82, 20, 217, - 215, 162, 41, 95, 215, 56, 130, 226, 177, 216, 20, 169, 133, 85, 140, 9, - 105, 172, 54, 121, 0, 87, 202, 18, 93, 96, 147, 103, 127, 164, 63, 197, 97, - 49, 230, 125, 53, 80, 64, 20, 239, 29, 90, 118, 102, 221, 177, 6, 220, 220, - 170, 107, 107, 18, 138, 125, 138, 70, 66, 60, 185, 232, 209, 4, 100, 17, - 118, 24, 181, 110, 241, 50, 250, 138, 209, 19, 84, 220, 61, 96, 80, 128, 81, - 101, 160, 9, 5, 53, 33, 112, 60, 59, 195, 79, 115, 190, 101, 93, 56, 171, - 146, 51, 82, 233, 66, 225, 226, 211, 72, 58, 9, 74, 222, 185, 175, 211, 156, - 164, 68, 188, 119, 46, 14, 64, 160, 13, 207, 60, 81, 68, 108, 148, 59, 88, - 88, 92, 88, 171, 249, 204, 160, 137, 222, 234, 168, 233, 3, 86, 224, 174, - 105, 224, 1, 177, 184, 230, 236, 30, 85, 249, 56, 105, 211, 50, 83, 168, - 139, 28, 175, 181, 22, 89, 166, 215, 152, 218, 184, 111, 65, 24, 82, 71, - 185, 100, 172, 66, 178, 6, 215, 164, 252, 56, 40, 198, 207, 152, 110, 186, - 207, 39, 235, 179, 38, 215, 88, 105, 109, 177, 130, 91, 5, 223, 164, 78, - 241, 176, 125, 197, 94, 100, 40, 214, 251, 239, 253, 88, 154, 14, 75, 254, - 94, 210, 86, 244, 51, 95, 168, 139, 213, 73, 87, 151, 209, 150, 126, 88, 69, - 251, 116, 157, 122, 96, 212, 206, 42, 218, 38, 85, 184, 50, 246, 188, 35, - 72, 60, 226, 155, 246, 86, 209, 110, 133, 161, 129, 126, 80, 154, 238, 64, - 64, 170, 156, 177, 225, 52, 87, 42, 88, 154, 174, 246, 30, 84, 143, 221, 51, - 27, 65, 60, 40, 22, 120, 42, 145, 34, 82, 235, 79, 20, 215, 211, 231, 151, - 108, 119, 53, 116, 190, 13, 139, 199, 189, 84, 54, 186, 222, 90, 116, 253, - 227, 207, 104, 209, 118, 42, 144, 94, 22, 219, 198, 211, 216, 171, 75, 245, - 61, 240, 157, 108, 81, 19, 238, 39, 120, 210, 242, 63, 126, 6, 15, 18, 97, - 232, 207, 184, 84, 239, 72, 115, 90, 95, 112, 78, 45, 201, 13, 102, 208, - 151, 146, 253, 153, 177, 115, 14, 194, 184, 107, 118, 120, 63, 105, 89, 144, - 60, 242, 80, 106, 32, 11, 204, 170, 165, 221, 182, 31, 187, 159, 216, 118, - 218, 207, 182, 107, 136, 211, 162, 231, 196, 128, 83, 251, 192, 189, 149, 1, - 245, 36, 146, 159, 11, 116, 30, 191, 141, 182, 157, 227, 91, 88, 72, 224, - 55, 195, 96, 245, 135, 249, 142, 16, 229, 237, 27, 60, 2, 91, 138, 82, 197, - 210, 40, 8, 123, 172, 202, 207, 119, 199, 190, 102, 40, 141, 174, 93, 211, - 219, 134, 105, 26, 103, 100, 102, 62, 130, 224, 135, 173, 82, 224, 200, 213, - 76, 211, 38, 181, 16, 97, 99, 75, 14, 42, 162, 223, 237, 141, 1, 29, 140, - 191, 146, 49, 236, 179, 88, 202, 220, 124, 239, 231, 131, 101, 134, 111, 28, - 54, 151, 172, 67, 167, 113, 96, 204, 63, 76, 169, 95, 14, 175, 149, 189, - 173, 39, 177, 102, 23, 158, 102, 236, 224, 70, 203, 190, 132, 230, 136, 3, - 28, 201, 131, 148, 164, 219, 181, 208, 26, 239, 111, 86, 35, 102, 133, 114, - 113, 180, 184, 82, 180, 106, 124, 248, 126, 87, 177, 165, 176, 204, 128, - 141, 179, 141, 34, 119, 160, 57, 206, 168, 95, 197, 110, 79, 60, 48, 170, - 125, 206, 147, 137, 156, 85, 46, 7, 193, 228, 150, 22, 46, 147, 51, 153, - 157, 248, 151, 253, 114, 58, 126, 38, 127, 19, 225, 99, 183, 235, 175, 90, - 166, 8, 233, 141, 10, 85, 232, 147, 7, 20, 137, 240, 84, 231, 86, 134, 50, - 212, 201, 6, 253, 18, 150, 114, 160, 140, 2, 254, 189, 152, 14, 68, 110, 50, - 134, 199, 73, 237, 56, 116, 110, 135, 36, 40, 14, 167, 50, 71, 81, 9, 178, - 54, 182, 247, 64, 32, 204, 116, 92, 131, 40, 30, 246, 188, 236, 182, 187, - 132, 239, 124, 136, 238, 146, 137, 247, 87, 52, 15, 78, 108, 135, 178, 101, - 70, 199, 193, 192, 144, 196, 106, 186, 141, 42, 101, 214, 196, 67, 175, 38, - 8, 189, 148, 166, 253, 221, 144, 119, 81, 1, 232, 175, 81, 237, 13, 188, - 220, 230, 47, 115, 184, 179, 0, 51, 118, 39, 22, 114, 232, 88, 15, 121, 216, - 130, 107, 173, 108, 175, 225, 113, 40, 223, 185, 6, 244, 227, 73, 38, 64, - 84, 10, 200, 53, 81, 179, 217, 106, 172, 59, 161, 70, 180, 70, 48, 56, 46, - 233, 133, 245, 57, 120, 154, 167, 49, 109, 188, 152, 245, 181, 1, 159, 247, - 44, 167, 152, 6, 191, 246, 38, 120, 141, 57, 241, 168, 60, 38, 6, 82, 248, - 87, 85, 0, 10, 22, 19, 44, 178, 63, 38, 78, 1, 210, 166, 140, 3, 199, 112, - 135, 155, 36, 13, 204, 124, 47, 5, 190, 103, 91, 205, 147, 248, 115, 177, - 196, 180, 234, 85, 35, 24, 182, 16, 207, 107, 167, 10, 54, 193, 146, 71, 95, - 45, 109, 184, 43, 101, 155, 184, 55, 171, 196, 136, 89, 227, 84, 183, 31, 0, - 137, 230, 146, 250, 6, 27, 225, 241, 11, 95, 124, 248, 133, 171, 149, 67, - 73, 19, 110, 104, 173, 86, 6, 246, 195, 196, 200, 175, 53, 18, 198, 223, - 140, 85, 208, 253, 204, 220, 255, 232, 88, 238, 20, 97, 24, 52, 13, 3, 179, - 62, 151, 101, 67, 33, 79, 253, 157, 253, 233, 197, 109, 130, 78, 11, 165, - 214, 200, 41, 157, 63, 46, 175, 251, 246, 225, 227, 199, 92, 107, 216, 58, - 124, 226, 202, 153, 92, 31, 250, 182, 92, 99, 0, 110, 18, 78, 228, 166, 190, - 67, 88, 245, 155, 139, 82, 152, 39, 204, 74, 140, 95, 82, 82, 160, 147, 144, - 33, 0, 242, 200, 22, 102, 160, 233, 102, 224, 42, 205, 240, 56, 95, 197, - 226, 175, 235, 240, 125, 10, 51, 12, 246, 150, 234, 173, 95, 132, 173, 174, - 1, 161, 23, 39, 52, 168, 87, 54, 4, 66, 201, 34, 155, 82, 133, 170, 76, 52, - 226, 109, 163, 19, 34, 184, 226, 39, 20, 75, 72, 201, 70, 188, 71, 182, 230, - 6, 19, 255, 8, 145, 193, 63, 81, 150, 24, 72, 89, 168, 74, 98, 173, 133, 67, - 227, 44, 252, 252, 227, 192, 125, 20, 227, 144, 24, 31, 48, 67, 67, 48, 94, - 163, 52, 219, 163, 225, 214, 214, 109, 211, 122, 213, 198, 90, 204, 40, 97, - 211, 121, 17, 28, 132, 246, 110, 230, 51, 197, 42, 162, 143, 199, 158, 215, - 210, 133, 60, 65, 127, 1, 153, 193, 22, 171, 250, 114, 204, 246, 255, 126, - 25, 96, 44, 164, 102, 172, 211, 23, 245, 122, 48, 221, 249, 138, 148, 134, - 206, 135, 246, 42, 235, 198, 89, 189, 45, 125, 204, 69, 193, 48, 29, 144, - 125, 224, 127, 66, 1, 134, 141, 224, 211, 193, 141, 69, 128, 75, 167, 244, - 160, 120, 54, 191, 214, 29, 40, 249, 15, 46, 68, 141, 91, 242, 91, 80, 252, - 109, 122, 154, 64, 153, 56, 65, 254, 106, 18, 4, 172, 171, 136, 80, 98, 79, - 133, 255, 4, 100, 191, 144, 171, 219, 46, 132, 181, 130, 228, 107, 68, 32, - 123, 201, 17, 67, 35, 144, 180, 160, 30, 125, 9, 55, 184, 172, 0, 159, 250, - 232, 83, 168, 162, 102, 158, 121, 208, 177, 116, 163, 160, 80, 241, 46, 156, - 58, 203, 240, 67, 176, 244, 170, 160, 115, 122, 141, 154, 101, 218, 178, - 119, 130, 195, 32, 207, 51, 149, 98, 51, 219, 57, 121, 216, 156, 101, 218, - 184, 220, 204, 41, 181, 149, 63, 80, 194, 11, 143, 164, 219, 23, 123, 141, - 119, 43, 94, 78, 175, 89, 165, 48, 167, 44, 45, 219, 197, 15, 202, 118, 116, - 245, 151, 218, 14, 199, 96, 27, 102, 206, 198, 123, 222, 178, 210, 20, 200, - 38, 25, 124, 58, 102, 92, 197, 107, 51, 5, 236, 125, 173, 198, 113, 144, - 108, 177, 22, 104, 223, 165, 39, 9, 84, 87, 124, 80, 153, 8, 212, 76, 2, 28, - 12, 90, 212, 129, 148, 212, 229, 63, 29, 200, 113, 171, 154, 107, 189, 202, - 22, 147, 7, 32, 253, 70, 37, 224, 98, 199, 129, 21, 54, 49, 52, 124, 84, 40, - 190, 194, 108, 73, 26, 15, 124, 87, 87, 198, 217, 122, 127, 82, 167, 131, - 59, 8, 172, 49, 162, 61, 64, 79, 196, 205, 65, 110, 75, 130, 128, 197, 182, - 251, 110, 141, 197, 184, 166, 244, 246, 217, 20, 105, 85, 42, 80, 251, 77, - 59, 204, 247, 179, 218, 181, 124, 209, 4, 28, 118, 234, 145, 237, 140, 106, - 54, 88, 82, 28, 235, 68, 221, 109, 139, 11, 166, 182, 63, 142, 194, 255, - 213, 219, 116, 158, 31, 224, 119, 126, 232, 160, 144, 1, 177, 92, 219, 162, - 49, 181, 116, 163, 104, 245, 193, 188, 26, 172, 15, 190, 135, 207, 106, 246, - 13, 132, 76, 189, 160, 25, 123, 26, 20, 48, 203, 59, 209, 69, 235, 103, 253, - 160, 108, 83, 206, 70, 98, 0, 2, 57, 162, 202, 63, 45, 89, 173, 201, 254, - 254, 253, 143, 21, 77, 131, 184, 234, 37, 68, 206, 69, 186, 179, 145, 147, - 135, 42, 137, 152, 253, 213, 240, 13, 122, 161, 218, 186, 180, 213, 162, - 150, 231, 63, 112, 182, 233, 86, 12, 225, 195, 133, 37, 28, 22, 147, 201, - 200, 197, 115, 3, 138, 194, 86, 79, 247, 27, 241, 149, 128, 197, 8, 11, 134, - 53, 118, 175, 248, 253, 114, 91, 31, 192, 253, 209, 111, 31, 228, 244, 184, - 179, 146, 145, 167, 137, 155, 184, 218, 38, 62, 187, 22, 181, 193, 93, 16, - 9, 195, 42, 198, 225, 100, 144, 148, 223, 184, 40, 117, 32, 131, 94, 93, 83, - 88, 125, 95, 220, 20, 206, 7, 228, 78, 54, 238, 178, 196, 38, 245, 95, 8, - 235, 106, 17, 175, 142, 193, 60, 179, 53, 244, 92, 147, 244, 218, 95, 127, - 251, 128, 42, 105, 82, 243, 224, 213, 25, 91, 151, 22, 201, 18, 25, 230, - 165, 85, 25, 249, 170, 160, 171, 210, 209, 32, 154, 124, 245, 60, 30, 255, - 138, 154, 29, 85, 156, 232, 177, 78, 14, 137, 52, 215, 247, 26, 211, 115, - 72, 20, 133, 232, 1, 151, 251, 63, 45, 120, 69, 49, 209, 130, 255, 2, 218, - 21, 251, 16, 86, 30, 62, 136, 92, 149, 60, 6, 125, 129, 145, 235, 102, 190, - 144, 248, 1, 53, 135, 21, 158, 44, 158, 230, 246, 172, 249, 161, 105, 204, - 49, 60, 70, 63, 127, 163, 231, 175, 174, 234, 147, 185, 62, 5, 244, 156, 4, - 31, 39, 156, 176, 154, 251, 166, 143, 212, 43, 30, 97, 50, 37, 176, 155, 77, - 149, 102, - ]), - 'ML-DSA-87': new Uint8Array([ - 48, 130, 10, 50, 48, 11, 6, 9, 96, 134, 72, 1, 101, 3, 4, 3, 19, 3, 130, 10, - 33, 0, 146, 184, 67, 40, 172, 27, 204, 27, 135, 22, 109, 223, 127, 23, 97, - 130, 198, 228, 199, 62, 178, 21, 173, 20, 88, 180, 205, 168, 17, 164, 135, - 92, 85, 146, 76, 194, 152, 80, 239, 157, 33, 21, 239, 182, 176, 254, 124, - 80, 135, 138, 87, 169, 103, 99, 87, 5, 91, 161, 239, 59, 18, 246, 148, 20, - 32, 60, 117, 245, 182, 156, 196, 230, 82, 117, 228, 211, 81, 45, 115, 217, - 23, 95, 138, 95, 103, 124, 32, 89, 187, 48, 251, 103, 81, 234, 76, 4, 57, - 197, 71, 48, 125, 169, 195, 147, 183, 142, 166, 8, 147, 7, 77, 240, 111, 44, - 168, 23, 89, 107, 95, 220, 75, 202, 44, 25, 244, 200, 160, 0, 174, 111, 107, - 204, 22, 36, 122, 191, 101, 33, 52, 252, 14, 47, 25, 109, 135, 48, 131, 253, - 195, 237, 60, 86, 14, 119, 85, 28, 182, 139, 136, 191, 59, 187, 90, 126, - 207, 168, 238, 184, 83, 77, 254, 208, 21, 57, 104, 188, 228, 134, 82, 249, - 190, 249, 163, 120, 111, 68, 225, 210, 131, 29, 151, 153, 146, 71, 163, 104, - 225, 194, 33, 64, 213, 92, 145, 253, 42, 32, 233, 95, 224, 72, 184, 119, - 192, 113, 253, 177, 153, 246, 240, 49, 103, 170, 229, 82, 69, 186, 36, 252, - 29, 124, 255, 25, 148, 5, 160, 159, 105, 157, 185, 25, 158, 122, 145, 30, - 245, 51, 205, 62, 56, 154, 23, 52, 0, 225, 177, 105, 195, 131, 177, 151, - 197, 114, 110, 128, 227, 127, 176, 28, 252, 217, 56, 61, 136, 148, 190, 124, - 108, 129, 62, 243, 235, 37, 70, 228, 233, 10, 67, 124, 120, 58, 164, 83, 57, - 80, 39, 204, 98, 28, 199, 136, 75, 12, 51, 255, 24, 130, 127, 19, 239, 160, - 94, 137, 75, 15, 82, 158, 252, 163, 43, 236, 193, 234, 27, 74, 69, 14, 179, - 171, 10, 169, 27, 138, 172, 213, 189, 222, 167, 110, 24, 11, 118, 151, 223, - 94, 154, 125, 9, 21, 137, 70, 128, 51, 102, 52, 105, 104, 157, 54, 186, 75, - 217, 226, 169, 71, 125, 177, 253, 218, 85, 236, 242, 25, 215, 147, 181, 104, - 242, 82, 75, 50, 165, 49, 102, 128, 82, 237, 170, 134, 162, 196, 56, 247, - 199, 138, 102, 118, 37, 66, 114, 165, 177, 156, 251, 39, 199, 12, 167, 246, - 169, 150, 108, 91, 192, 42, 68, 192, 244, 255, 107, 18, 191, 7, 73, 19, 174, - 28, 116, 66, 131, 96, 173, 60, 131, 190, 249, 219, 246, 71, 182, 124, 183, - 129, 101, 109, 95, 180, 78, 17, 140, 182, 62, 80, 195, 184, 253, 176, 169, - 153, 1, 29, 83, 39, 252, 150, 41, 219, 176, 48, 151, 108, 60, 255, 239, 0, - 85, 101, 193, 110, 204, 12, 254, 22, 136, 15, 154, 217, 88, 13, 28, 252, - 232, 48, 32, 33, 41, 221, 103, 227, 228, 177, 54, 175, 195, 106, 174, 140, - 54, 128, 108, 214, 228, 215, 118, 226, 206, 171, 21, 155, 162, 152, 135, - 203, 16, 170, 130, 100, 173, 155, 243, 80, 40, 98, 157, 248, 7, 101, 88, - 199, 218, 224, 141, 82, 238, 121, 92, 82, 97, 49, 31, 155, 61, 63, 84, 227, - 90, 143, 164, 59, 216, 101, 19, 35, 134, 2, 20, 18, 197, 97, 215, 169, 85, - 220, 75, 254, 91, 125, 144, 43, 65, 128, 29, 66, 77, 184, 172, 89, 123, 203, - 231, 254, 59, 18, 249, 204, 249, 220, 153, 84, 166, 63, 23, 108, 120, 145, - 216, 67, 223, 123, 248, 15, 253, 63, 191, 126, 84, 95, 98, 141, 66, 200, - 129, 194, 174, 30, 80, 48, 75, 113, 14, 102, 101, 218, 249, 14, 203, 24, 6, - 11, 89, 99, 56, 49, 17, 148, 160, 242, 101, 191, 102, 227, 115, 33, 107, 71, - 235, 6, 141, 68, 161, 162, 165, 227, 159, 82, 253, 54, 157, 214, 255, 141, - 151, 154, 134, 150, 93, 141, 97, 158, 244, 180, 135, 42, 10, 3, 148, 9, 152, - 149, 20, 18, 237, 253, 180, 136, 165, 13, 80, 195, 220, 43, 3, 178, 10, 127, - 144, 2, 207, 209, 246, 40, 110, 38, 133, 9, 22, 180, 11, 223, 116, 236, 205, - 186, 25, 183, 155, 165, 77, 206, 101, 255, 106, 223, 70, 10, 22, 176, 119, - 142, 163, 197, 178, 251, 216, 112, 237, 63, 201, 77, 219, 196, 2, 176, 48, - 15, 207, 91, 74, 236, 21, 8, 205, 126, 77, 28, 13, 26, 28, 202, 250, 100, - 79, 134, 209, 193, 78, 202, 58, 248, 124, 215, 64, 143, 244, 17, 23, 163, - 162, 241, 249, 49, 210, 168, 203, 213, 135, 77, 14, 29, 35, 193, 234, 58, - 12, 106, 165, 163, 251, 192, 115, 251, 7, 198, 189, 93, 207, 178, 246, 50, - 189, 185, 51, 45, 84, 140, 194, 34, 46, 92, 90, 136, 81, 81, 53, 52, 253, - 128, 247, 131, 243, 21, 207, 245, 141, 49, 178, 213, 214, 211, 8, 17, 234, - 133, 225, 104, 197, 186, 224, 117, 1, 173, 104, 17, 177, 161, 223, 71, 195, - 159, 194, 45, 177, 116, 26, 187, 193, 161, 213, 179, 158, 8, 122, 186, 122, - 191, 158, 5, 12, 178, 235, 78, 132, 78, 189, 16, 86, 110, 73, 51, 129, 255, - 242, 110, 63, 6, 53, 209, 110, 132, 236, 43, 239, 192, 221, 138, 1, 128, - 176, 0, 113, 85, 119, 201, 36, 188, 202, 9, 223, 98, 196, 42, 130, 158, 149, - 200, 150, 202, 132, 118, 153, 97, 54, 195, 154, 15, 45, 246, 129, 144, 255, - 231, 75, 25, 56, 47, 178, 98, 10, 106, 84, 56, 113, 161, 227, 37, 246, 1, - 245, 129, 173, 70, 186, 11, 28, 125, 198, 243, 225, 113, 130, 5, 138, 52, - 251, 194, 152, 105, 48, 214, 13, 246, 228, 75, 236, 194, 223, 177, 64, 150, - 97, 167, 20, 27, 74, 76, 166, 199, 239, 91, 240, 8, 22, 54, 41, 63, 35, 112, - 255, 251, 88, 252, 147, 173, 185, 43, 98, 83, 155, 230, 176, 55, 161, 8, 83, - 15, 110, 151, 241, 110, 168, 203, 190, 198, 218, 152, 144, 150, 58, 123, 11, - 123, 250, 104, 113, 198, 93, 1, 152, 51, 172, 140, 246, 115, 113, 229, 218, - 166, 200, 35, 123, 16, 133, 169, 191, 59, 103, 12, 114, 15, 60, 37, 4, 92, - 208, 54, 31, 79, 56, 225, 6, 11, 74, 107, 79, 225, 239, 16, 73, 249, 234, - 197, 129, 230, 97, 39, 115, 49, 96, 141, 41, 242, 225, 177, 214, 18, 103, - 34, 229, 37, 176, 241, 99, 82, 227, 195, 77, 32, 64, 4, 120, 49, 199, 209, - 139, 2, 4, 222, 233, 45, 151, 141, 142, 252, 41, 124, 231, 13, 144, 63, 212, - 252, 145, 34, 142, 232, 152, 84, 135, 87, 175, 46, 53, 139, 60, 168, 135, - 167, 101, 253, 127, 152, 138, 154, 31, 231, 198, 77, 89, 182, 9, 54, 103, - 119, 100, 218, 245, 44, 191, 74, 30, 152, 84, 22, 62, 159, 131, 163, 223, 3, - 51, 194, 241, 49, 9, 213, 43, 214, 201, 75, 158, 198, 22, 203, 209, 190, - 199, 189, 75, 4, 6, 72, 60, 241, 113, 171, 30, 42, 143, 73, 51, 72, 206, - 110, 175, 203, 195, 199, 15, 155, 208, 166, 121, 26, 132, 59, 44, 72, 155, - 7, 48, 122, 132, 224, 142, 3, 7, 21, 207, 11, 30, 112, 18, 149, 146, 127, - 41, 104, 197, 169, 86, 213, 108, 253, 111, 160, 5, 11, 202, 172, 233, 32, 5, - 52, 92, 124, 152, 162, 11, 88, 28, 166, 248, 141, 251, 38, 161, 53, 49, 136, - 246, 183, 85, 9, 165, 115, 108, 18, 208, 218, 129, 165, 163, 131, 34, 32, - 94, 226, 121, 93, 24, 87, 226, 105, 25, 242, 128, 198, 78, 26, 237, 21, 92, - 33, 121, 8, 119, 131, 140, 193, 14, 60, 139, 130, 19, 65, 96, 50, 5, 249, - 12, 27, 51, 23, 195, 89, 255, 47, 23, 109, 62, 202, 190, 5, 131, 92, 91, 39, - 27, 209, 132, 146, 95, 98, 66, 26, 230, 186, 236, 186, 162, 149, 81, 143, - 221, 21, 79, 171, 236, 21, 161, 19, 135, 10, 213, 168, 200, 135, 19, 221, - 177, 207, 106, 214, 194, 124, 220, 53, 45, 176, 245, 178, 189, 49, 242, 22, - 230, 154, 241, 146, 230, 187, 180, 244, 158, 145, 197, 225, 51, 150, 140, - 26, 175, 78, 142, 243, 232, 221, 137, 205, 130, 178, 54, 216, 136, 118, 212, - 33, 90, 206, 18, 224, 158, 44, 23, 144, 204, 24, 184, 48, 81, 233, 124, 20, - 222, 77, 119, 144, 22, 145, 241, 19, 206, 135, 252, 164, 114, 84, 37, 175, - 107, 67, 243, 183, 137, 213, 53, 236, 41, 73, 50, 34, 146, 218, 204, 68, - 235, 158, 150, 139, 133, 75, 248, 157, 7, 0, 53, 68, 44, 156, 110, 56, 197, - 209, 201, 0, 155, 225, 85, 35, 169, 193, 231, 36, 31, 142, 101, 168, 29, - 192, 31, 128, 81, 191, 253, 184, 153, 226, 214, 1, 27, 6, 0, 192, 36, 101, - 72, 105, 150, 226, 3, 21, 12, 127, 72, 250, 223, 240, 136, 249, 157, 129, - 247, 91, 178, 157, 208, 86, 146, 23, 176, 150, 35, 211, 155, 22, 207, 119, - 168, 167, 122, 180, 183, 106, 97, 138, 87, 96, 34, 141, 110, 145, 231, 226, - 35, 115, 232, 129, 54, 186, 128, 190, 238, 37, 169, 194, 37, 24, 237, 211, - 164, 111, 54, 88, 245, 125, 67, 78, 194, 11, 194, 235, 217, 87, 203, 14, - 220, 189, 107, 68, 94, 139, 66, 230, 5, 54, 64, 28, 246, 143, 75, 127, 239, - 243, 20, 251, 189, 246, 246, 151, 90, 219, 227, 242, 223, 205, 40, 124, 245, - 4, 189, 72, 39, 145, 110, 96, 120, 164, 27, 117, 146, 177, 30, 76, 173, 106, - 130, 228, 192, 189, 59, 167, 30, 127, 178, 164, 5, 133, 80, 199, 207, 216, - 189, 156, 93, 222, 150, 129, 81, 193, 180, 38, 59, 8, 214, 210, 95, 150, - 182, 175, 148, 43, 153, 169, 66, 62, 135, 140, 159, 89, 195, 253, 3, 132, - 180, 164, 244, 243, 232, 71, 196, 200, 158, 194, 114, 115, 193, 88, 161, - 185, 235, 247, 14, 126, 225, 176, 111, 17, 79, 77, 245, 80, 229, 174, 6, - 180, 156, 217, 85, 174, 201, 255, 237, 85, 83, 53, 188, 153, 98, 91, 193, - 21, 211, 49, 145, 196, 252, 52, 66, 226, 131, 203, 214, 130, 237, 194, 208, - 174, 102, 133, 220, 235, 222, 79, 232, 36, 21, 161, 248, 51, 185, 164, 156, - 95, 121, 65, 57, 233, 183, 29, 199, 105, 104, 12, 90, 195, 186, 81, 199, - 176, 1, 87, 16, 226, 192, 206, 185, 197, 46, 34, 75, 174, 153, 238, 15, 50, - 87, 226, 96, 26, 197, 202, 73, 235, 19, 140, 9, 79, 12, 52, 83, 76, 85, 146, - 234, 24, 151, 179, 178, 118, 58, 162, 223, 103, 69, 244, 231, 135, 167, 204, - 117, 166, 60, 237, 82, 63, 11, 4, 207, 10, 146, 54, 126, 191, 79, 133, 60, - 128, 34, 136, 170, 23, 84, 81, 38, 94, 9, 130, 245, 100, 115, 209, 34, 228, - 158, 101, 216, 135, 208, 207, 191, 169, 115, 252, 144, 139, 226, 252, 6, 44, - 221, 134, 170, 87, 11, 46, 124, 58, 219, 179, 238, 6, 98, 216, 18, 174, 42, - 12, 97, 126, 85, 245, 81, 220, 232, 135, 114, 21, 125, 135, 225, 182, 245, - 228, 223, 242, 62, 158, 35, 76, 6, 110, 25, 184, 206, 124, 237, 54, 252, - 199, 44, 78, 89, 0, 135, 44, 176, 57, 168, 36, 221, 173, 77, 214, 209, 60, - 1, 202, 238, 237, 61, 90, 47, 114, 230, 92, 238, 235, 18, 151, 220, 243, - 225, 163, 159, 139, 189, 253, 62, 225, 182, 202, 59, 7, 83, 99, 129, 118, - 175, 37, 246, 85, 119, 251, 246, 69, 180, 247, 37, 24, 194, 89, 158, 97, - 230, 247, 254, 145, 102, 89, 77, 68, 245, 3, 103, 83, 28, 45, 168, 30, 189, - 151, 112, 120, 215, 84, 90, 198, 85, 85, 129, 55, 127, 124, 28, 137, 229, - 139, 54, 88, 229, 105, 81, 212, 83, 28, 107, 250, 82, 164, 43, 24, 15, 57, - 206, 156, 19, 145, 95, 57, 169, 8, 128, 211, 29, 213, 195, 148, 27, 73, 186, - 221, 242, 11, 167, 78, 246, 133, 18, 118, 67, 236, 59, 19, 112, 254, 93, - 168, 157, 118, 0, 107, 248, 57, 149, 67, 222, 123, 225, 207, 251, 69, 218, - 56, 110, 162, 19, 25, 209, 209, 213, 200, 158, 70, 9, 100, 208, 77, 48, 255, - 151, 200, 0, 68, 230, 70, 120, 209, 29, 86, 225, 188, 189, 226, 101, 42, - 176, 32, 147, 121, 72, 151, 130, 217, 13, 66, 148, 84, 129, 215, 249, 164, - 174, 187, 80, 85, 185, 245, 108, 169, 119, 59, 178, 144, 229, 63, 194, 132, - 250, 131, 82, 161, 125, 126, 255, 252, 220, 204, 104, 231, 201, 136, 246, - 116, 43, 88, 233, 0, 43, 128, 214, 40, 59, 81, 147, 139, 132, 69, 24, 233, - 21, 14, 91, 230, 241, 19, 138, 163, 55, 13, 221, 47, 64, 140, 248, 6, 38, - 164, 16, 219, 63, 33, 180, 71, 151, 0, 234, 103, 58, 213, 222, 163, 95, 132, - 1, 178, 146, 66, 124, 242, 223, 102, 129, 192, 214, 194, 117, 162, 252, 246, - 143, 42, 70, 139, 97, 168, 64, 141, 190, 115, 126, 93, 175, 59, 49, 9, 184, - 88, 201, 100, 182, 142, 145, 244, 72, 128, 203, 49, 196, 5, 5, 18, 46, 34, - 87, 171, 132, 158, 128, 75, 194, 8, 242, 52, 156, 229, 245, 56, 245, 88, 14, - 195, 110, 166, 51, 158, 245, 195, 120, 17, 166, 66, 100, 212, 188, 243, 2, - 236, 90, 8, 16, 35, 151, 122, 175, 115, 168, 186, 191, 60, 71, 23, 81, 217, - 79, 203, 239, 61, 146, 247, 168, 112, 83, 102, 146, 222, 178, 45, 247, 63, - 23, 181, 3, 136, 208, 62, 154, 203, 35, 250, 238, 61, 98, 207, 90, 169, 175, - 36, 227, 9, 182, 78, 226, 99, 89, 67, 105, 185, 35, 242, 162, 54, 99, 60, - 148, 14, 118, 1, 26, 120, 62, 82, 62, 222, 34, 99, 58, 174, 145, 199, 190, - 21, 182, 117, 238, 13, 170, 29, 67, 149, 44, 90, 94, 181, 125, 182, 186, 82, - 55, 105, 253, 29, 212, 67, 134, 204, 227, 94, 255, 127, 72, 157, 140, 142, - 224, 77, 149, 29, 170, 45, 163, 214, 209, 46, 28, 125, 177, 111, 2, 92, 121, - 252, 166, 204, 227, 173, 51, 60, 162, 243, 202, 207, 103, 30, 153, 182, 116, - 182, 130, 98, 59, 25, 141, 239, 49, 224, 176, 27, 237, 218, 76, 68, 189, - 108, 185, 136, 255, 105, 150, 11, 153, 44, 248, 139, 199, 178, 235, 85, 115, - 121, 144, 87, 221, 50, 222, 238, 16, 20, 51, 190, 93, 248, 228, 84, 228, - 115, 31, 229, 227, 137, 180, 44, 115, 224, 119, 129, 181, 134, 224, 144, - 186, 123, 208, 118, 96, 101, 177, 191, 232, 171, 6, 17, 247, 187, 173, 84, - 70, 249, 19, 191, 116, 172, 126, 131, 216, 123, 225, 151, 55, 205, 177, 93, - 139, 117, - ]), -}; +var { pkcs8, spki } = getMldsaKeyFixtures(); // Test message to sign (same for all variants) var data = new Uint8Array([ diff --git a/test/fixtures/wpt/WebCryptoAPI/sign_verify/rsa.js b/test/fixtures/wpt/WebCryptoAPI/sign_verify/rsa.js index 667f5d2793e4..8a87ba88cb4b 100644 --- a/test/fixtures/wpt/WebCryptoAPI/sign_verify/rsa.js +++ b/test/fixtures/wpt/WebCryptoAPI/sign_verify/rsa.js @@ -1,581 +1,106 @@ - function run_test() { - setup({explicit_done: true}); - - var subtle = self.crypto.subtle; // Change to test prefixed implementations - - // When are all these tests really done? When all the promises they use have resolved. - var all_promises = []; - - // Source file [algorithm_name]_vectors.js provides the getTestVectors method - // for the algorithm that drives these tests. - var testVectors = getTestVectors(); - - // Test verification first, because signing tests rely on that working - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - var operation = subtle.verify(vector.algorithm, vector.publicKey, vector.signature, vector.plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification"); - }); - - all_promises.push(promise); - }); - - // Test verification with an altered buffer during call - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - var signature = copyBuffer(vector.signature); - signature[0] = 255 - signature[0]; - var operation = subtle.verify({ - ...vector.algorithm, - get name() { - signature[0] = vector.signature[0]; - return vector.algorithm.name; - } - }, vector.publicKey, signature, vector.plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification with altered signature during call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification with altered signature during call"); - }); - - all_promises.push(promise); - }); - - // Test verification with an altered buffer after call - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - var signature = copyBuffer(vector.signature); - var operation = subtle.verify(vector.algorithm, vector.publicKey, signature, vector.plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - signature[0] = 255 - signature[0]; - return operation; - }, vector.name + " verification with altered signature after call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification with altered signature after call"); - }); - - all_promises.push(promise); - }); - - // Test verification with a transferred buffer during call - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - var signature = copyBuffer(vector.signature); - var operation = subtle.verify({ - ...vector.algorithm, - get name() { - signature.buffer.transfer(); - return vector.algorithm.name; - } - }, vector.publicKey, signature, vector.plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature is NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification with transferred signature during call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification with transferred signature during call"); - }); - - all_promises.push(promise); - }); - - // Test verification with a transferred buffer after call - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - var signature = copyBuffer(vector.signature); - var operation = subtle.verify(vector.algorithm, vector.publicKey, signature, vector.plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - signature.buffer.transfer(); - return operation; - }, vector.name + " verification with transferred signature after call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification with transferred signature after call"); - }); - - all_promises.push(promise); - }); - - // Check for successful verification even if plaintext is altered during call. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - var plaintext = copyBuffer(vector.plaintext); - plaintext[0] = 255 - plaintext[0]; - var operation = subtle.verify({ - ...vector.algorithm, - get name() { - plaintext[0] = vector.plaintext[0]; - return vector.algorithm.name; - } - }, vector.publicKey, vector.signature, plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " with altered plaintext during call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " with altered plaintext during call"); - }); - - all_promises.push(promise); - }); - - // Check for successful verification even if plaintext is altered after call. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - var plaintext = copyBuffer(vector.plaintext); - var operation = subtle.verify(vector.algorithm, vector.publicKey, vector.signature, plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - plaintext[0] = 255 - plaintext[0]; - return operation; - }, vector.name + " with altered plaintext after call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " with altered plaintext after call"); - }); - - all_promises.push(promise); - }); - - // Check for failed verification if plaintext is transferred during call. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - var plaintext = copyBuffer(vector.plaintext); - var operation = subtle.verify({ - ...vector.algorithm, - get name() { - plaintext.buffer.transfer(); - return vector.algorithm.name; - } - }, vector.publicKey, vector.signature, plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature is NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " with transferred plaintext during call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " with transferred plaintext during call"); - }); - - all_promises.push(promise); - }); - - // Check for successful verification even if plaintext is transferred after call. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - var plaintext = copyBuffer(vector.plaintext); - var operation = subtle.verify(vector.algorithm, vector.publicKey, vector.signature, plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - plaintext.buffer.transfer(); - return operation; - }, vector.name + " with transferred plaintext after call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " with transferred plaintext after call"); - }); - - all_promises.push(promise); - }); - - // Check for failures due to using privateKey to verify. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - return subtle.verify(vector.algorithm, vector.privateKey, vector.signature, vector.plaintext) - .then(function(plaintext) { - assert_unreached("Should have thrown error for using privateKey to verify in " + vector.name + ": '" + err.message + "'"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); - }); - }, vector.name + " using privateKey to verify"); - - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " using privateKey to verify"); - }); - - all_promises.push(promise); - }); - - // Check for failures due to using publicKey to sign. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - return subtle.sign(vector.algorithm, vector.publicKey, vector.plaintext) - .then(function(signature) { - assert_unreached("Should have thrown error for using publicKey to sign in " + vector.name + ": '" + err.message + "'"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); - }); - }, vector.name + " using publicKey to sign"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " using publicKey to sign"); - }); - - all_promises.push(promise); - }); - - // Check for failures due to no "verify" usage. - testVectors.forEach(function(originalVector) { - var vector = Object.assign({}, originalVector); - - var promise = importVectorKeys(vector, [], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - return subtle.verify(vector.algorithm, vector.publicKey, vector.signature, vector.plaintext) - .then(function(plaintext) { - assert_unreached("Should have thrown error for no verify usage in " + vector.name + ": '" + err.message + "'"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); - }); - }, vector.name + " no verify usage"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " no verify usage"); - }); - - all_promises.push(promise); - }); - - // Check for successful signing and verification. - testVectors.forEach(function(vector) { - // RSA signing is deterministic with PKCS#1 v1.5, or PSS with zero-length salts. - const isDeterministic = !("saltLength" in vector.algorithm) || vector.algorithm.saltLength == 0; - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - return subtle.sign(vector.algorithm, vector.privateKey, vector.plaintext) - .then(function(signature) { - if (isDeterministic) { - // If deterministic, we can check the output matches. Otherwise, we can only check it verifies. - assert_true(equalBuffers(signature, vector.signature), "Signing did not give the expected output"); - } - // Can we verify the new signature? - return subtle.verify(vector.algorithm, vector.publicKey, signature, vector.plaintext) - .then(function(is_verified) { - assert_true(is_verified, "Round trip verifies"); - return signature; - }, function(err) { - assert_unreached("verify error for test " + vector.name + ": '" + err.message + "'"); - }); - }) - .then(function(priorSignature) { - // Will a second signing give us different signature? It should for PSS with non-empty salt - return subtle.sign(vector.algorithm, vector.privateKey, vector.plaintext) - .then(function(signature) { - if (isDeterministic) { - assert_true(equalBuffers(priorSignature, signature), "Two signings with empty salt give same signature") - } else { - assert_false(equalBuffers(priorSignature, signature), "Two signings with a salt give different signatures") - } - }, function(err) { - assert_unreached("second time verify error for test " + vector.name + ": '" + err.message + "'"); - }); - }, function(err) { - assert_unreached("sign error for test " + vector.name + ": '" + err.message + "'"); - }); - }, vector.name + " round trip"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested signing or verifying - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " round trip"); - }); - - all_promises.push(promise); - }); - - - // Test signing with the wrong algorithm - testVectors.forEach(function(vector) { - // Want to get the key for the wrong algorithm - var alteredVector = Object.assign({}, vector); - alteredVector.algorithm = Object.assign({}, vector.algorithm); - if (vector.algorithm.name === "RSA-PSS") { - alteredVector.algorithm.name = "RSASSA-PKCS1-v1_5"; - } else { - alteredVector.algorithm.name = "RSA-PSS"; - } - - var promise = importVectorKeys(alteredVector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - var operation = subtle.sign(vector.algorithm, alteredVector.privateKey, vector.plaintext) - .then(function(signature) { - assert_unreached("Signing should not have succeeded for " + vector.name); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); - }); - - return operation; - }, vector.name + " signing with wrong algorithm name"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " signing with wrong algorithm name"); - }); - - all_promises.push(promise); - }); - - // Test verification with the wrong algorithm - testVectors.forEach(function(vector) { - // Want to get the key for the wrong algorithm - var alteredVector = Object.assign({}, vector); - alteredVector.algorithm = Object.assign({}, vector.algorithm); - if (vector.algorithm.name === "RSA-PSS") { - alteredVector.algorithm.name = "RSASSA-PKCS1-v1_5"; - } else { - alteredVector.algorithm.name = "RSA-PSS"; - } - - var promise = importVectorKeys(alteredVector, ["verify"], ["sign"]) - .then(function(vectors) { - // Some tests are sign only - if (!("signature" in vector)) { - return; + const subtle = self.crypto.subtle; + const testVectors = getTestVectors().map( + vector => ({...vector, data: vector.plaintext}) + ); + const importAlgorithm = vector => ({ + name: vector.algorithm.name, + hash: vector.hash, + }); + + runSignatureTests({ + vectors: testVectors, + algorithmIdentifier(vector) { + return vector.algorithm; + }, + importAlgorithm, + dataLabel: "plaintext", + shortSignature: false, + wrongVerifyLabel: " verification with wrong algorithm name", + alteredSignatureLabel: " verification failure with altered signature", + alteredDataLabel: " verification failure with altered plaintext", + async wrongKey(vector, operation) { + const name = vector.algorithm.name === "RSA-PSS" + ? "RSASSA-PKCS1-v1_5" + : "RSA-PSS"; + const isSign = operation === "sign"; + return subtle.importKey( + isSign ? vector.privateKeyFormat : vector.publicKeyFormat, + isSign ? vector.privateKeyBuffer : vector.publicKeyBuffer, + {name, hash: vector.hash}, + false, + [operation] + ); + }, + async roundTrip({ + vector, + algorithm, + verificationKey, + signingKey, + }) { + const isDeterministic = !("saltLength" in algorithm) || + algorithm.saltLength === 0; + const signature = await subtle.sign( + algorithm, + signingKey, + vector.data + ); + + if (isDeterministic) { + assert_true( + equalBuffers(signature, vector.signature), + "Signing did not give the expected output" + ); } - promise_test(function(test) { - var operation = subtle.verify(vector.algorithm, alteredVector.publicKey, vector.signature, vector.plaintext) - .then(function(is_verified) { - assert_unreached("Verification should not have succeeded for " + vector.name); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); - }); - return operation; - }, vector.name + " verification with wrong algorithm name"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification with wrong algorithm name"); - }); - - all_promises.push(promise); - }); - - // Verification should fail with wrong signature - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - var signature = copyBuffer(vector.signature); - signature[0] = 255 - signature[0]; - var operation = subtle.verify(vector.algorithm, vector.publicKey, signature, vector.plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification failure with altered signature"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification failure with altered signature"); - }); - - all_promises.push(promise); + const isVerified = await subtle.verify( + algorithm, + verificationKey, + signature, + vector.data + ); + assert_true(isVerified, "Round trip verifies"); + + const secondSignature = await subtle.sign( + algorithm, + signingKey, + vector.data + ); + if (isDeterministic) { + assert_true( + equalBuffers(signature, secondSignature), + "Two signings with empty salt give same signature" + ); + } else { + assert_false( + equalBuffers(signature, secondSignature), + "Two signings with a salt give different signatures" + ); + } + }, }); - // [RSA-PSS] Verification should fail with wrong saltLength testVectors.forEach(function(vector) { - if (vector.algorithm.name === "RSA-PSS") { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - const saltLength = vector.algorithm.saltLength === 32 ? 48 : 32; - var operation = subtle.verify({ ...vector.algorithm, saltLength }, vector.publicKey, vector.signature, vector.plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification failure with wrong saltLength"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification failure with wrong saltLength"); - }); - - all_promises.push(promise); + if (vector.algorithm.name !== "RSA-PSS") { + return; } - }); - // Verification should fail with wrong plaintext - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - var plaintext = copyBuffer(vector.plaintext); - plaintext[0] = 255 - plaintext[0]; - var operation = subtle.verify(vector.algorithm, vector.publicKey, vector.signature, plaintext) - .then(function(is_verified) { - assert_false(is_verified, "Signature NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verification failure with altered plaintext"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification failure with altered plaintext"); - }); - - all_promises.push(promise); + promise_test(async function() { + const key = await subtle.importKey( + vector.publicKeyFormat, + vector.publicKeyBuffer, + importAlgorithm(vector), + false, + ["verify"] + ); + const saltLength = vector.algorithm.saltLength === 32 ? 48 : 32; + const isVerified = await subtle.verify( + {...vector.algorithm, saltLength}, + key, + vector.signature, + vector.data + ); + assert_false(isVerified, "Signature NOT verified"); + }, vector.name + " verification failure with wrong saltLength"); }); - - - promise_test(function() { - return Promise.all(all_promises) - .then(function() {done();}) - .catch(function() {done();}) - }, "setup"); - - // A test vector has all needed fields for signing and verifying, EXCEPT that the - // key field may be null. This function replaces that null with the Correct - // CryptoKey object. - // - // Returns a Promise that yields an updated vector on success. - function importVectorKeys(vector, publicKeyUsages, privateKeyUsages) { - var publicPromise, privatePromise; - - if (vector.publicKey !== null) { - publicPromise = new Promise(function(resolve, reject) { - resolve(vector); - }); - } else { - publicPromise = subtle.importKey(vector.publicKeyFormat, vector.publicKeyBuffer, {name: vector.algorithm.name, hash: vector.hash}, false, publicKeyUsages) - .then(function(key) { - vector.publicKey = key; - return vector; - }); // Returns a copy of the sourceBuffer it is sent. - } - - if (vector.privateKey !== null) { - privatePromise = new Promise(function(resolve, reject) { - resolve(vector); - }); - } else { - privatePromise = subtle.importKey(vector.privateKeyFormat, vector.privateKeyBuffer, {name: vector.algorithm.name, hash: vector.hash}, false, privateKeyUsages) - .then(function(key) { - vector.privateKey = key; - return vector; - }); - } - - return Promise.all([publicPromise, privatePromise]); - } - - return; } diff --git a/test/fixtures/wpt/WebCryptoAPI/sign_verify/rsa_pkcs.https.any.js b/test/fixtures/wpt/WebCryptoAPI/sign_verify/rsa_pkcs.https.any.js index 3e3a8c23bf53..43b87658d21f 100644 --- a/test/fixtures/wpt/WebCryptoAPI/sign_verify/rsa_pkcs.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/sign_verify/rsa_pkcs.https.any.js @@ -1,6 +1,8 @@ // META: title=WebCryptoAPI: sign() and verify() Using RSASSA-PKCS1-v1_5 // META: script=../util/helpers.js +// META: script=../util/rsa_key_fixtures.js // META: script=rsa_pkcs_vectors.js +// META: script=signature.js // META: script=rsa.js // META: timeout=long diff --git a/test/fixtures/wpt/WebCryptoAPI/sign_verify/rsa_pkcs_vectors.js b/test/fixtures/wpt/WebCryptoAPI/sign_verify/rsa_pkcs_vectors.js index 71e5d8571bc8..f1eca448a988 100644 --- a/test/fixtures/wpt/WebCryptoAPI/sign_verify/rsa_pkcs_vectors.js +++ b/test/fixtures/wpt/WebCryptoAPI/sign_verify/rsa_pkcs_vectors.js @@ -18,8 +18,9 @@ // plaintext - the text to encrypt // signature - the expected signature function getTestVectors() { - var pkcs8 = new Uint8Array([48, 130, 4, 191, 2, 1, 0, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 4, 130, 4, 169, 48, 130, 4, 165, 2, 1, 0, 2, 130, 1, 1, 0, 211, 87, 96, 146, 230, 41, 87, 54, 69, 68, 231, 228, 35, 59, 123, 219, 41, 61, 178, 8, 81, 34, 196, 121, 50, 133, 70, 249, 240, 247, 18, 246, 87, 196, 177, 120, 104, 201, 48, 144, 140, 197, 148, 247, 237, 0, 192, 20, 66, 193, 175, 4, 194, 246, 120, 164, 139, 162, 200, 15, 209, 113, 62, 48, 181, 172, 80, 120, 122, 195, 81, 101, 137, 241, 113, 150, 127, 99, 134, 173, 163, 73, 0, 166, 187, 4, 238, 206, 164, 43, 240, 67, 206, 217, 160, 249, 77, 12, 192, 158, 145, 155, 157, 113, 102, 192, 138, 182, 206, 32, 70, 64, 174, 164, 196, 146, 13, 182, 216, 110, 185, 22, 208, 220, 192, 244, 52, 26, 16, 56, 4, 41, 231, 225, 3, 33, 68, 234, 148, 157, 232, 246, 192, 204, 191, 149, 250, 142, 146, 141, 112, 216, 163, 140, 225, 104, 219, 69, 246, 241, 52, 102, 61, 111, 101, 111, 92, 234, 188, 114, 93, 168, 192, 42, 171, 234, 170, 19, 172, 54, 167, 92, 192, 186, 225, 53, 223, 49, 20, 182, 101, 137, 199, 237, 60, 182, 21, 89, 174, 90, 56, 79, 22, 43, 250, 128, 219, 228, 97, 127, 134, 195, 241, 208, 16, 201, 79, 226, 201, 191, 1, 154, 110, 99, 179, 239, 192, 40, 212, 60, 238, 97, 28, 133, 236, 38, 60, 144, 108, 70, 55, 114, 198, 145, 27, 25, 238, 192, 150, 202, 118, 236, 94, 49, 225, 227, 2, 3, 1, 0, 1, 2, 130, 1, 1, 0, 139, 55, 92, 203, 135, 200, 37, 197, 255, 61, 83, 208, 9, 145, 110, 150, 65, 5, 126, 24, 82, 114, 39, 160, 122, 178, 38, 190, 16, 136, 129, 58, 59, 56, 187, 123, 72, 243, 119, 5, 81, 101, 250, 42, 147, 57, 210, 77, 198, 103, 213, 197, 186, 52, 39, 230, 164, 129, 23, 110, 172, 21, 255, 212, 144, 104, 49, 30, 28, 40, 59, 159, 58, 142, 12, 184, 9, 180, 99, 12, 80, 170, 143, 62, 69, 166, 11, 53, 158, 25, 191, 140, 187, 94, 202, 214, 78, 118, 31, 16, 149, 116, 63, 243, 106, 175, 92, 240, 236, 185, 127, 237, 173, 221, 166, 11, 91, 243, 93, 129, 26, 117, 184, 34, 35, 12, 250, 160, 25, 47, 173, 64, 84, 126, 39, 84, 72, 170, 51, 22, 191, 142, 43, 76, 224, 133, 79, 199, 112, 139, 83, 123, 162, 45, 19, 33, 11, 9, 174, 195, 122, 39, 89, 239, 192, 130, 161, 83, 27, 35, 169, 23, 48, 3, 125, 222, 78, 242, 107, 95, 150, 239, 220, 195, 159, 211, 76, 52, 90, 213, 28, 187, 228, 79, 229, 139, 138, 59, 78, 201, 151, 134, 108, 8, 109, 255, 27, 136, 49, 239, 10, 31, 234, 38, 60, 247, 218, 205, 3, 192, 76, 188, 194, 178, 121, 229, 127, 165, 185, 83, 153, 107, 251, 29, 214, 136, 23, 175, 127, 180, 44, 222, 247, 165, 41, 74, 87, 250, 194, 184, 173, 115, 159, 27, 2, 153, 2, 129, 129, 0, 251, 248, 51, 194, 198, 49, 201, 112, 36, 12, 142, 116, 133, 240, 106, 62, 162, 168, 72, 34, 81, 26, 134, 39, 221, 70, 78, 248, 175, 175, 113, 72, 209, 164, 37, 182, 184, 101, 125, 221, 82, 70, 131, 43, 142, 83, 48, 32, 197, 187, 181, 104, 133, 90, 106, 236, 62, 66, 33, 215, 147, 241, 220, 91, 47, 37, 132, 226, 65, 94, 72, 233, 162, 189, 41, 43, 19, 64, 49, 249, 156, 142, 180, 47, 192, 188, 208, 68, 155, 242, 44, 230, 222, 201, 112, 20, 239, 229, 172, 147, 235, 232, 53, 135, 118, 86, 37, 44, 187, 177, 108, 65, 91, 103, 177, 132, 210, 40, 69, 104, 162, 119, 213, 147, 53, 88, 92, 253, 2, 129, 129, 0, 214, 184, 206, 39, 199, 41, 93, 93, 22, 252, 53, 112, 237, 100, 200, 218, 147, 3, 250, 210, 148, 136, 193, 166, 94, 154, 215, 17, 249, 3, 112, 24, 125, 187, 253, 129, 49, 109, 105, 100, 139, 200, 140, 197, 200, 53, 81, 175, 255, 69, 222, 186, 207, 182, 17, 5, 247, 9, 228, 195, 8, 9, 185, 0, 49, 235, 214, 134, 36, 68, 150, 198, 246, 158, 105, 46, 189, 200, 20, 246, 66, 57, 244, 173, 21, 117, 110, 203, 120, 197, 165, 176, 153, 49, 219, 24, 48, 119, 197, 70, 163, 140, 76, 116, 56, 137, 173, 61, 62, 208, 121, 181, 98, 46, 208, 18, 15, 160, 225, 249, 59, 89, 61, 183, 216, 82, 224, 95, 2, 129, 128, 56, 135, 75, 157, 131, 247, 129, 120, 206, 45, 158, 252, 23, 92, 131, 137, 127, 214, 127, 48, 107, 191, 166, 159, 100, 238, 52, 35, 104, 206, 212, 124, 128, 195, 241, 206, 23, 122, 117, 141, 100, 186, 251, 12, 151, 134, 164, 66, 133, 250, 1, 205, 236, 53, 7, 205, 238, 125, 201, 183, 226, 178, 29, 60, 187, 204, 16, 14, 238, 153, 103, 132, 59, 5, 115, 41, 253, 204, 166, 41, 152, 237, 15, 17, 179, 140, 232, 176, 171, 199, 222, 57, 1, 124, 113, 207, 208, 174, 87, 84, 108, 85, 145, 68, 205, 208, 175, 208, 100, 95, 126, 168, 255, 7, 185, 116, 209, 237, 68, 253, 31, 142, 0, 245, 96, 191, 109, 69, 2, 129, 129, 0, 133, 41, 239, 144, 115, 207, 143, 123, 95, 249, 226, 26, 186, 223, 58, 65, 115, 211, 144, 6, 112, 223, 175, 89, 66, 106, 188, 223, 4, 147, 193, 61, 47, 29, 27, 70, 184, 36, 166, 172, 24, 148, 179, 217, 37, 37, 12, 24, 30, 52, 114, 193, 96, 120, 5, 110, 177, 154, 141, 40, 247, 31, 48, 128, 146, 117, 52, 129, 212, 148, 68, 253, 247, 140, 158, 166, 194, 68, 7, 220, 1, 142, 119, 211, 175, 239, 56, 91, 47, 247, 67, 158, 150, 35, 121, 65, 51, 45, 212, 70, 206, 190, 255, 219, 68, 4, 254, 79, 113, 89, 81, 97, 208, 22, 64, 44, 51, 77, 15, 87, 198, 26, 190, 79, 249, 244, 203, 249, 2, 129, 129, 0, 135, 216, 119, 8, 212, 103, 99, 228, 204, 190, 178, 209, 233, 113, 46, 91, 240, 33, 109, 112, 222, 148, 32, 165, 178, 6, 155, 116, 89, 185, 159, 93, 159, 127, 47, 173, 124, 215, 154, 174, 230, 122, 127, 154, 52, 67, 126, 60, 121, 168, 74, 240, 205, 141, 233, 223, 242, 104, 235, 12, 71, 147, 245, 1, 249, 136, 213, 64, 246, 211, 71, 92, 32, 121, 184, 34, 122, 35, 217, 104, 222, 196, 227, 198, 101, 3, 24, 113, 147, 69, 150, 48, 71, 43, 253, 182, 186, 29, 231, 134, 199, 151, 250, 111, 78, 166, 90, 42, 132, 25, 38, 47, 41, 103, 136, 86, 203, 115, 201, 189, 75, 200, 155, 94, 4, 27, 34, 119]); - var spki = new Uint8Array([48, 130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 130, 1, 15, 0, 48, 130, 1, 10, 2, 130, 1, 1, 0, 211, 87, 96, 146, 230, 41, 87, 54, 69, 68, 231, 228, 35, 59, 123, 219, 41, 61, 178, 8, 81, 34, 196, 121, 50, 133, 70, 249, 240, 247, 18, 246, 87, 196, 177, 120, 104, 201, 48, 144, 140, 197, 148, 247, 237, 0, 192, 20, 66, 193, 175, 4, 194, 246, 120, 164, 139, 162, 200, 15, 209, 113, 62, 48, 181, 172, 80, 120, 122, 195, 81, 101, 137, 241, 113, 150, 127, 99, 134, 173, 163, 73, 0, 166, 187, 4, 238, 206, 164, 43, 240, 67, 206, 217, 160, 249, 77, 12, 192, 158, 145, 155, 157, 113, 102, 192, 138, 182, 206, 32, 70, 64, 174, 164, 196, 146, 13, 182, 216, 110, 185, 22, 208, 220, 192, 244, 52, 26, 16, 56, 4, 41, 231, 225, 3, 33, 68, 234, 148, 157, 232, 246, 192, 204, 191, 149, 250, 142, 146, 141, 112, 216, 163, 140, 225, 104, 219, 69, 246, 241, 52, 102, 61, 111, 101, 111, 92, 234, 188, 114, 93, 168, 192, 42, 171, 234, 170, 19, 172, 54, 167, 92, 192, 186, 225, 53, 223, 49, 20, 182, 101, 137, 199, 237, 60, 182, 21, 89, 174, 90, 56, 79, 22, 43, 250, 128, 219, 228, 97, 127, 134, 195, 241, 208, 16, 201, 79, 226, 201, 191, 1, 154, 110, 99, 179, 239, 192, 40, 212, 60, 238, 97, 28, 133, 236, 38, 60, 144, 108, 70, 55, 114, 198, 145, 27, 25, 238, 192, 150, 202, 118, 236, 94, 49, 225, 227, 2, 3, 1, 0, 1]); + var keyFixtures = getRsaKeyFixtures(); + var pkcs8 = keyFixtures.pkcs8; + var spki = keyFixtures.spki; // plaintext var plaintext = new Uint8Array([95, 77, 186, 79, 50, 12, 12, 232, 118, 114, 90, 252, 229, 251, 210, 91, 248, 62, 90, 113, 37, 160, 140, 175, 231, 60, 62, 186, 196, 33, 119, 157, 249, 213, 93, 24, 12, 58, 233, 148, 38, 69, 225, 216, 47, 238, 140, 157, 41, 75, 60, 177, 160, 138, 153, 49, 32, 27, 60, 14, 129, 252, 71, 202, 207, 131, 21, 162, 175, 102, 50, 65, 19, 195, 182, 98, 48, 195, 70, 8, 196, 244, 89, 54, 52, 206, 2, 178, 103, 54, 34, 119, 240, 168, 64, 202, 116, 188, 61, 26, 98, 54, 149, 44, 94, 215, 170, 248, 168, 254, 203, 221, 250, 117, 132, 230, 151, 140, 234, 93, 42, 91, 159, 183, 241, 180, 140, 139, 11, 229, 138, 48, 82, 2, 117, 77, 131, 118, 16, 115, 116, 121, 60, 240, 38, 170, 238, 83, 0, 114, 125, 131, 108, 215, 30, 113, 179, 69, 221, 178, 228, 68, 70, 255, 197, 185, 1, 99, 84, 19, 137, 13, 145, 14, 163, 128, 152, 74, 144, 25, 16, 49, 50, 63, 22, 219, 204, 157, 107, 225, 104, 184, 72, 133, 56, 76, 160, 62, 18, 96, 10, 193, 194, 72, 2, 138, 243, 114, 108, 201, 52, 99, 136, 46, 168, 192, 42, 171]); diff --git a/test/fixtures/wpt/WebCryptoAPI/sign_verify/rsa_pss.https.any.js b/test/fixtures/wpt/WebCryptoAPI/sign_verify/rsa_pss.https.any.js index 399baba78468..c3ed8355f3f8 100644 --- a/test/fixtures/wpt/WebCryptoAPI/sign_verify/rsa_pss.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/sign_verify/rsa_pss.https.any.js @@ -1,6 +1,8 @@ // META: title=WebCryptoAPI: sign() and verify() Using RSA-PSS // META: script=../util/helpers.js +// META: script=../util/rsa_key_fixtures.js // META: script=rsa_pss_vectors.js +// META: script=signature.js // META: script=rsa.js // META: timeout=long diff --git a/test/fixtures/wpt/WebCryptoAPI/sign_verify/rsa_pss_vectors.js b/test/fixtures/wpt/WebCryptoAPI/sign_verify/rsa_pss_vectors.js index c3ce77960629..224bacc3d1bb 100644 --- a/test/fixtures/wpt/WebCryptoAPI/sign_verify/rsa_pss_vectors.js +++ b/test/fixtures/wpt/WebCryptoAPI/sign_verify/rsa_pss_vectors.js @@ -18,8 +18,9 @@ // plaintext - the text to encrypt // signature - the expected signature function getTestVectors() { - var pkcs8 = new Uint8Array([48, 130, 4, 191, 2, 1, 0, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 4, 130, 4, 169, 48, 130, 4, 165, 2, 1, 0, 2, 130, 1, 1, 0, 211, 87, 96, 146, 230, 41, 87, 54, 69, 68, 231, 228, 35, 59, 123, 219, 41, 61, 178, 8, 81, 34, 196, 121, 50, 133, 70, 249, 240, 247, 18, 246, 87, 196, 177, 120, 104, 201, 48, 144, 140, 197, 148, 247, 237, 0, 192, 20, 66, 193, 175, 4, 194, 246, 120, 164, 139, 162, 200, 15, 209, 113, 62, 48, 181, 172, 80, 120, 122, 195, 81, 101, 137, 241, 113, 150, 127, 99, 134, 173, 163, 73, 0, 166, 187, 4, 238, 206, 164, 43, 240, 67, 206, 217, 160, 249, 77, 12, 192, 158, 145, 155, 157, 113, 102, 192, 138, 182, 206, 32, 70, 64, 174, 164, 196, 146, 13, 182, 216, 110, 185, 22, 208, 220, 192, 244, 52, 26, 16, 56, 4, 41, 231, 225, 3, 33, 68, 234, 148, 157, 232, 246, 192, 204, 191, 149, 250, 142, 146, 141, 112, 216, 163, 140, 225, 104, 219, 69, 246, 241, 52, 102, 61, 111, 101, 111, 92, 234, 188, 114, 93, 168, 192, 42, 171, 234, 170, 19, 172, 54, 167, 92, 192, 186, 225, 53, 223, 49, 20, 182, 101, 137, 199, 237, 60, 182, 21, 89, 174, 90, 56, 79, 22, 43, 250, 128, 219, 228, 97, 127, 134, 195, 241, 208, 16, 201, 79, 226, 201, 191, 1, 154, 110, 99, 179, 239, 192, 40, 212, 60, 238, 97, 28, 133, 236, 38, 60, 144, 108, 70, 55, 114, 198, 145, 27, 25, 238, 192, 150, 202, 118, 236, 94, 49, 225, 227, 2, 3, 1, 0, 1, 2, 130, 1, 1, 0, 139, 55, 92, 203, 135, 200, 37, 197, 255, 61, 83, 208, 9, 145, 110, 150, 65, 5, 126, 24, 82, 114, 39, 160, 122, 178, 38, 190, 16, 136, 129, 58, 59, 56, 187, 123, 72, 243, 119, 5, 81, 101, 250, 42, 147, 57, 210, 77, 198, 103, 213, 197, 186, 52, 39, 230, 164, 129, 23, 110, 172, 21, 255, 212, 144, 104, 49, 30, 28, 40, 59, 159, 58, 142, 12, 184, 9, 180, 99, 12, 80, 170, 143, 62, 69, 166, 11, 53, 158, 25, 191, 140, 187, 94, 202, 214, 78, 118, 31, 16, 149, 116, 63, 243, 106, 175, 92, 240, 236, 185, 127, 237, 173, 221, 166, 11, 91, 243, 93, 129, 26, 117, 184, 34, 35, 12, 250, 160, 25, 47, 173, 64, 84, 126, 39, 84, 72, 170, 51, 22, 191, 142, 43, 76, 224, 133, 79, 199, 112, 139, 83, 123, 162, 45, 19, 33, 11, 9, 174, 195, 122, 39, 89, 239, 192, 130, 161, 83, 27, 35, 169, 23, 48, 3, 125, 222, 78, 242, 107, 95, 150, 239, 220, 195, 159, 211, 76, 52, 90, 213, 28, 187, 228, 79, 229, 139, 138, 59, 78, 201, 151, 134, 108, 8, 109, 255, 27, 136, 49, 239, 10, 31, 234, 38, 60, 247, 218, 205, 3, 192, 76, 188, 194, 178, 121, 229, 127, 165, 185, 83, 153, 107, 251, 29, 214, 136, 23, 175, 127, 180, 44, 222, 247, 165, 41, 74, 87, 250, 194, 184, 173, 115, 159, 27, 2, 153, 2, 129, 129, 0, 251, 248, 51, 194, 198, 49, 201, 112, 36, 12, 142, 116, 133, 240, 106, 62, 162, 168, 72, 34, 81, 26, 134, 39, 221, 70, 78, 248, 175, 175, 113, 72, 209, 164, 37, 182, 184, 101, 125, 221, 82, 70, 131, 43, 142, 83, 48, 32, 197, 187, 181, 104, 133, 90, 106, 236, 62, 66, 33, 215, 147, 241, 220, 91, 47, 37, 132, 226, 65, 94, 72, 233, 162, 189, 41, 43, 19, 64, 49, 249, 156, 142, 180, 47, 192, 188, 208, 68, 155, 242, 44, 230, 222, 201, 112, 20, 239, 229, 172, 147, 235, 232, 53, 135, 118, 86, 37, 44, 187, 177, 108, 65, 91, 103, 177, 132, 210, 40, 69, 104, 162, 119, 213, 147, 53, 88, 92, 253, 2, 129, 129, 0, 214, 184, 206, 39, 199, 41, 93, 93, 22, 252, 53, 112, 237, 100, 200, 218, 147, 3, 250, 210, 148, 136, 193, 166, 94, 154, 215, 17, 249, 3, 112, 24, 125, 187, 253, 129, 49, 109, 105, 100, 139, 200, 140, 197, 200, 53, 81, 175, 255, 69, 222, 186, 207, 182, 17, 5, 247, 9, 228, 195, 8, 9, 185, 0, 49, 235, 214, 134, 36, 68, 150, 198, 246, 158, 105, 46, 189, 200, 20, 246, 66, 57, 244, 173, 21, 117, 110, 203, 120, 197, 165, 176, 153, 49, 219, 24, 48, 119, 197, 70, 163, 140, 76, 116, 56, 137, 173, 61, 62, 208, 121, 181, 98, 46, 208, 18, 15, 160, 225, 249, 59, 89, 61, 183, 216, 82, 224, 95, 2, 129, 128, 56, 135, 75, 157, 131, 247, 129, 120, 206, 45, 158, 252, 23, 92, 131, 137, 127, 214, 127, 48, 107, 191, 166, 159, 100, 238, 52, 35, 104, 206, 212, 124, 128, 195, 241, 206, 23, 122, 117, 141, 100, 186, 251, 12, 151, 134, 164, 66, 133, 250, 1, 205, 236, 53, 7, 205, 238, 125, 201, 183, 226, 178, 29, 60, 187, 204, 16, 14, 238, 153, 103, 132, 59, 5, 115, 41, 253, 204, 166, 41, 152, 237, 15, 17, 179, 140, 232, 176, 171, 199, 222, 57, 1, 124, 113, 207, 208, 174, 87, 84, 108, 85, 145, 68, 205, 208, 175, 208, 100, 95, 126, 168, 255, 7, 185, 116, 209, 237, 68, 253, 31, 142, 0, 245, 96, 191, 109, 69, 2, 129, 129, 0, 133, 41, 239, 144, 115, 207, 143, 123, 95, 249, 226, 26, 186, 223, 58, 65, 115, 211, 144, 6, 112, 223, 175, 89, 66, 106, 188, 223, 4, 147, 193, 61, 47, 29, 27, 70, 184, 36, 166, 172, 24, 148, 179, 217, 37, 37, 12, 24, 30, 52, 114, 193, 96, 120, 5, 110, 177, 154, 141, 40, 247, 31, 48, 128, 146, 117, 52, 129, 212, 148, 68, 253, 247, 140, 158, 166, 194, 68, 7, 220, 1, 142, 119, 211, 175, 239, 56, 91, 47, 247, 67, 158, 150, 35, 121, 65, 51, 45, 212, 70, 206, 190, 255, 219, 68, 4, 254, 79, 113, 89, 81, 97, 208, 22, 64, 44, 51, 77, 15, 87, 198, 26, 190, 79, 249, 244, 203, 249, 2, 129, 129, 0, 135, 216, 119, 8, 212, 103, 99, 228, 204, 190, 178, 209, 233, 113, 46, 91, 240, 33, 109, 112, 222, 148, 32, 165, 178, 6, 155, 116, 89, 185, 159, 93, 159, 127, 47, 173, 124, 215, 154, 174, 230, 122, 127, 154, 52, 67, 126, 60, 121, 168, 74, 240, 205, 141, 233, 223, 242, 104, 235, 12, 71, 147, 245, 1, 249, 136, 213, 64, 246, 211, 71, 92, 32, 121, 184, 34, 122, 35, 217, 104, 222, 196, 227, 198, 101, 3, 24, 113, 147, 69, 150, 48, 71, 43, 253, 182, 186, 29, 231, 134, 199, 151, 250, 111, 78, 166, 90, 42, 132, 25, 38, 47, 41, 103, 136, 86, 203, 115, 201, 189, 75, 200, 155, 94, 4, 27, 34, 119]); - var spki = new Uint8Array([48, 130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 130, 1, 15, 0, 48, 130, 1, 10, 2, 130, 1, 1, 0, 211, 87, 96, 146, 230, 41, 87, 54, 69, 68, 231, 228, 35, 59, 123, 219, 41, 61, 178, 8, 81, 34, 196, 121, 50, 133, 70, 249, 240, 247, 18, 246, 87, 196, 177, 120, 104, 201, 48, 144, 140, 197, 148, 247, 237, 0, 192, 20, 66, 193, 175, 4, 194, 246, 120, 164, 139, 162, 200, 15, 209, 113, 62, 48, 181, 172, 80, 120, 122, 195, 81, 101, 137, 241, 113, 150, 127, 99, 134, 173, 163, 73, 0, 166, 187, 4, 238, 206, 164, 43, 240, 67, 206, 217, 160, 249, 77, 12, 192, 158, 145, 155, 157, 113, 102, 192, 138, 182, 206, 32, 70, 64, 174, 164, 196, 146, 13, 182, 216, 110, 185, 22, 208, 220, 192, 244, 52, 26, 16, 56, 4, 41, 231, 225, 3, 33, 68, 234, 148, 157, 232, 246, 192, 204, 191, 149, 250, 142, 146, 141, 112, 216, 163, 140, 225, 104, 219, 69, 246, 241, 52, 102, 61, 111, 101, 111, 92, 234, 188, 114, 93, 168, 192, 42, 171, 234, 170, 19, 172, 54, 167, 92, 192, 186, 225, 53, 223, 49, 20, 182, 101, 137, 199, 237, 60, 182, 21, 89, 174, 90, 56, 79, 22, 43, 250, 128, 219, 228, 97, 127, 134, 195, 241, 208, 16, 201, 79, 226, 201, 191, 1, 154, 110, 99, 179, 239, 192, 40, 212, 60, 238, 97, 28, 133, 236, 38, 60, 144, 108, 70, 55, 114, 198, 145, 27, 25, 238, 192, 150, 202, 118, 236, 94, 49, 225, 227, 2, 3, 1, 0, 1]); + var keyFixtures = getRsaKeyFixtures(); + var pkcs8 = keyFixtures.pkcs8; + var spki = keyFixtures.spki; // plaintext for RSA-PSS var plaintext = new Uint8Array([95, 77, 186, 79, 50, 12, 12, 232, 118, 114, 90, 252, 229, 251, 210, 91, 248, 62, 90, 113, 37, 160, 140, 175, 231, 60, 62, 186, 196, 33, 119, 157, 249, 213, 93, 24, 12, 58, 233, 148, 38, 69, 225, 216, 47, 238, 140, 157, 41, 75, 60, 177, 160, 138, 153, 49, 32, 27, 60, 14, 129, 252, 71, 202, 207, 131, 21, 162, 175, 102, 50, 65, 19, 195, 182, 98, 48, 195, 70, 8, 196, 244, 89, 54, 52, 206, 2, 178, 103, 54, 34, 119, 240, 168, 64, 202, 116, 188, 61, 26, 98, 54, 149, 44, 94, 215, 170, 248, 168, 254, 203, 221, 250, 117, 132, 230, 151, 140, 234, 93, 42, 91, 159, 183, 241, 180, 140, 139, 11, 229, 138, 48, 82, 2, 117, 77, 131, 118, 16, 115, 116, 121, 60, 240, 38, 170, 238, 83, 0, 114, 125, 131, 108, 215, 30, 113, 179, 69, 221, 178, 228, 68, 70, 255, 197, 185, 1, 99, 84, 19, 137, 13, 145, 14, 163, 128, 152, 74, 144, 25, 16, 49, 50, 63, 22, 219, 204, 157, 107, 225, 104, 184, 72, 133, 56, 76, 160, 62, 18, 96, 10, 193, 194, 72, 2, 138, 243, 114, 108, 201, 52, 99, 136, 46, 168, 192, 42, 171]); diff --git a/test/fixtures/wpt/WebCryptoAPI/sign_verify/signature.js b/test/fixtures/wpt/WebCryptoAPI/sign_verify/signature.js new file mode 100644 index 000000000000..2d734e1d973e --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/sign_verify/signature.js @@ -0,0 +1,368 @@ +function runSignatureTests(options) { + const subtle = self.crypto.subtle; + const publicKeyCache = new WeakMap(); + const privateKeyCache = new WeakMap(); + const dataLabel = options.dataLabel || 'data'; + + function algorithmIdentifier(vector) { + return options.algorithmIdentifier(vector); + } + + function algorithmName(vector) { + const algorithm = algorithmIdentifier(vector); + return typeof algorithm === 'string' ? algorithm : algorithm.name; + } + + function algorithmWithNameGetter(vector, getter) { + const algorithm = algorithmIdentifier(vector); + const result = typeof algorithm === 'string' ? {} : { ...algorithm }; + Object.defineProperty(result, 'name', { + enumerable: true, + get: getter, + }); + return result; + } + + function importAlgorithm(vector) { + return options.importAlgorithm + ? options.importAlgorithm(vector) + : {name: algorithmName(vector)}; + } + + function cachedKey(cache, vector, usages, importer) { + let keys = cache.get(vector); + if (keys === undefined) { + keys = new Map(); + cache.set(vector, keys); + } + + const cacheKey = usages.join(','); + if (!keys.has(cacheKey)) { + keys.set(cacheKey, importer()); + } + return keys.get(cacheKey); + } + + function publicKey(vector, usages = ['verify']) { + return cachedKey(publicKeyCache, vector, usages, function () { + return subtle.importKey( + vector.publicKeyFormat || 'spki', + vector.publicKeyBuffer, + importAlgorithm(vector), + false, + usages + ); + }); + } + + function privateKey(vector, usages = ['sign']) { + return cachedKey(privateKeyCache, vector, usages, function () { + return subtle.importKey( + vector.privateKeyFormat || 'pkcs8', + vector.privateKeyBuffer, + importAlgorithm(vector), + false, + usages + ); + }); + } + + async function assertInvalidAccess(operation, message) { + let error; + try { + await operation(); + } catch (caught) { + error = caught; + } + assert_not_equals(error, undefined, message); + assert_equals( + error.name, + 'InvalidAccessError', + "Should have thrown InvalidAccessError instead of '" + error.message + "'" + ); + } + + options.vectors.forEach(function (vector) { + const algorithm = algorithmIdentifier(vector); + + promise_test(async function () { + const key = await publicKey(vector); + const isVerified = await subtle.verify( + algorithm, + key, + vector.signature, + vector.data + ); + assert_true(isVerified, 'Signature verified'); + }, vector.name + ' verification'); + + promise_test(async function () { + const key = await publicKey(vector); + const signature = copyBuffer(vector.signature); + signature[0] = 255 - signature[0]; + const duringCallAlgorithm = algorithmWithNameGetter(vector, function () { + signature[0] = vector.signature[0]; + return algorithmName(vector); + }); + const isVerified = await subtle.verify( + duringCallAlgorithm, + key, + signature, + vector.data + ); + assert_true(isVerified, 'Signature verified'); + }, vector.name + ' verification with altered signature during call'); + + promise_test(async function () { + const key = await publicKey(vector); + const signature = copyBuffer(vector.signature); + const operation = subtle.verify(algorithm, key, signature, vector.data); + signature[0] = 255 - signature[0]; + assert_true(await operation, 'Signature verified'); + }, vector.name + ' verification with altered signature after call'); + + promise_test(async function () { + const key = await publicKey(vector); + const signature = copyBuffer(vector.signature); + const duringCallAlgorithm = algorithmWithNameGetter(vector, function () { + signature.buffer.transfer(); + return algorithmName(vector); + }); + const isVerified = await subtle.verify( + duringCallAlgorithm, + key, + signature, + vector.data + ); + assert_false(isVerified, 'Signature is NOT verified'); + }, vector.name + ' verification with transferred signature during call'); + + promise_test(async function () { + const key = await publicKey(vector); + const signature = copyBuffer(vector.signature); + const operation = subtle.verify(algorithm, key, signature, vector.data); + signature.buffer.transfer(); + assert_true(await operation, 'Signature verified'); + }, vector.name + ' verification with transferred signature after call'); + + promise_test(async function () { + const key = await publicKey(vector); + const data = copyBuffer(vector.data); + data[0] = 255 - data[0]; + const duringCallAlgorithm = algorithmWithNameGetter(vector, function () { + data[0] = vector.data[0]; + return algorithmName(vector); + }); + const isVerified = await subtle.verify( + duringCallAlgorithm, + key, + vector.signature, + data + ); + assert_true(isVerified, 'Signature verified'); + }, vector.name + ' with altered ' + dataLabel + ' during call'); + + promise_test(async function () { + const key = await publicKey(vector); + const data = copyBuffer(vector.data); + const operation = subtle.verify(algorithm, key, vector.signature, data); + data[0] = 255 - data[0]; + assert_true(await operation, 'Signature verified'); + }, vector.name + ' with altered ' + dataLabel + ' after call'); + + promise_test(async function () { + const key = await publicKey(vector); + const data = copyBuffer(vector.data); + const duringCallAlgorithm = algorithmWithNameGetter(vector, function () { + data.buffer.transfer(); + return algorithmName(vector); + }); + const isVerified = await subtle.verify( + duringCallAlgorithm, + key, + vector.signature, + data + ); + assert_false(isVerified, 'Signature is NOT verified'); + }, vector.name + ' with transferred ' + dataLabel + ' during call'); + + promise_test(async function () { + const key = await publicKey(vector); + const data = copyBuffer(vector.data); + const operation = subtle.verify(algorithm, key, vector.signature, data); + data.buffer.transfer(); + assert_true(await operation, 'Signature verified'); + }, vector.name + ' with transferred ' + dataLabel + ' after call'); + + promise_test(async function () { + const key = await privateKey(vector); + await assertInvalidAccess( + () => subtle.verify(algorithm, key, vector.signature, vector.data), + 'Using a private key to verify should fail' + ); + }, vector.name + ' using privateKey to verify'); + + promise_test(async function () { + const key = await publicKey(vector); + await assertInvalidAccess( + () => subtle.sign(algorithm, key, vector.data), + 'Using a public key to sign should fail' + ); + }, vector.name + ' using publicKey to sign'); + + promise_test(async function () { + const key = await publicKey(vector, []); + await assertInvalidAccess( + () => subtle.verify(algorithm, key, vector.signature, vector.data), + 'Verifying without the verify usage should fail' + ); + }, vector.name + ' no verify usage'); + + promise_test(async function () { + const verificationKey = await publicKey(vector); + const signingKey = await privateKey(vector); + + if (options.roundTrip) { + await options.roundTrip({ + subtle, + vector, + algorithm, + verificationKey, + signingKey, + }); + return; + } + + if (options.katFirst) { + const vectorSignatureIsVerified = await subtle.verify( + algorithm, + verificationKey, + vector.signature, + vector.data + ); + assert_true( + vectorSignatureIsVerified, + 'Known-answer signature verified' + ); + } + + const signature = await subtle.sign(algorithm, signingKey, vector.data); + + if (!options.katFirst || !equalBuffers(signature, vector.signature)) { + const generatedSignatureIsVerified = await subtle.verify( + algorithm, + verificationKey, + signature, + vector.data + ); + assert_true( + generatedSignatureIsVerified, + 'Generated signature verified' + ); + } + }, vector.name + ' round trip'); + + promise_test(async function () { + const wrongKey = options.wrongKey + ? await options.wrongKey(vector, 'sign') + : await subtle.generateKey( + {name: 'HMAC', hash: 'SHA-1'}, + false, + ['sign', 'verify'] + ); + await assertInvalidAccess( + () => subtle.sign(algorithm, wrongKey, vector.data), + 'Signing with a key for another algorithm should fail' + ); + }, vector.name + ' signing with wrong algorithm name'); + + promise_test(async function () { + const wrongKey = options.wrongKey + ? await options.wrongKey(vector, 'verify') + : await subtle.generateKey( + {name: 'HMAC', hash: 'SHA-1'}, + false, + ['sign', 'verify'] + ); + await assertInvalidAccess( + () => subtle.verify(algorithm, wrongKey, vector.signature, vector.data), + 'Verifying with a key for another algorithm should fail' + ); + }, vector.name + + (options.wrongVerifyLabel || ' verifying with wrong algorithm name')); + + promise_test(async function () { + const key = await publicKey(vector); + const signature = copyBuffer(vector.signature); + signature[0] = 255 - signature[0]; + const isVerified = await subtle.verify( + algorithm, + key, + signature, + vector.data + ); + assert_false(isVerified, 'Signature NOT verified'); + }, vector.name + + (options.alteredSignatureLabel || + ' verification failure due to altered signature')); + + if (options.shortSignature !== false) { + promise_test(async function () { + const key = await publicKey(vector); + const signature = vector.signature.slice(1); + const isVerified = await subtle.verify( + algorithm, + key, + signature, + vector.data + ); + assert_false(isVerified, 'Signature NOT verified'); + }, vector.name + ' verification failure due to shortened signature'); + } + + promise_test(async function () { + const key = await publicKey(vector); + const data = copyBuffer(vector.data); + data[0] = 255 - data[0]; + const isVerified = await subtle.verify( + algorithm, + key, + vector.signature, + data + ); + assert_false(isVerified, 'Signature NOT verified'); + }, vector.name + + (options.alteredDataLabel || + ' verification failure due to altered ' + dataLabel)); + + if (options.generatedKeys) { + promise_test(async function () { + const key = await subtle.generateKey(algorithm, false, ['sign', 'verify']); + const signature = await subtle.sign( + algorithm, + key.privateKey, + vector.data + ); + const isVerified = await subtle.verify( + algorithm, + key.publicKey, + signature, + vector.data + ); + assert_true(isVerified, 'Verification failed.'); + }, 'Sign and verify using generated ' + algorithmName(vector) + ' keys.'); + } + }); + + (options.invalidVectors || []).forEach(function (vector) { + promise_test(async function () { + const isVerified = await subtle.verify( + algorithmIdentifier(vector), + await publicKey(vector), + vector.signature, + vector.data + ); + assert_false(isVerified, 'Signature unexpectedly verified'); + }, vector.name + ' verification'); + }); +} diff --git a/test/fixtures/wpt/WebCryptoAPI/supports-modern.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/supports-modern.tentative.https.any.js index ca23b7823177..97cf9dff48ae 100644 --- a/test/fixtures/wpt/WebCryptoAPI/supports-modern.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/supports-modern.tentative.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCrypto API: supports method tests for algorithms in https://wicg.github.io/webcrypto-modern-algos/ // META: script=util/helpers.js +// META: script=util/supports.js 'use strict'; @@ -58,73 +59,11 @@ const operations = [ ]; // Test that supports method exists and is a static method -test(() => { - assert_true( - typeof SubtleCrypto.supports === 'function', - 'SubtleCrypto.supports should be a function'); -}, 'SubtleCrypto.supports method exists'); +testSupportsMethod(); // Test standard WebCrypto algorithms for requested operations -for (const [algorithmName, algorithmInfo] of Object.entries(modernAlgorithms)) { - for (const operation of operations) { - promise_test(async (t) => { - const isSupported = algorithmInfo.operations.includes(operation); - - // Use appropriate algorithm parameters for each operation - let algorithm; - let lengthOrAdditionalAlgorithm; - switch (operation) { - case 'generateKey': - algorithm = algorithmInfo.keyGenParams || algorithmName; - break; - case 'importKey': - algorithm = algorithmInfo.importParams || algorithmName; - break; - case 'sign': - case 'verify': - algorithm = algorithmInfo.signParams || algorithmName; - break; - case 'encrypt': - case 'decrypt': - algorithm = algorithmInfo.encryptParams || algorithmName; - break; - case 'deriveBits': - algorithm = algorithmInfo.deriveBitsParams || algorithmName; - if (algorithm?.public instanceof Promise) { - algorithm.public = (await algorithm.public).publicKey; - } - if (algorithmName === 'PBKDF2' || algorithmName === 'HKDF') { - lengthOrAdditionalAlgorithm = 256; - } - break; - case 'digest': - algorithm = algorithmName; - break; - case 'encapsulateKey': - case 'encapsulateBits': - case 'decapsulateKey': - case 'decapsulateBits': - algorithm = algorithmName; - if (operation === 'encapsulateKey' || operation === 'decapsulateKey') { - lengthOrAdditionalAlgorithm = { name: 'AES-GCM', length: 256 }; - } - break; - default: - algorithm = algorithmName; - } - - const result = SubtleCrypto.supports(operation, algorithm, lengthOrAdditionalAlgorithm); - - if (isSupported) { - assert_true(result, `${algorithmName} should support ${operation}`); - } else { - assert_false( - result, `${algorithmName} should not support ${operation}`); - } - }, `supports(${operation}, ${algorithmName})`); - } -} +runSupportsTests(modernAlgorithms, operations); // Test some algorithm objects with valid parameters test(() => { diff --git a/test/fixtures/wpt/WebCryptoAPI/supports.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/supports.tentative.https.any.js index ac3a32c74100..fcccbecd6916 100644 --- a/test/fixtures/wpt/WebCryptoAPI/supports.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/supports.tentative.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCrypto API: supports method tests // META: script=util/helpers.js +// META: script=util/supports.js 'use strict'; @@ -156,12 +157,7 @@ const operations = [ ]; // Test that supports method exists and is a static method -test(() => { - assert_true( - typeof SubtleCrypto.supports === 'function', - 'SubtleCrypto.supports should be a function' - ); -}, 'SubtleCrypto.supports method exists'); +testSupportsMethod(); // Test invalid operation names test(() => { @@ -192,57 +188,7 @@ test(() => { }, 'supports returns false for invalid algorithms'); // Test standard WebCrypto algorithms for requested operations -for (const [algorithmName, algorithmInfo] of Object.entries( - standardAlgorithms -)) { - for (const operation of operations) { - promise_test(async (t) => { - const isSupported = algorithmInfo.operations.includes(operation); - - // Use appropriate algorithm parameters for each operation - let algorithm; - let length; - switch (operation) { - case 'generateKey': - algorithm = algorithmInfo.keyGenParams || algorithmName; - break; - case 'importKey': - algorithm = algorithmInfo.importParams || algorithmName; - break; - case 'sign': - case 'verify': - algorithm = algorithmInfo.signParams || algorithmName; - break; - case 'encrypt': - case 'decrypt': - algorithm = algorithmInfo.encryptParams || algorithmName; - break; - case 'deriveBits': - algorithm = algorithmInfo.deriveBitsParams || algorithmName; - if (algorithm?.public instanceof Promise) { - algorithm.public = (await algorithm.public).publicKey; - } - if (algorithmName === 'PBKDF2' || algorithmName === 'HKDF') { - length = 256; - } - break; - case 'digest': - algorithm = algorithmName; - break; - default: - algorithm = algorithmName; - } - - const result = SubtleCrypto.supports(operation, algorithm, length); - - if (isSupported) { - assert_true(result, `${algorithmName} should support ${operation}`); - } else { - assert_false(result, `${algorithmName} should not support ${operation}`); - } - }, `supports(${operation}, ${algorithmName})`); - } -} +runSupportsTests(standardAlgorithms, operations); // Test algorithm objects (not just strings) test(() => { diff --git a/test/fixtures/wpt/WebCryptoAPI/util/ec_key_fixtures.js b/test/fixtures/wpt/WebCryptoAPI/util/ec_key_fixtures.js new file mode 100644 index 000000000000..e298fa8f9ebe --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/util/ec_key_fixtures.js @@ -0,0 +1,50 @@ +var ecKeyData = { + "P-521": { + spki: new Uint8Array([48, 129, 155, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 3, 129, 134, 0, 4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56, 251]), + spki_compressed: new Uint8Array([48, 88, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 3, 68, 0, 3, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63]), + raw: new Uint8Array([4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56, 251]), + raw_compressed: new Uint8Array([3, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63]), + pkcs8: new Uint8Array([48, 129, 238, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 4, 129, 214, 48, 129, 211, 2, 1, 1, 4, 66, 0, 244, 8, 117, 131, 104, 186, 147, 15, 48, 247, 106, 224, 84, 254, 92, 210, 206, 127, 218, 44, 159, 118, 166, 212, 54, 207, 117, 214, 108, 68, 11, 254, 99, 49, 199, 193, 114, 161, 36, 120, 25, 60, 130, 81, 72, 123, 201, 18, 99, 250, 80, 33, 127, 133, 255, 99, 111, 89, 205, 84, 110, 58, 180, 131, 180, 161, 129, 137, 3, 129, 134, 0, 4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56, 251]), + pkcs8_private_only: new Uint8Array([48, 96, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 4, 73, 48, 71, 2, 1, 1, 4, 66, 0, 244, 8, 117, 131, 104, 186, 147, 15, 48, 247, 106, 224, 84, 254, 92, 210, 206, 127, 218, 44, 159, 118, 166, 212, 54, 207, 117, 214, 108, 68, 11, 254, 99, 49, 199, 193, 114, 161, 36, 120, 25, 60, 130, 81, 72, 123, 201, 18, 99, 250, 80, 33, 127, 133, 255, 99, 111, 89, 205, 84, 110, 58, 180, 131, 180]), + jwk: { + kty: "EC", + crv: "P-521", + x: "AVb0efjfHiCn_8BM5CDD4VSuJRmWvuQvA0uE1Bt0PzTkXzEbgTqc3sjNpZu7vTHUYLMpJSHnwbci5WZ8A9svrnU_", + y: "AVAXNs_iRzlDINjkr8L9ObWpMxBhuB4iQSgrnheJGCK1t54FL0WXtZZD_Tk3nFG9USXE9IvD8CXOPNNpUyhsyzj7", + d: "APQIdYNoupMPMPdq4FT-XNLOf9osn3am1DbPddZsRAv-YzHHwXKhJHgZPIJRSHvJEmP6UCF_hf9jb1nNVG46tIO0" + } + }, + + "P-256": { + spki: new Uint8Array([48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97, 232]), + spki_compressed: new Uint8Array([48, 57, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 34, 0, 2, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209]), + raw: new Uint8Array([4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97, 232]), + raw_compressed: new Uint8Array([2, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209]), + pkcs8: new Uint8Array([48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 19, 211, 58, 45, 90, 191, 156, 249, 235, 178, 31, 248, 96, 212, 174, 254, 110, 86, 231, 119, 144, 244, 222, 233, 180, 8, 132, 235, 211, 53, 68, 234, 161, 68, 3, 66, 0, 4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97, 232]), + pkcs8_private_only: new Uint8Array([48, 65, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 4, 39, 48, 37, 2, 1, 1, 4, 32, 19, 211, 58, 45, 90, 191, 156, 249, 235, 178, 31, 248, 96, 212, 174, 254, 110, 86, 231, 119, 144, 244, 222, 233, 180, 8, 132, 235, 211, 53, 68, 234]), + jwk: { + kty: "EC", + crv: "P-256", + x: "0hCwpvnZ8BKGgFi0P6T0cQGFQ7ugDJJQ35JXwqyuXdE", + y: "zgN1UtSBRQzjm00QlXAbF1v6s0uObAmeGPHBmDWDYeg", + d: "E9M6LVq_nPnrsh_4YNSu_m5W53eQ9N7ptAiE69M1ROo" + } + }, + + "P-384": { + spki: new Uint8Array([48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172, 232]), + spki_compressed: new Uint8Array([48, 70, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 50, 0, 2, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53]), + raw: new Uint8Array([4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172, 232]), + raw_compressed: new Uint8Array([2, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53]), + pkcs8: new Uint8Array([48, 129, 182, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 4, 129, 158, 48, 129, 155, 2, 1, 1, 4, 48, 69, 55, 181, 153, 7, 132, 211, 194, 210, 46, 150, 168, 249, 47, 161, 170, 73, 46, 232, 115, 229, 118, 164, 21, 130, 225, 68, 24, 60, 152, 136, 209, 14, 107, 158, 180, 206, 212, 178, 204, 64, 18, 228, 172, 94, 168, 64, 115, 161, 100, 3, 98, 0, 4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172, 232]), + pkcs8_private_only: new Uint8Array([48, 78, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 4, 55, 48, 53, 2, 1, 1, 4, 48, 69, 55, 181, 153, 7, 132, 211, 194, 210, 46, 150, 168, 249, 47, 161, 170, 73, 46, 232, 115, 229, 118, 164, 21, 130, 225, 68, 24, 60, 152, 136, 209, 14, 107, 158, 180, 206, 212, 178, 204, 64, 18, 228, 172, 94, 168, 64, 115]), + jwk: { + kty: "EC", + crv: "P-384", + x: "IZwU1mYXs27G2IVrOFtzp000T9iude8EZDXdpU47RL1fvevR0I3Wni19wdwhjLQ1", + y: "vSgTjMd4M3qEL2vWGyQOdCSfJGZ8KlgQp2v8KOAzX4imUB3sAZdtqFr7AIactqzo", + d: "RTe1mQeE08LSLpao-S-hqkku6HPldqQVguFEGDyYiNEOa560ztSyzEAS5KxeqEBz" + } + }, + +}; diff --git a/test/fixtures/wpt/WebCryptoAPI/util/helpers.js b/test/fixtures/wpt/WebCryptoAPI/util/helpers.js index 3d44b7a7550e..cc44dd16b1c9 100644 --- a/test/fixtures/wpt/WebCryptoAPI/util/helpers.js +++ b/test/fixtures/wpt/WebCryptoAPI/util/helpers.js @@ -40,6 +40,21 @@ var registeredAlgorithmNames = [ "KMAC256", ]; +var allKeyUsages = [ + "encrypt", + "decrypt", + "sign", + "verify", + "wrapKey", + "unwrapKey", + "deriveKey", + "deriveBits", + "encapsulateKey", + "encapsulateBits", + "decapsulateKey", + "decapsulateBits", +]; + // Treats an array as a set, and generates an array of all non-empty // subsets (which are themselves arrays). @@ -86,6 +101,35 @@ function objectToString(obj) { } } +function mismatchedCryptoKeyAlgorithmMembers(keyAlgorithm, algorithm, registeredAlgorithmName) { + const mismatches = []; + + if (["HMAC", "RSASSA-PKCS1-v1_5", "RSA-PSS", "RSA-OAEP"].includes(registeredAlgorithmName)) { + const expectedHash = typeof algorithm.hash === "string" ? + algorithm.hash : algorithm.hash.name; + if (keyAlgorithm.hash.name.toUpperCase() !== expectedHash.toUpperCase()) { + mismatches.push("hash"); + } + } + + if (algorithm.namedCurve !== undefined && + keyAlgorithm.namedCurve !== algorithm.namedCurve) { + mismatches.push("namedCurve"); + } + + if (algorithm.modulusLength !== undefined && + keyAlgorithm.modulusLength !== algorithm.modulusLength) { + mismatches.push("modulusLength"); + } + + if (algorithm.publicExponent !== undefined && + !equalBuffers(keyAlgorithm.publicExponent, algorithm.publicExponent)) { + mismatches.push("publicExponent"); + } + + return mismatches; +} + // Is key a CryptoKey object with correct algorithm, extractable, and usages? // Is it a secret, private, or public kind of key? function assert_goodCryptoKey(key, algorithm, extractable, usages, kind) { @@ -132,9 +176,13 @@ function assert_goodCryptoKey(key, algorithm, extractable, usages, kind) { } else { assert_equals(key.algorithm.length, algorithm.length, "Correct length"); } - if (["HMAC", "RSASSA-PKCS1-v1_5", "RSA-PSS"].includes(registeredAlgorithmName)) { - assert_equals(key.algorithm.hash.name.toUpperCase(), algorithm.hash.toUpperCase(), "Correct hash function"); - } + assert_array_equals( + mismatchedCryptoKeyAlgorithmMembers( + key.algorithm, + algorithm, + registeredAlgorithmName), + [], + "Algorithm members are correct"); if (/^(?:Ed|X)(?:25519|448)$/.test(key.algorithm.name)) { assert_false('namedCurve' in key.algorithm, "Does not have a namedCurve property"); @@ -164,12 +212,9 @@ function assert_goodCryptoKey(key, algorithm, extractable, usages, kind) { // The usages parameter could have repeats, but the usages // property of the result should not. - var usageCount = 0; - key.usages.forEach(function(usage) { - usageCount += 1; - assert_in_array(usage, correctUsages, "Has " + usage + " usage"); - }); - assert_equals(key.usages.length, usageCount, "usages property is correct"); + const expectedUsages = unique(correctUsages).sort(); + const actualUsages = [...key.usages].sort(); + assert_array_equals(actualUsages, expectedUsages, "usages property is correct"); assert_equals(key[Symbol.toStringTag], 'CryptoKey', "has the expected Symbol.toStringTag"); } @@ -287,7 +332,7 @@ function bytesToHexString(bytes) if (!bytes) return null; - bytes = new Uint8Array(bytes); + bytes = byteView(bytes); var hexBytes = []; for (var i = 0; i < bytes.length; ++i) { @@ -302,18 +347,25 @@ function bytesToHexString(bytes) function hexStringToUint8Array(hexString) { - if (hexString.length % 2 != 0) - throw "Invalid hexString"; - var arrayBuffer = new Uint8Array(hexString.length / 2); - - for (var i = 0; i < hexString.length; i += 2) { - var byteValue = parseInt(hexString.substr(i, 2), 16); - if (byteValue == NaN) - throw "Invalid hexString"; - arrayBuffer[i/2] = byteValue; + if (hexString.length % 2 !== 0 || !/^[0-9a-f]*$/i.test(hexString)) { + throw new TypeError("Invalid hexadecimal string"); } - return arrayBuffer; + const result = new Uint8Array(hexString.length / 2); + + for (let i = 0; i < hexString.length; i += 2) { + result[i / 2] = parseInt(hexString.slice(i, i + 2), 16); + } + + return result; +} + +function byteView(source) { + if (ArrayBuffer.isView(source)) { + return new Uint8Array(source.buffer, source.byteOffset, source.byteLength); + } + + return new Uint8Array(source); } // Compares two ArrayBuffer or ArrayBufferView objects. If bitCount is @@ -321,44 +373,39 @@ function hexStringToUint8Array(hexString) // in every byte. If bitCount is included, only that leading number of bits // have to match. function equalBuffers(a, b, bitCount) { - var remainder; + const aBytes = byteView(a); + const bBytes = byteView(b); - if (typeof bitCount === "undefined" && a.byteLength !== b.byteLength) { + if (typeof bitCount === "undefined") { + if (aBytes.byteLength !== bBytes.byteLength) { + return false; + } + bitCount = aBytes.byteLength * 8; + } else if (!Number.isInteger(bitCount) || bitCount < 0 || + bitCount > aBytes.byteLength * 8 || + bitCount > bBytes.byteLength * 8) { return false; } - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - var length = a.byteLength; - if (typeof bitCount !== "undefined") { - length = Math.floor(bitCount / 8); - } - - for (var i=0; i> (8 - remainder) === bBytes[length] >> (8 - remainder); + const remainder = bitCount % 8; + if (remainder === 0) { + return true; } - return true; + const mask = 0xff << (8 - remainder); + return (aBytes[length] & mask) === (bBytes[length] & mask); } // Returns a copy of the sourceBuffer it is sent. function copyBuffer(sourceBuffer) { - var source = new Uint8Array(sourceBuffer); - var copy = new Uint8Array(sourceBuffer.byteLength) - - for (var i=0; i { + assert_true( + typeof SubtleCrypto.supports === 'function', + 'SubtleCrypto.supports should be a function' + ); + }, 'SubtleCrypto.supports method exists'); +} + +function runSupportsTests(algorithms, operations) { + for (const [algorithmName, algorithmInfo] of Object.entries(algorithms)) { + for (const operation of operations) { + promise_test(async (t) => { + const isSupported = algorithmInfo.operations.includes(operation); + + let algorithm; + let lengthOrAdditionalAlgorithm; + switch (operation) { + case 'generateKey': + algorithm = algorithmInfo.keyGenParams || algorithmName; + break; + case 'importKey': + algorithm = algorithmInfo.importParams || algorithmName; + break; + case 'sign': + case 'verify': + algorithm = algorithmInfo.signParams || algorithmName; + break; + case 'encrypt': + case 'decrypt': + algorithm = algorithmInfo.encryptParams || algorithmName; + break; + case 'deriveBits': + algorithm = algorithmInfo.deriveBitsParams || algorithmName; + if (algorithm?.public instanceof Promise) { + algorithm.public = (await algorithm.public).publicKey; + } + if (algorithmName === 'PBKDF2' || algorithmName === 'HKDF') { + lengthOrAdditionalAlgorithm = 256; + } + break; + case 'digest': + algorithm = algorithmName; + break; + case 'encapsulateKey': + case 'encapsulateBits': + case 'decapsulateKey': + case 'decapsulateBits': + algorithm = algorithmName; + if (operation === 'encapsulateKey' || operation === 'decapsulateKey') { + lengthOrAdditionalAlgorithm = { name: 'AES-GCM', length: 256 }; + } + break; + default: + algorithm = algorithmName; + } + + const result = SubtleCrypto.supports( + operation, + algorithm, + lengthOrAdditionalAlgorithm + ); + + if (isSupported) { + assert_true(result, `${algorithmName} should support ${operation}`); + } else { + assert_false(result, `${algorithmName} should not support ${operation}`); + } + }, `supports(${operation}, ${algorithmName})`); + } + } +} diff --git a/test/fixtures/wpt/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.https.any.js b/test/fixtures/wpt/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.https.any.js index 9fa3bb775d42..d7a044030826 100644 --- a/test/fixtures/wpt/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.https.any.js @@ -1,6 +1,7 @@ // META: title=WebCryptoAPI: wrapKey() and unwrapKey() // META: timeout=long // META: script=../util/helpers.js +// META: script=../util/okp_key_fixtures.js // META: script=wrapKey_unwrapKey_vectors.js // Tests for wrapKey and unwrapKey round tripping @@ -285,7 +286,7 @@ } if ("kty" in exportedKey && algorithmName === "AES-KW") { - return JSON.stringify(exportedKey).length % 8 == 0; + return JSON.stringify(exportedKey).length % 8 === 0; } if ("kty" in exportedKey && algorithmName === "RSA-OAEP") { @@ -478,4 +479,3 @@ function str2ab(str) { return Uint8Array.from( str.split(''), function(s){return s.charCodeAt(0)} ); } function ab2str(ab) { return String.fromCharCode.apply(null, new Uint8Array(ab)); } - diff --git a/test/fixtures/wpt/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey_vectors.js b/test/fixtures/wpt/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey_vectors.js index cf799a8a8ce3..36500e4f27ba 100644 --- a/test/fixtures/wpt/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey_vectors.js +++ b/test/fixtures/wpt/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey_vectors.js @@ -49,46 +49,10 @@ let toWrapKeyData = { d: "E9M6LVq_nPnrsh_4YNSu_m5W53eQ9N7ptAiE69M1ROo" } }, - "ED25519": { - spki: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 112, 3, 33, 0, 216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61, 204]), - pkcs8: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32, 243, 200, 244, 196, 141, 248, 120, 20, 110, 140, 211, 191, 109, 244, 229, 14, 56, 155, 167, 7, 78, 21, 194, 53, 45, 205, 93, 48, 141, 76, 168, 31]), - jwk: { - crv: "Ed25519", - d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8", - x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPcw", - kty: "OKP" - } - }, - "ED448": { - spki: new Uint8Array([48, 67, 48, 5, 6, 3, 43, 101, 113, 3, 58, 0, 171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90, 128]), - pkcs8: new Uint8Array([48, 71, 2, 1, 0, 48, 5, 6, 3, 43, 101, 113, 4, 59, 4, 57, 14, 255, 3, 69, 140, 40, 224, 23, 156, 82, 29, 227, 18, 201, 105, 183, 131, 67, 72, 236, 171, 153, 26, 96, 227, 178, 233, 167, 158, 76, 217, 228, 128, 239, 41, 23, 18, 210, 200, 61, 4, 114, 114, 213, 201, 244, 40, 102, 79, 105, 109, 38, 112, 69, 143, 29, 46]), - jwk: { - crv: "Ed448", - d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u", - x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA", - kty: "OKP" - } - }, - "X25519": { - spki: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151, 6]), - pkcs8: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 110, 4, 34, 4, 32, 200, 131, 142, 118, 208, 87, 223, 183, 216, 201, 90, 105, 225, 56, 22, 10, 221, 99, 115, 253, 113, 164, 210, 118, 187, 86, 227, 168, 27, 100, 255, 97]), - jwk: { - crv: "X25519", - d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2E", - x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY", - kty: "OKP" - } - }, - "X448": { - spki: new Uint8Array([48, 66, 48, 5, 6, 3, 43, 101, 111, 3, 57, 0, 182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206, 111]), - pkcs8: new Uint8Array([48, 70, 2, 1, 0, 48, 5, 6, 3, 43, 101, 111, 4, 58, 4, 56, 88, 199, 210, 154, 62, 181, 25, 178, 157, 0, 207, 177, 145, 187, 100, 252, 109, 138, 66, 216, 241, 113, 118, 39, 43, 137, 242, 39, 45, 24, 25, 41, 92, 101, 37, 192, 130, 150, 113, 176, 82, 239, 7, 39, 83, 15, 24, 142, 49, 208, 204, 83, 191, 38, 146, 158]), - jwk: { - crv: "X448", - d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp4", - x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8", - kty: "OKP" - } - }, + "ED25519": okpKeyData.Ed25519, + "ED448": okpKeyData.Ed448, + "X25519": okpKeyData.X25519, + "X448": okpKeyData.X448, "SYMMETRIC128": { raw: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]), }, diff --git a/test/fixtures/wpt/urlpattern/WEB_FEATURES.yml b/test/fixtures/wpt/urlpattern/WEB_FEATURES.yml index cb82ba5cda29..f6d02d253e41 100644 --- a/test/fixtures/wpt/urlpattern/WEB_FEATURES.yml +++ b/test/fixtures/wpt/urlpattern/WEB_FEATURES.yml @@ -1,3 +1,2 @@ -features: -- name: urlpattern - files: "**" +rules: +- "**": [urlpattern] diff --git a/test/fixtures/wpt/versions.json b/test/fixtures/wpt/versions.json index 32b9537ffca9..b659c868d498 100644 --- a/test/fixtures/wpt/versions.json +++ b/test/fixtures/wpt/versions.json @@ -76,7 +76,7 @@ "path": "url" }, "urlpattern": { - "commit": "5847ee5cfa4f710cbb78ab9ef5cc66f74433ee03", + "commit": "4832db47614f5f48cc57374cbf5c1f70937fad48", "path": "urlpattern" }, "user-timing": { @@ -96,7 +96,7 @@ "path": "web-locks" }, "WebCryptoAPI": { - "commit": "ec2fee39a4ca3c13afd55236795547eedd7f165d", + "commit": "4c2fd05ed5d0b90a9e1fcdcb35f6671bd461de0d", "path": "WebCryptoAPI" }, "webidl": { diff --git a/test/parallel/parallel.status b/test/parallel/parallel.status index e4c82da4d617..d13efc8ac172 100644 --- a/test/parallel/parallel.status +++ b/test/parallel/parallel.status @@ -60,8 +60,6 @@ test-http-server-headers-timeout-keepalive: PASS,FLAKY test-http-server-request-timeout-keepalive: PASS,FLAKY # https://github.com/nodejs/node/issues/60050 test-cluster-dgram-1: SKIP -# https://github.com/nodejs/node/issues/64005 -test-debugger-run-after-quit-restart: PASS,FLAKY [$arch==arm || $arch==arm64] # https://github.com/nodejs/node/pull/31178 diff --git a/test/parallel/test-arm-math-illegal-instruction.js b/test/parallel/test-arm-math-illegal-instruction.js index c4a6ec01ba88..0e53a22c5244 100644 --- a/test/parallel/test-arm-math-illegal-instruction.js +++ b/test/parallel/test-arm-math-illegal-instruction.js @@ -9,10 +9,10 @@ const { test } = require('node:test'); // Iterate over all Math functions test('Iterate over all Math functions', () => { - Object.getOwnPropertyNames(Math).forEach((functionName) => { + for (const functionName of Object.getOwnPropertyNames(Math)) { if (!/[A-Z]/.test(functionName)) { // The function names don't have capital letters. Math[functionName](-0.5); } - }); + } }); diff --git a/test/parallel/test-async-local-storage-bind.js b/test/parallel/test-async-local-storage-bind.js index d8d4c4599826..01aa449c1d46 100644 --- a/test/parallel/test-async-local-storage-bind.js +++ b/test/parallel/test-async-local-storage-bind.js @@ -4,11 +4,11 @@ const common = require('../common'); const assert = require('assert'); const { AsyncLocalStorage } = require('async_hooks'); -[1, false, '', {}, []].forEach((i) => { +for (const i of [1, false, '', {}, []]) { assert.throws(() => AsyncLocalStorage.bind(i), { code: 'ERR_INVALID_ARG_TYPE' }); -}); +} const fn = common.mustCall(AsyncLocalStorage.bind(() => 123)); assert.strictEqual(fn(), 123); diff --git a/test/parallel/test-blocklist-fast-api.js b/test/parallel/test-blocklist-fast-api.js new file mode 100644 index 000000000000..3c59ad361d1a --- /dev/null +++ b/test/parallel/test-blocklist-fast-api.js @@ -0,0 +1,42 @@ +// Flags: --allow-natives-syntax --expose-internals --no-warnings +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const { BlockList } = require('net'); +const { internalBinding } = require('internal/test/binding'); + +// The fast API is on the native check() method which takes a +// SocketAddressBase object. The JS BlockList.prototype.check() routes +// string arguments to checkString() which has no fast API, so we need +// to use SocketAddress objects to exercise the fast API path. +const { kHandle: kBlockListHandle } = require('internal/blocklist'); +const { + SocketAddress, + kHandle: kSocketAddressHandle, +} = require('internal/socketaddress'); + +const blockList = new BlockList(); +blockList.addAddress('1.1.1.1'); +blockList.addSubnet('10.0.0.0', 24); + +const handle = blockList[kBlockListHandle]; +const addr1 = new SocketAddress({ address: '1.1.1.1' })[kSocketAddressHandle]; +const addr2 = new SocketAddress({ address: '2.2.2.2' })[kSocketAddressHandle]; +const addr3 = new SocketAddress({ address: '10.0.0.5' })[kSocketAddressHandle]; + +function testFastCheck() { + assert.strictEqual(handle.check(addr1), true); + assert.strictEqual(handle.check(addr2), false); + assert.strictEqual(handle.check(addr3), true); +} + +eval('%PrepareFunctionForOptimization(testFastCheck)'); +testFastCheck(); +eval('%OptimizeFunctionOnNextCall(testFastCheck)'); +testFastCheck(); + +if (common.isDebug) { + const { getV8FastApiCallCount } = internalBinding('debug'); + assert.strictEqual(getV8FastApiCallCount('blocklist.check'), 3); +} diff --git a/test/parallel/test-blocklist.js b/test/parallel/test-blocklist.js index 6895efcc1c00..08a293bb6a81 100644 --- a/test/parallel/test-blocklist.js +++ b/test/parallel/test-blocklist.js @@ -178,11 +178,11 @@ const util = require('util'); blockList.addSubnet('8592:757c:efae:4e45::', 64, 'IpV6'); // Case insensitive const rulesCheck = [ + 'Address: IPv4 1.1.1.1', 'Subnet: IPv6 8592:757c:efae:4e45::/64', 'Range: IPv4 10.0.0.1-10.0.0.10', - 'Address: IPv4 1.1.1.1', ]; - assert.deepStrictEqual(blockList.rules, rulesCheck); + assert.deepStrictEqual(blockList.rules.sort(), rulesCheck.sort()); assert(blockList.check('1.1.1.1')); assert(blockList.check('10.0.0.5')); @@ -288,6 +288,88 @@ const util = require('util'); assert(!BlockList.isBlockList({})); } +{ + // Test that adding the same address twice does not create duplicate rules. + // Previously, the second add would orphan the first rule in the internal + // list while overwriting its index entry, making it unreachable for removal + // but still evaluated during checks. + const blockList = new BlockList(); + blockList.addAddress('1.1.1.1'); + blockList.addAddress('1.1.1.1'); + + // Should have exactly one rule, not two. + assert.strictEqual(blockList.rules.length, 1); + assert(blockList.check('1.1.1.1')); +} + +{ + // Test clear() removes all rules. + const blockList = new BlockList(); + blockList.addAddress('1.1.1.1'); + blockList.addRange('10.0.0.1', '10.0.0.10'); + blockList.addSubnet('192.168.0.0', 16); + + assert.strictEqual(blockList.rules.length, 3); + assert(blockList.check('1.1.1.1')); + assert(blockList.check('10.0.0.5')); + assert(blockList.check('192.168.1.1')); + + blockList.clear(); + + assert.strictEqual(blockList.rules.length, 0); + assert(!blockList.check('1.1.1.1')); + assert(!blockList.check('10.0.0.5')); + assert(!blockList.check('192.168.1.1')); + + // Can add new rules after clearing. + blockList.addAddress('2.2.2.2'); + assert.strictEqual(blockList.rules.length, 1); + assert(blockList.check('2.2.2.2')); + assert(!blockList.check('1.1.1.1')); +} + +{ + // addAddresses() validation: non-array argument throws. + const blockList0 = new BlockList(); + assert.throws(() => blockList0.addAddresses('not-an-array'), { + code: 'ERR_INVALID_ARG_TYPE', + }); + assert.throws(() => blockList0.addAddresses(123), { + code: 'ERR_INVALID_ARG_TYPE', + }); +} + +{ + // Test addAddresses() batch insert. + const blockList = new BlockList(); + blockList.addAddresses(['1.1.1.1', '2.2.2.2', '3.3.3.3']); + + assert(blockList.check('1.1.1.1')); + assert(blockList.check('2.2.2.2')); + assert(blockList.check('3.3.3.3')); + assert(!blockList.check('4.4.4.4')); + assert.strictEqual(blockList.rules.length, 3); + + // Cross-family works with batch insert. + assert(blockList.check('::ffff:1.1.1.1', 'ipv6')); + + // Batch with SocketAddress objects. + const blockList2 = new BlockList(); + const sa1 = new SocketAddress({ address: '10.0.0.1' }); + const sa2 = new SocketAddress({ address: '10.0.0.2' }); + blockList2.addAddresses([sa1, sa2]); + assert(blockList2.check('10.0.0.1')); + assert(blockList2.check('10.0.0.2')); + assert(!blockList2.check('10.0.0.3')); + + // IPv6 batch. + const blockList3 = new BlockList(); + blockList3.addAddresses(['::1', '::2'], 'ipv6'); + assert(blockList3.check('::1', 'ipv6')); + assert(blockList3.check('::2', 'ipv6')); + assert(!blockList3.check('::3', 'ipv6')); +} + // Test exporting and importing the rule list to/from JSON { const ruleList = [ @@ -359,3 +441,489 @@ const util = require('util'); assert.strictEqual(test5.check(i[0], i[1]), i[2]); }); } + +// removeRange: basic removal +{ + const blockList = new BlockList(); + blockList.addRange('10.0.0.1', '10.0.0.100'); + blockList.addRange('192.168.1.1', '192.168.1.50'); + assert(blockList.check('10.0.0.50')); + assert(blockList.check('192.168.1.25')); + + blockList.removeRange('10.0.0.1', '10.0.0.100'); + assert(!blockList.check('10.0.0.50')); + assert(blockList.check('192.168.1.25')); + assert.strictEqual(blockList.rules.length, 1); +} + +// removeRange: non-existent range is a no-op +{ + const blockList = new BlockList(); + blockList.addRange('10.0.0.1', '10.0.0.10'); + assert.strictEqual(blockList.rules.length, 1); + blockList.removeRange('99.99.99.1', '99.99.99.10'); + assert.strictEqual(blockList.rules.length, 1); + assert(blockList.check('10.0.0.5')); +} + +// removeRange: IPv6 range +{ + const blockList = new BlockList(); + blockList.addRange('2001:db8::1', '2001:db8::ff', 'ipv6'); + assert(blockList.check('2001:db8::50', 'ipv6')); + + blockList.removeRange('2001:db8::1', '2001:db8::ff', 'ipv6'); + assert(!blockList.check('2001:db8::50', 'ipv6')); + assert.strictEqual(blockList.rules.length, 0); +} + +// removeRange: with SocketAddress objects +{ + const blockList = new BlockList(); + const start = new SocketAddress({ address: '10.0.0.1' }); + const end = new SocketAddress({ address: '10.0.0.10' }); + blockList.addRange(start, end); + assert(blockList.check('10.0.0.5')); + + blockList.removeRange(start, end); + assert(!blockList.check('10.0.0.5')); +} + +// removeSubnet: basic IPv4 removal +{ + const blockList = new BlockList(); + blockList.addSubnet('10.0.0.0', 8); + blockList.addSubnet('192.168.0.0', 16); + assert(blockList.check('10.1.2.3')); + assert(blockList.check('192.168.5.5')); + + blockList.removeSubnet('10.0.0.0', 8); + assert(!blockList.check('10.1.2.3')); + assert(blockList.check('192.168.5.5')); + assert.strictEqual(blockList.rules.length, 1); +} + +// removeSubnet: IPv6 +{ + const blockList = new BlockList(); + blockList.addSubnet('2001:db8::', 32, 'ipv6'); + assert(blockList.check('2001:db8::1', 'ipv6')); + + blockList.removeSubnet('2001:db8::', 32, 'ipv6'); + assert(!blockList.check('2001:db8::1', 'ipv6')); + assert.strictEqual(blockList.rules.length, 0); +} + +// removeSubnet: cross-family cleanup +{ + const blockList = new BlockList(); + blockList.addSubnet('10.0.0.0', 8); + assert(blockList.check('::ffff:10.0.0.1', 'ipv6')); + + blockList.removeSubnet('10.0.0.0', 8); + assert(!blockList.check('10.0.0.1')); + assert(!blockList.check('::ffff:10.0.0.1', 'ipv6')); +} + +// removeSubnet: non-existent subnet is a no-op +{ + const blockList = new BlockList(); + blockList.addSubnet('10.0.0.0', 8); + blockList.removeSubnet('172.16.0.0', 12); + assert(blockList.check('10.1.2.3')); + assert.strictEqual(blockList.rules.length, 1); +} + +// removeSubnet: with SocketAddress objects +{ + const blockList = new BlockList(); + const net = new SocketAddress({ address: '10.0.0.0' }); + blockList.addSubnet(net, 8); + assert(blockList.check('10.1.2.3')); + + blockList.removeSubnet(net, 8); + assert(!blockList.check('10.1.2.3')); +} + +// removeRange/removeSubnet don't affect other rule types +{ + const blockList = new BlockList(); + blockList.addAddress('1.1.1.1'); + blockList.addRange('10.0.0.1', '10.0.0.100'); + blockList.addSubnet('192.168.0.0', 16); + + blockList.removeRange('10.0.0.1', '10.0.0.100'); + blockList.removeSubnet('192.168.0.0', 16); + + // Address rule should still work + assert(blockList.check('1.1.1.1')); + assert(!blockList.check('10.0.0.50')); + assert(!blockList.check('192.168.1.1')); +} + +// addCIDR: IPv4 +{ + const blockList = new BlockList(); + blockList.addCIDR('10.0.0.0/8'); + blockList.addCIDR('192.168.1.0/24'); + assert(blockList.check('10.1.2.3')); + assert(blockList.check('192.168.1.50')); + assert(!blockList.check('192.168.2.1')); + assert(!blockList.check('11.0.0.1')); +} + +// addCIDR: IPv6 auto-detected +{ + const blockList = new BlockList(); + blockList.addCIDR('2001:db8::/32'); + assert(blockList.check('2001:db8::1', 'ipv6')); + assert(blockList.check('2001:db8:ffff::1', 'ipv6')); + assert(!blockList.check('2001:db9::1', 'ipv6')); +} + +// addCIDR: cross-family +{ + const blockList = new BlockList(); + blockList.addCIDR('10.0.0.0/8'); + assert(blockList.check('::ffff:10.0.0.1', 'ipv6')); +} + +// addCIDR: validation errors +{ + const blockList = new BlockList(); + assert.throws(() => blockList.addCIDR('10.0.0.0'), { + code: 'ERR_INVALID_ARG_VALUE', + }); + assert.throws(() => blockList.addCIDR('10.0.0.0/abc'), { + code: 'ERR_INVALID_ARG_VALUE', + }); + assert.throws(() => blockList.addCIDR(123), { + code: 'ERR_INVALID_ARG_TYPE', + }); + assert.throws(() => blockList.addCIDR('10.0.0.0/'), { + code: 'ERR_INVALID_ARG_VALUE', + }); +} + +// removeCIDR: basic +{ + const blockList = new BlockList(); + blockList.addCIDR('10.0.0.0/8'); + blockList.addCIDR('192.168.0.0/16'); + assert(blockList.check('10.1.2.3')); + + blockList.removeCIDR('10.0.0.0/8'); + assert(!blockList.check('10.1.2.3')); + assert(blockList.check('192.168.1.1')); + assert.strictEqual(blockList.rules.length, 1); +} + +// removeCIDR: IPv6 +{ + const blockList = new BlockList(); + blockList.addCIDR('2001:db8::/32'); + assert(blockList.check('2001:db8::1', 'ipv6')); + + blockList.removeCIDR('2001:db8::/32'); + assert(!blockList.check('2001:db8::1', 'ipv6')); + assert.strictEqual(blockList.rules.length, 0); +} + +// removeCIDR: non-existent is a no-op +{ + const blockList = new BlockList(); + blockList.addCIDR('10.0.0.0/8'); + blockList.removeCIDR('172.16.0.0/12'); + assert(blockList.check('10.1.2.3')); + assert.strictEqual(blockList.rules.length, 1); +} + +// addCIDR interoperates with removeSubnet, and vice versa +{ + const blockList = new BlockList(); + blockList.addCIDR('10.0.0.0/8'); + blockList.removeSubnet('10.0.0.0', 8); + assert(!blockList.check('10.1.2.3')); + + blockList.addSubnet('192.168.0.0', 16); + blockList.removeCIDR('192.168.0.0/16'); + assert(!blockList.check('192.168.1.1')); +} + +// removeAddress: basic +{ + const blockList = new BlockList(); + blockList.addAddress('1.1.1.1'); + blockList.addAddress('2.2.2.2'); + assert(blockList.check('1.1.1.1')); + + blockList.removeAddress('1.1.1.1'); + assert(!blockList.check('1.1.1.1')); + assert(blockList.check('2.2.2.2')); +} + +// removeAddress: cross-family cleanup +{ + const blockList = new BlockList(); + blockList.addAddress('3.3.3.3'); + assert(blockList.check('::ffff:3.3.3.3', 'ipv6')); + + blockList.removeAddress('3.3.3.3'); + assert(!blockList.check('3.3.3.3')); + assert(!blockList.check('::ffff:3.3.3.3', 'ipv6')); +} + +// removeAddress: IPv6 +{ + const blockList = new BlockList(); + blockList.addAddress('::1', 'ipv6'); + assert(blockList.check('::1', 'ipv6')); + + blockList.removeAddress('::1', 'ipv6'); + assert(!blockList.check('::1', 'ipv6')); +} + +// removeAddress: non-existent is a no-op +{ + const blockList = new BlockList(); + blockList.addAddress('1.1.1.1'); + blockList.removeAddress('9.9.9.9'); + assert(blockList.check('1.1.1.1')); +} + +// removeAddress: with SocketAddress object +{ + const blockList = new BlockList(); + const addr = new SocketAddress({ address: '5.5.5.5' }); + blockList.addAddress(addr); + assert(blockList.check('5.5.5.5')); + + blockList.removeAddress(addr); + assert(!blockList.check('5.5.5.5')); +} + +// addCIDRs: batch +{ + const blockList = new BlockList(); + blockList.addCIDRs(['10.0.0.0/8', '192.168.0.0/16', '2001:db8::/32']); + assert(blockList.check('10.1.2.3')); + assert(blockList.check('192.168.1.1')); + assert(blockList.check('2001:db8::1', 'ipv6')); + assert(!blockList.check('11.0.0.1')); + assert.strictEqual(blockList.rules.length, 3); +} + +// addCIDRs: validation +{ + const blockList = new BlockList(); + assert.throws(() => blockList.addCIDRs('not-an-array'), { + code: 'ERR_INVALID_ARG_TYPE', + }); + assert.throws(() => blockList.addCIDRs([123]), { + code: 'ERR_INVALID_ARG_TYPE', + }); + assert.throws(() => blockList.addCIDRs(['10.0.0.0']), { + code: 'ERR_INVALID_ARG_VALUE', + }); +} + +// addCIDRs: empty array is a no-op +{ + const blockList = new BlockList(); + blockList.addCIDRs([]); + assert.strictEqual(blockList.size, 0); +} + +// addCIDRs: invalid entry mid-array does not half-apply +{ + const blockList = new BlockList(); + assert.throws(() => blockList.addCIDRs(['10.0.0.0/8', 'bad', '1.1.1.0/24']), { + code: 'ERR_INVALID_ARG_VALUE', + }); + // Nothing should have been applied. + assert.strictEqual(blockList.size, 0); + assert(!blockList.check('10.0.0.1')); +} + +// size: tracks all rule types +{ + const blockList = new BlockList(); + assert.strictEqual(blockList.size, 0); + + blockList.addAddress('1.1.1.1'); + assert.strictEqual(blockList.size, 1); + + blockList.addRange('10.0.0.1', '10.0.0.10'); + assert.strictEqual(blockList.size, 2); + + blockList.addSubnet('192.168.0.0', 16); + assert.strictEqual(blockList.size, 3); + + // Matches rules.length + assert.strictEqual(blockList.size, blockList.rules.length); + + blockList.removeAddress('1.1.1.1'); + assert.strictEqual(blockList.size, 2); + + blockList.removeRange('10.0.0.1', '10.0.0.10'); + assert.strictEqual(blockList.size, 1); + + blockList.removeSubnet('192.168.0.0', 16); + assert.strictEqual(blockList.size, 0); + + // After clear + blockList.addAddress('5.5.5.5'); + blockList.clear(); + assert.strictEqual(blockList.size, 0); +} + +// size: duplicate addAddress does not double-count +{ + const blockList = new BlockList(); + blockList.addAddress('1.1.1.1'); + blockList.addAddress('1.1.1.1'); + assert.strictEqual(blockList.size, 1); +} + +// PRIVATE_RANGES: is a frozen array of CIDR strings +{ + assert(Array.isArray(BlockList.PRIVATE_RANGES)); + assert(Object.isFrozen(BlockList.PRIVATE_RANGES)); + assert(BlockList.PRIVATE_RANGES.length > 0); + for (const cidr of BlockList.PRIVATE_RANGES) { + assert.strictEqual(typeof cidr, 'string'); + assert(cidr.includes('/')); + } +} + +// PRIVATE_RANGES: covers expected addresses +{ + const blockList = new BlockList(); + blockList.addCIDRs(BlockList.PRIVATE_RANGES); + + // IPv4 private (RFC 1918) + assert(blockList.check('10.0.0.1')); + assert(blockList.check('10.255.255.255')); + assert(blockList.check('172.16.0.1')); + assert(blockList.check('172.31.255.255')); + assert(blockList.check('192.168.0.1')); + assert(blockList.check('192.168.255.255')); + + // Loopback + assert(blockList.check('127.0.0.1')); + assert(blockList.check('127.255.255.255')); + assert(blockList.check('::1', 'ipv6')); + + // Link-local + assert(blockList.check('169.254.0.1')); + assert(blockList.check('fe80::1', 'ipv6')); + + // ULA + assert(blockList.check('fc00::1', 'ipv6')); + assert(blockList.check('fd00::1', 'ipv6')); + + // Public addresses should not match + assert(!blockList.check('8.8.8.8')); + assert(!blockList.check('1.1.1.1')); + assert(!blockList.check('203.0.113.1')); + assert(!blockList.check('2001:db8::1', 'ipv6')); +} + +// check() with invalid address string returns false (exercises checkString +// error path in C++ — SocketAddress::New fails, returns false). +{ + const blockList = new BlockList(); + blockList.addAddress('1.1.1.1'); + assert.strictEqual(blockList.check('not_a_valid_ip'), false); + assert.strictEqual(blockList.check('', 'ipv4'), false); + assert.strictEqual(blockList.check('999.999.999.999'), false); + assert.strictEqual(blockList.check('not_valid_ipv6', 'ipv6'), false); +} + +// check() family parameter is case-insensitive. +{ + const blockList = new BlockList(); + blockList.addAddress('10.0.0.1'); + blockList.addAddress('::1', 'ipv6'); + + assert(blockList.check('10.0.0.1', 'ipv4')); + assert(blockList.check('10.0.0.1', 'IPv4')); + assert(blockList.check('10.0.0.1', 'IPV4')); + assert(blockList.check('::1', 'ipv6')); + assert(blockList.check('::1', 'IPv6')); + assert(blockList.check('::1', 'IPV6')); +} + +// SocketAddress constructor with invalid address throws ERR_INVALID_ADDRESS. +{ + assert.throws(() => new SocketAddress({ address: 'not_a_valid_ip' }), { + code: 'ERR_INVALID_ADDRESS', + }); + assert.throws( + () => new SocketAddress({ address: 'not_valid', family: 'ipv6' }), { + code: 'ERR_INVALID_ADDRESS', + }); +} + +// check() with SocketAddress objects across family boundaries. +{ + const blockList = new BlockList(); + const ipv4 = new SocketAddress({ address: '10.0.0.1' }); + const mapped = new SocketAddress({ + address: '::ffff:10.0.0.1', + family: 'ipv6', + }); + + blockList.addAddress(ipv4); + + // Check with SocketAddress objects (exercises the check() -> C++ fast path). + assert(blockList.check(ipv4)); + assert(blockList.check(mapped)); + + blockList.removeAddress(ipv4); + assert(!blockList.check(ipv4)); + assert(!blockList.check(mapped)); +} + +// Subnet with IPv4-mapped IPv6 network. +{ + const blockList = new BlockList(); + blockList.addSubnet('::ffff:10.0.0.0', 120, 'ipv6'); + + // IPv4-mapped IPv6 within the subnet should match. + assert(blockList.check('::ffff:10.0.0.5', 'ipv6')); + // The plain IPv4 form should also match (cross-family trie lookup). + assert(blockList.check('10.0.0.5')); + // Outside the subnet. + assert(!blockList.check('10.0.1.0')); +} + +// Range with IPv6 addresses. +{ + const blockList = new BlockList(); + blockList.addRange('::1', '::ff', 'ipv6'); + assert(blockList.check('::1', 'ipv6')); + assert(blockList.check('::a0', 'ipv6')); + assert(blockList.check('::ff', 'ipv6')); + assert(!blockList.check('::100', 'ipv6')); + assert(!blockList.check('::0', 'ipv6')); + + blockList.removeRange('::1', '::ff', 'ipv6'); + assert(!blockList.check('::a0', 'ipv6')); +} + +// Removing a broader subnet must restore subsumed narrower subnets. +{ + const blockList = new BlockList(); + blockList.addSubnet('10.0.0.0', 8); // /8 subsumes /16 in the trie + blockList.addSubnet('10.1.0.0', 16); + assert(blockList.check('10.1.2.3')); + + blockList.removeSubnet('10.0.0.0', 8); + + // /16 must still work after /8 is removed. + assert(blockList.check('10.1.2.3')); + // Address outside /16 but inside old /8 should no longer match. + assert(!blockList.check('10.2.0.1')); + assert.strictEqual(blockList.rules.length, 1); +} diff --git a/test/parallel/test-btoa-atob.js b/test/parallel/test-btoa-atob.js index a2c8d9e3134c..3fde039f395e 100644 --- a/test/parallel/test-btoa-atob.js +++ b/test/parallel/test-btoa-atob.js @@ -26,14 +26,17 @@ assert.strictEqual(atob({ toString: () => '' }), ''); assert.strictEqual(atob({ [Symbol.toPrimitive]: () => '' }), ''); assert.throws(() => atob(Symbol()), /TypeError/); -[ +const testCases = [ undefined, false, () => {}, {}, [1], 0, 1, 0n, 1n, -Infinity, 'a', 'a\n\n\n', '\ra\r\r', ' a ', '\t\t\ta', 'a\f\f\f', '\ta\r \n\f', -].forEach((value) => - // See #2 - https://html.spec.whatwg.org/multipage/webappapis.html#dom-atob +]; + +// See #2 - https://html.spec.whatwg.org/multipage/webappapis.html#dom-atob +for (const value of testCases) { assert.throws(() => atob(value), { constructor: DOMException, name: 'InvalidCharacterError', code: 5, - })); + }); +} diff --git a/test/parallel/test-buffer-isascii.js b/test/parallel/test-buffer-isascii.js index b9468ca13359..48cc96a17d61 100644 --- a/test/parallel/test-buffer-isascii.js +++ b/test/parallel/test-buffer-isascii.js @@ -30,13 +30,20 @@ assert.strictEqual(isAscii(Buffer.from([])), true); }); { - // Test with detached array buffers - const arrayBuffer = new ArrayBuffer(1024); + // Detached array buffers and views are treated as empty. + const arrayBuffer = new ArrayBuffer(1); + const typedArray = new Uint8Array(arrayBuffer); + typedArray[0] = 0xff; + const inputs = [ + arrayBuffer, + typedArray, + Buffer.from(arrayBuffer), + ]; + for (const input of inputs) { + assert.strictEqual(isAscii(input), false); + } structuredClone(arrayBuffer, { transfer: [arrayBuffer] }); - assert.throws( - () => { isAscii(arrayBuffer); }, - { - code: 'ERR_INVALID_STATE' - } - ); + for (const input of inputs) { + assert.strictEqual(isAscii(input), true); + } } diff --git a/test/parallel/test-buffer-isutf8.js b/test/parallel/test-buffer-isutf8.js index 204db3e6a5fe..151fc0baf4ae 100644 --- a/test/parallel/test-buffer-isutf8.js +++ b/test/parallel/test-buffer-isutf8.js @@ -74,13 +74,20 @@ assert.strictEqual(isUtf8(Buffer.from([])), true); }); { - // Test with detached array buffers - const arrayBuffer = new ArrayBuffer(1024); + // Detached array buffers and views are treated as empty. + const arrayBuffer = new ArrayBuffer(1); + const typedArray = new Uint8Array(arrayBuffer); + typedArray[0] = 0xff; + const inputs = [ + arrayBuffer, + typedArray, + Buffer.from(arrayBuffer), + ]; + for (const input of inputs) { + assert.strictEqual(isUtf8(input), false); + } structuredClone(arrayBuffer, { transfer: [arrayBuffer] }); - assert.throws( - () => { isUtf8(arrayBuffer); }, - { - code: 'ERR_INVALID_STATE' - } - ); + for (const input of inputs) { + assert.strictEqual(isUtf8(input), true); + } } diff --git a/test/parallel/test-buffer-write.js b/test/parallel/test-buffer-write.js index 4c797059b592..11cfb32ab19a 100644 --- a/test/parallel/test-buffer-write.js +++ b/test/parallel/test-buffer-write.js @@ -127,3 +127,17 @@ assert.throws(() => { }, common.expectsError({ code: 'ERR_BUFFER_OUT_OF_BOUNDS', })); + +for (const method of ['asciiWrite', 'latin1Write', 'utf8Write']) { + let calls = 0; + const offset = { + valueOf() { + calls++; + return 2; + }, + }; + assert.throws(() => Buffer.alloc(1)[method]('ww', offset, 1), common.expectsError({ + code: 'ERR_BUFFER_OUT_OF_BOUNDS', + })); + assert.strictEqual(calls, 1); +} diff --git a/test/parallel/test-child-process-fork-stdio-string-variant.js b/test/parallel/test-child-process-fork-stdio-string-variant.js index 6a396b51d9bd..91691b353a15 100644 --- a/test/parallel/test-child-process-fork-stdio-string-variant.js +++ b/test/parallel/test-child-process-fork-stdio-string-variant.js @@ -29,4 +29,7 @@ function test(stringVariant) { child.on('exit', common.mustCall((code) => assert.strictEqual(code, 0))); } -['pipe', 'inherit', 'ignore'].forEach(test); +const testCases = ['pipe', 'inherit', 'ignore']; +for (const value of testCases) { + test(value); +} diff --git a/test/parallel/test-child-process-ipc-next-tick.js b/test/parallel/test-child-process-ipc-next-tick.js index b23aefc85d11..849a927e251e 100644 --- a/test/parallel/test-child-process-ipc-next-tick.js +++ b/test/parallel/test-child-process-ipc-next-tick.js @@ -32,8 +32,8 @@ if (process.argv[2] === 'child') { child.on('message', common.mustCall((msg) => { assert.strictEqual(msg, 'ready'); - values.forEach((value) => { + for (const value of values) { child.send(value); - }); + }; })); } diff --git a/test/parallel/test-child-process-kill-sigwinch.js b/test/parallel/test-child-process-kill-sigwinch.js new file mode 100644 index 000000000000..e474eefa40b4 --- /dev/null +++ b/test/parallel/test-child-process-kill-sigwinch.js @@ -0,0 +1,34 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const { spawn } = require('child_process'); + +// SIGWINCH is a non-terminal signal: sending it must not terminate the target +// process. On Windows, kill() must surface ENOSYS instead of coercing +// SIGWINCH into a SIGKILL (which would wrongly terminate the process). +// Refs: https://github.com/nodejs/node/issues/64324 + +const child = spawn(process.execPath, ['-e', 'setInterval(() => {}, 1000)']); + +// The process must survive the SIGWINCH; it is only ever torn down by the +// explicit SIGKILL in the cleanup below (after the listener is removed). +child.on('exit', common.mustNotCall('child must survive SIGWINCH')); + +child.on('spawn', common.mustCall(() => { + if (common.isWindows) { + assert.throws(() => child.kill('SIGWINCH'), { code: 'ENOSYS' }); + } else { + assert.strictEqual(child.kill('SIGWINCH'), true); + } + + assert.strictEqual(child.signalCode, null); + assert.strictEqual(child.exitCode, null); + + setTimeout(common.mustCall(() => { + assert.strictEqual(child.signalCode, null); + assert.strictEqual(child.exitCode, null); + + child.removeAllListeners('exit'); + child.kill('SIGKILL'); + }), common.platformTimeout(500)); +})); diff --git a/test/parallel/test-child-process-windows-hide.js b/test/parallel/test-child-process-windows-hide.js index c218c901a7f2..324b342a7c7b 100644 --- a/test/parallel/test-child-process-windows-hide.js +++ b/test/parallel/test-child-process-windows-hide.js @@ -8,6 +8,7 @@ const internalCp = require('internal/child_process'); const cmd = process.execPath; const args = ['-p', '42']; const options = { windowsHide: true }; +const { spawnSyncAndAssert } = require('../common/child_process'); // Since windowsHide isn't really observable, this test relies on monkey // patching spawn() and spawnSync() to verify that the flag is being passed @@ -15,12 +16,12 @@ const options = { windowsHide: true }; test('spawnSync() passes windowsHide correctly', (t) => { const spy = t.mock.method(internalCp, 'spawnSync'); - const child = cp.spawnSync(cmd, args, options); - assert.strictEqual(child.status, 0); - assert.strictEqual(child.signal, null); - assert.strictEqual(child.stdout.toString().trim(), '42'); - assert.strictEqual(child.stderr.toString().trim(), ''); + spawnSyncAndAssert(cmd, args, options, { + stdout: '42', + stderr: '', + trim: true + }); assert.strictEqual(spy.mock.calls.length, 1); assert.strictEqual(spy.mock.calls[0].arguments[0].windowsHide, true); }); diff --git a/test/parallel/test-constants.js b/test/parallel/test-constants.js index 51023b56d4dc..6ae205ca24bb 100644 --- a/test/parallel/test-constants.js +++ b/test/parallel/test-constants.js @@ -14,7 +14,8 @@ assert.ok(binding.os.errno); assert.ok(binding.fs); assert.ok(binding.crypto); -['os', 'fs', 'crypto'].forEach((l) => { +const moduleNames = ['os', 'fs', 'crypto']; +for (const l of moduleNames) { for (const k of Object.keys(binding[l])) { if (typeof binding[l][k] === 'object') { // errno and signals for (const j of Object.keys(binding[l][k])) { @@ -25,6 +26,6 @@ assert.ok(binding.crypto); assert.strictEqual(binding[l][k], constants[k]); } } -}); +} assert.ok(Object.isFrozen(constants)); diff --git a/test/parallel/test-crypto-authenticated.js b/test/parallel/test-crypto-authenticated.js index 2a4e2a1520a3..082e86a669b0 100644 --- a/test/parallel/test-crypto-authenticated.js +++ b/test/parallel/test-crypto-authenticated.js @@ -633,14 +633,29 @@ for (const test of TEST_CASES) { const iv = Buffer.alloc(12); const opts = { authTagLength: 10 }; + const control = crypto.createCipheriv('aes-128-ccm', key, iv, opts); + control.update(Buffer.alloc(0)); + control.final(); + const expectedTag = control.getAuthTag(); + const cipher = crypto.createCipheriv('aes-128-ccm', key, iv, opts); - assert.throws(() => { - cipher.final(); - }, hasOpenSSL3 ? { - code: 'ERR_OSSL_TAG_NOT_SET' - } : { - message: /Unsupported state/ - }); + let output; + try { + output = cipher.final(); + } catch (err) { + // OpenSSL without https://github.com/openssl/openssl/pull/32427 + // cannot finalize an empty CCM message unless update() was called. + if (hasOpenSSL3) { + assert.strictEqual(err.code, 'ERR_OSSL_TAG_NOT_SET'); + } else { + assert.match(err.message, /Unsupported state/); + } + } + + if (output !== undefined) { + assert.deepStrictEqual(output, Buffer.alloc(0)); + assert.deepStrictEqual(cipher.getAuthTag(), expectedTag); + } } } diff --git a/test/parallel/test-crypto-dh-curves.js b/test/parallel/test-crypto-dh-curves.js index f14c58e7c200..c0d9f1b5c425 100644 --- a/test/parallel/test-crypto-dh-curves.js +++ b/test/parallel/test-crypto-dh-curves.js @@ -35,33 +35,33 @@ if (!process.features.openssl_is_boringssl) { assert.strictEqual( crypto.createDiffieHellman(notSafePrime, Buffer.from([2])).verifyError, DH_CHECK_P_NOT_SAFE_PRIME); - - const group = crypto.getDiffieHellman('modp14'); - const alice = crypto.createDiffieHellman( - group.getPrime(), group.getGenerator()); - alice.generateKeys(); - const groupPrime = BigInt(`0x${group.getPrime('hex')}`); - assert.throws( - () => alice.computeSecret(Buffer.from([1])), - { - code: 'ERR_CRYPTO_INVALID_KEYLEN', - message: 'Supplied key is too small' - }); - assert.throws( - () => alice.computeSecret(group.getPrime()), - { - code: 'ERR_CRYPTO_INVALID_KEYLEN', - message: 'Supplied key is too large' - }); - assert.throws( - () => alice.computeSecret( - Buffer.from((groupPrime - 1n).toString(16), 'hex')), - { - code: 'ERR_CRYPTO_INVALID_KEYLEN', - message: 'Supplied key is too large' - }); } +const group = crypto.getDiffieHellman('modp14'); +const alice = crypto.createDiffieHellman( + group.getPrime(), group.getGenerator()); +alice.generateKeys(); +const groupPrime = BigInt(`0x${group.getPrime('hex')}`); +assert.throws( + () => alice.computeSecret(Buffer.from([1])), + { + code: 'ERR_CRYPTO_INVALID_KEYLEN', + message: 'Supplied key is too small' + }); +assert.throws( + () => alice.computeSecret(group.getPrime()), + { + code: 'ERR_CRYPTO_INVALID_KEYLEN', + message: 'Supplied key is too large' + }); +assert.throws( + () => alice.computeSecret( + Buffer.from((groupPrime - 1n).toString(16), 'hex')), + { + code: 'ERR_CRYPTO_INVALID_KEYLEN', + message: 'Supplied key is too large' + }); + // Confirm DH_check() results are exposed for optional examination. const bad_dh = process.features.openssl_is_boringssl ? crypto.createDiffieHellman('abcd', 'hex', 0) : diff --git a/test/parallel/test-crypto-dh.js b/test/parallel/test-crypto-dh.js index 8a3dee5b0756..01a7f0f3ddd8 100644 --- a/test/parallel/test-crypto-dh.js +++ b/test/parallel/test-crypto-dh.js @@ -91,9 +91,7 @@ const { { assert.throws(() => { dh3.computeSecret(''); - }, { message: process.features.openssl_is_boringssl ? - 'Supplied key is invalid' : - 'Supplied key is too small' }); + }, { message: 'Supplied key is too small' }); } } diff --git a/test/parallel/test-crypto-fips.js b/test/parallel/test-crypto-fips.js index 04a95fa5fd37..8b2e1c9a3649 100644 --- a/test/parallel/test-crypto-fips.js +++ b/test/parallel/test-crypto-fips.js @@ -21,7 +21,14 @@ const FIPS_ERROR_STRING2 = 'Error [ERR_CRYPTO_FIPS_FORCED]: Cannot set FIPS mode, it was forced with ' + '--force-fips at startup.'; const FIPS_UNSUPPORTED_ERROR_STRING = 'fips mode not supported'; -const FIPS_ENABLE_ERROR_STRING = 'OpenSSL error when trying to enable FIPS:'; +const FIPS_ENABLE_ERROR_STRING = + hasOpenSSL3 ? + '--enable-fips requires an active OpenSSL provider named "fips"' : + 'OpenSSL error when trying to enable FIPS:'; +const FIPS_FORCE_ERROR_STRING = + hasOpenSSL3 ? + '--force-fips requires an active OpenSSL provider named "fips"' : + 'OpenSSL error when trying to enable FIPS:'; const CNF_FIPS_ON = fixtures.path('openssl_fips_enabled.cnf'); const CNF_FIPS_OFF = fixtures.path('openssl_fips_disabled.cnf'); @@ -75,7 +82,7 @@ testHelper( ['--enable-fips'], testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_ENABLE_ERROR_STRING, - 'process.versions', + 'require("crypto").getFips()', process.env); // --force-fips should raise an error if OpenSSL is not FIPS enabled. @@ -83,8 +90,8 @@ testHelper( testFipsCrypto() ? 'stdout' : 'stderr', ['--force-fips'], testFipsCrypto() ? kNoFailure : kGenericUserError, - testFipsCrypto() ? FIPS_ENABLED : FIPS_ENABLE_ERROR_STRING, - 'process.versions', + testFipsCrypto() ? FIPS_ENABLED : FIPS_FORCE_ERROR_STRING, + 'require("crypto").getFips()', process.env); // By default FIPS should be off in both FIPS and non-FIPS builds @@ -98,6 +105,24 @@ if (!sharedOpenSSL()) { FIPS_DISABLED, 'require("crypto").getFips()', { ...process.env, 'OPENSSL_CONF': ' ' }); + + if (hasOpenSSL3) { + // Disabling FIPS mode should not throw after OpenSSL updates the default + // property query. + testHelper( + 'stdout', + [], + kNoFailure, + FIPS_DISABLED, + '(() => {' + + 'const crypto = require("crypto");' + + 'crypto.setFips(true);' + + 'require("assert").strictEqual(crypto.getFips(), 1);' + + 'crypto.setFips(false);' + + 'return crypto.getFips();' + + '})()', + { ...process.env, 'OPENSSL_CONF': ' ' }); + } } // Toggling fips with setFips should not be allowed from a worker thread diff --git a/test/parallel/test-crypto-key-store-pkcs11.js b/test/parallel/test-crypto-key-store-pkcs11.js new file mode 100644 index 000000000000..8c344686a426 --- /dev/null +++ b/test/parallel/test-crypto-key-store-pkcs11.js @@ -0,0 +1,581 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const { hasOpenSSL } = require('../common/crypto'); +if (!hasOpenSSL(3, 0)) + common.skip('requires OpenSSL 3.x'); + +// The PKCS#11 token, the OpenSSL configuration that activates a provider for +// it, and the PIN that unlocks it are all provided by the environment. +const kOpenSSLConfig = process.env.NODE_TEST_PKCS11_OPENSSL_CONF; +const kPin = process.env.NODE_TEST_PKCS11_PIN; +if (!kOpenSSLConfig || !kPin) + common.skip('missing a PKCS#11 provider test fixture'); + +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); +const { spawnSync } = require('child_process'); +const { + constants: { + RSA_PKCS1_PSS_PADDING, + }, + createPublicKey, + createPrivateKey, + createSign, + createVerify, + diffieHellman, + generateKeyPairSync, + sign, + verify, +} = require('crypto'); +const tmpdir = require('../common/tmpdir'); +const { spawnSyncAndExitWithoutError } = require('../common/child_process'); + +const { subtle } = globalThis.crypto; +const kData = Buffer.from( + Array.from({ length: 256 }, (_, i) => (i * 17 + 43) & 0xff)); +const kProperties = 'provider=pkcs11'; +const kExpectedPrivateExportFailure = + /Failed to encode private key|Failed to export JWK|Failed to export RSA private key|Failed to export EC .* key|Failed to get raw .* key|keymgmt export failure|not exportable|operation not supported|not supported|incompatible/i; + +// A SoftHSM fixture can provide a directory holding the token and its +// configuration. SoftHSM opens its token read-write, so run from a writable +// copy of that directory; the configuration names the token relative to the +// working directory. A real HSM sets no directory and is used as it stands. +function softhsmOptions() { + const source = process.env.NODE_TEST_PKCS11_SOFTHSM_DIR; + if (!source) return {}; + + tmpdir.refresh(); + const cwd = tmpdir.resolve('softhsm'); + fs.cpSync(source, cwd, { recursive: true }); + fs.chmodSync(cwd, 0o700); + for (const entry of fs.readdirSync(cwd, { recursive: true })) { + fs.chmodSync(path.join(cwd, entry), 0o700); + } + + return { cwd, env: { SOFTHSM2_CONF: path.join(cwd, 'softhsm2.conf') } }; +} + +function runInChild() { + const { cwd, env } = softhsmOptions(); + spawnSyncAndExitWithoutError(process.execPath, [ + `--openssl-config=${kOpenSSLConfig}`, + __filename, + ], { + cwd, + env: { ...process.env, ...env, NODE_TEST_PKCS11_CHILD: '1' }, + stdio: 'inherit', + }); +} + +function privateKeyUrl(label) { + return new URL(`pkcs11:object=${label};type=private`); +} + +function loadPrivateKey(label) { + return createPrivateKey({ + key: privateKeyUrl(label), + passphrase: kPin, + properties: kProperties, + }); +} + +function assertKeyDetails(key, type, asymmetricKeyType) { + assert.strictEqual(key.type, type); + assert.strictEqual(key.asymmetricKeyType, asymmetricKeyType); + + switch (asymmetricKeyType) { + case 'rsa': + assert.strictEqual(key.asymmetricKeyDetails.modulusLength, 2048); + assert.strictEqual(key.asymmetricKeyDetails.publicExponent, 65537n); + break; + case 'ec': + assert.strictEqual(key.asymmetricKeyDetails.namedCurve, 'prime256v1'); + break; + case 'ed25519': + case 'ed448': + assert.deepStrictEqual(key.asymmetricKeyDetails, {}); + break; + default: + assert.fail(`unexpected asymmetric key type ${asymmetricKeyType}`); + } +} + +function assertDerivedPublicKey(privateKey, asymmetricKeyType) { + const publicKey = createPublicKey(privateKey); + assertKeyDetails(publicKey, 'public', asymmetricKeyType); + return publicKey; +} + +function assertPublicExports(publicKey) { + const spkiPem = publicKey.export({ format: 'pem', type: 'spki' }); + assert.strictEqual( + spkiPem.split('\n')[0], + '-----BEGIN PUBLIC KEY-----'); + + const spkiDer = publicKey.export({ format: 'der', type: 'spki' }); + assert(Buffer.isBuffer(spkiDer)); + assert(spkiDer.byteLength > 0); + + // The PEM must carry the same SubjectPublicKeyInfo the DER export produces. + // Encoding a provider-backed key through OpenSSL's PEM_write_bio_PUBKEY() + // yields a PKCS#1 body for RSA, which the label alone does not catch. + const pemBody = Buffer.from( + spkiPem.split('\n').filter((line) => !line.startsWith('---')).join(''), + 'base64'); + assert.deepStrictEqual(pemBody, spkiDer); +} + +function assertPrivateExportsRejected(privateKey, asymmetricKeyType) { + const specs = [ + { format: 'pem', type: 'pkcs8' }, + { format: 'der', type: 'pkcs8' }, + { format: 'jwk' }, + ]; + + switch (asymmetricKeyType) { + case 'rsa': + specs.push( + { format: 'pem', type: 'pkcs1' }, + { format: 'der', type: 'pkcs1' }); + break; + case 'ec': + specs.push( + { format: 'pem', type: 'sec1' }, + { format: 'der', type: 'sec1' }, + { format: 'raw-private' }); + break; + default: + specs.push({ format: 'raw-private' }); + } + + for (const options of specs) { + assert.throws(() => { + privateKey.export(options); + }, { + message: kExpectedPrivateExportFailure, + }); + } +} + +function assertOneShotSignVerify(digest, data, privateKey, options = {}) { + const publicKey = createPublicKey(privateKey); + const signKey = { key: privateKey, ...options }; + const verifyPublicKey = { key: publicKey, ...options }; + const verifyPrivateKey = { key: privateKey, ...options }; + + const signature = sign(digest, data, signKey); + assert(signature.byteLength > 0); + assert.strictEqual(verify(digest, data, verifyPublicKey, signature), true); + assert.strictEqual(verify(digest, data, verifyPrivateKey, signature), true); + + return signature; +} + +function assertStreamingSignOneShotVerify(digest, data, privateKey) { + const publicKey = createPublicKey(privateKey); + const signature = createSign(digest).update(data).sign(privateKey); + assert(signature.byteLength > 0); + assert.strictEqual(verify(digest, data, publicKey, signature), true); + assert.strictEqual(verify(digest, data, privateKey, signature), true); + + assert.strictEqual( + createVerify(digest).update(data).verify(publicKey, signature), + true); + assert.strictEqual( + createVerify(digest).update(data).verify(privateKey, signature), + true); +} + +// The one-shot sign and verify callbacks run the operation on the threadpool +// rather than on the main thread. PKCS#11 sessions are shared process-wide, so +// exercise that path explicitly instead of only the synchronous one. +async function assertAsyncSignVerify(digest, data, privateKey) { + const publicKey = createPublicKey(privateKey); + + const signature = await new Promise((resolve, reject) => { + sign(digest, data, privateKey, (err, sig) => { + if (err) reject(err); + else resolve(sig); + }); + }); + assert(signature.byteLength > 0); + + for (const key of [publicKey, privateKey]) { + assert.strictEqual(await new Promise((resolve, reject) => { + verify(digest, data, key, signature, (err, result) => { + if (err) reject(err); + else resolve(result); + }); + }), true); + } +} + +// A store-backed key and a second load of the same URI are the same key. +function assertKeyObjectEquality(privateKey, label) { + assert.strictEqual(privateKey.equals(loadPrivateKey(label)), true); + assert.strictEqual(privateKey.equals(loadPrivateKey('node-ec')), + label === 'node-ec'); +} + +function assertEcdh(privateKey) { + const peer = generateKeyPairSync('ec', { namedCurve: 'prime256v1' }); + + // The peer public key has to reach OpenSSL through the SPKI decoder, which + // is what happens in practice because a peer key arrives over the wire. A + // public KeyObject that the default provider produced directly, including + // createPublicKey() of this very key, is rejected by the PKCS#11 provider + // with CKR_ARGUMENTS_BAD even though it is byte-for-byte the same key. + const importSpki = (key) => createPublicKey({ + key: key.export({ format: 'der', type: 'spki' }), + format: 'der', + type: 'spki', + }); + + const publicKey = createPublicKey(privateKey); + const ours = diffieHellman({ + privateKey, + publicKey: importSpki(peer.publicKey), + }); + const theirs = diffieHellman({ + privateKey: peer.privateKey, + publicKey: importSpki(publicKey), + }); + + assert(ours.byteLength > 0); + assert.deepStrictEqual(ours, theirs); +} + +async function assertWebCryptoSignVerify( + privateKey, + publicKey, + algorithm, + privateUsages, + publicUsages, + signAlgorithm = algorithm.name, +) { + const privateCryptoKey = privateKey.toCryptoKey( + algorithm, + false, + privateUsages); + assert.strictEqual(privateCryptoKey.type, 'private'); + assert.strictEqual(privateCryptoKey.extractable, false); + assert.deepStrictEqual(privateCryptoKey.usages, privateUsages); + + await assert.rejects( + subtle.exportKey('pkcs8', privateCryptoKey), + { + name: 'InvalidAccessError', + message: /not extractable/i, + }); + + const publicCryptoKey = publicKey.toCryptoKey( + algorithm, + true, + publicUsages); + assert.strictEqual(publicCryptoKey.type, 'public'); + assert.strictEqual(publicCryptoKey.extractable, true); + assert.deepStrictEqual(publicCryptoKey.usages, publicUsages); + + const signature = await subtle.sign( + signAlgorithm, + privateCryptoKey, + kData); + assert(signature instanceof ArrayBuffer); + assert(signature.byteLength > 0); + assert.strictEqual( + await subtle.verify( + signAlgorithm, + publicCryptoKey, + signature, + kData), + true); + + try { + const exportedPublicKey = await subtle.exportKey('spki', publicCryptoKey); + assert(exportedPublicKey instanceof ArrayBuffer); + assert(exportedPublicKey.byteLength > 0); + } catch (err) { + assert.strictEqual(err.name, 'OperationError'); + assert.match(err.message, /operation-specific reason|not supported/i); + } +} + +async function assertPrivateCryptoKeyExportsRejected( + privateKey, + algorithm, + privateUsages, +) { + const privateCryptoKey = privateKey.toCryptoKey( + algorithm, + true, + privateUsages); + assert.strictEqual(privateCryptoKey.type, 'private'); + assert.strictEqual(privateCryptoKey.extractable, true); + assert.deepStrictEqual(privateCryptoKey.usages, privateUsages); + + for (const format of ['pkcs8', 'jwk']) { + await assert.rejects( + subtle.exportKey(format, privateCryptoKey), + (err) => { + assert(err.name === 'OperationError' || + err.code === 'ERR_CRYPTO_OPERATION_FAILED'); + assert.match(err.cause?.message ?? err.message, + kExpectedPrivateExportFailure); + return true; + }); + } +} + +function assertStoreOptions() { + assert.strictEqual( + createPrivateKey({ + key: privateKeyUrl('node-rsa'), + passphrase: kPin, + }).asymmetricKeyType, + 'rsa'); + + assert.strictEqual( + createPrivateKey({ + key: privateKeyUrl('node-rsa'), + passphrase: kPin, + properties: kProperties, + }).asymmetricKeyType, + 'rsa'); +} + +function assertChild(args, expectedStatus, stderrPattern, options = {}) { + const child = spawnSync(process.execPath, args, { + env: process.env, + encoding: 'utf8', + ...options, + }); + assert.strictEqual(child.signal, null); + assert.strictEqual(child.status, expectedStatus, child.stderr || child.stdout); + if (stderrPattern) assert.match(child.stderr, stderrPattern); +} + +function assertStoreLoadFailure(code, stderrPattern, options) { + assertChild([ + `--openssl-config=${kOpenSSLConfig}`, + '-e', + code, + ], 1, stderrPattern, options); +} + +function assertPassphraseHandling() { + // When no passphrase is supplied the provider falls back to prompting for a + // PIN through OpenSSL's default UI, which opens the terminal directly + // (/dev/tty, or "con" on Windows) rather than reading stdin. Detaching gives + // the child no controlling terminal, so the prompt cannot block. The result + // is the same either way, because Node has already recorded that no + // passphrase was available. + assertStoreLoadFailure(` + require('crypto').createPrivateKey({ + key: new URL('pkcs11:object=node-rsa;type=private'), + properties: ${JSON.stringify(kProperties)}, + }); + `, /ERR_MISSING_PASSPHRASE/, { detached: true }); + + assertStoreLoadFailure(` + require('crypto').createPrivateKey({ + key: new URL('pkcs11:object=node-rsa;type=private'), + passphrase: 'bad', + properties: ${JSON.stringify(kProperties)}, + }); + `, /Failed to load private key through an OpenSSL STORE loader/); +} + +function assertBadProperties() { + assertStoreLoadFailure(` + require('crypto').createPrivateKey({ + key: new URL('pkcs11:object=node-rsa;type=private'), + passphrase: ${JSON.stringify(kPin)}, + properties: 'provider=default', + }); + `, /Failed to load private key through an OpenSSL STORE loader|No such file or directory|unsupported/i); +} + +function assertPermissionModel() { + const code = ` + require('crypto').createPrivateKey({ + key: new URL('pkcs11:object=node-rsa;type=private'), + passphrase: ${JSON.stringify(kPin)}, + properties: ${JSON.stringify(kProperties)}, + }); + `; + + assertChild([ + `--openssl-config=${kOpenSSLConfig}`, + '--permission', + '--allow-fs-read=*', + '-e', + code, + ], 1, /ERR_ACCESS_DENIED/); + + assertChild([ + `--openssl-config=${kOpenSSLConfig}`, + '--permission', + '--allow-openssl-store', + '--allow-fs-read=*', + '-e', + code, + ], 0); +} + +function assertInlineSignWithStoreUrl(privateKey) { + const publicKey = createPublicKey(privateKey); + const signature = sign('sha256', kData, { + key: privateKeyUrl('node-rsa'), + passphrase: kPin, + properties: kProperties, + }); + assert(signature.byteLength > 0); + assert.strictEqual(verify('sha256', kData, publicKey, signature), true); +} + +async function testRsa() { + const privateKey = loadPrivateKey('node-rsa'); + assertKeyDetails(privateKey, 'private', 'rsa'); + + const publicKey = assertDerivedPublicKey(privateKey, 'rsa'); + assertOneShotSignVerify('sha256', kData, privateKey); + assertOneShotSignVerify('sha256', kData, privateKey, { + padding: RSA_PKCS1_PSS_PADDING, + saltLength: 32, + }); + assertStreamingSignOneShotVerify('sha256', kData, privateKey); + await assertAsyncSignVerify('sha256', kData, privateKey); + assertKeyObjectEquality(privateKey, 'node-rsa'); + assertInlineSignWithStoreUrl(privateKey); + assertPublicExports(publicKey); + assertPrivateExportsRejected(privateKey, 'rsa'); + await assertPrivateCryptoKeyExportsRejected( + privateKey, + { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' }, + ['sign']); + + await assertWebCryptoSignVerify( + privateKey, + publicKey, + { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' }, + ['sign'], + ['verify']); + + await assertWebCryptoSignVerify( + privateKey, + publicKey, + { name: 'RSA-PSS', hash: 'SHA-256' }, + ['sign'], + ['verify'], + { name: 'RSA-PSS', saltLength: 32 }); +} + +async function testEc() { + const privateKey = loadPrivateKey('node-ec'); + assertKeyDetails(privateKey, 'private', 'ec'); + + const publicKey = assertDerivedPublicKey(privateKey, 'ec'); + assertOneShotSignVerify('sha256', kData, privateKey); + assertOneShotSignVerify('sha256', kData, privateKey, { + dsaEncoding: 'ieee-p1363', + }); + assertStreamingSignOneShotVerify('sha256', kData, privateKey); + await assertAsyncSignVerify('sha256', kData, privateKey); + assertKeyObjectEquality(privateKey, 'node-ec'); + + assertPublicExports(publicKey); + assertPrivateExportsRejected(privateKey, 'ec'); + await assertPrivateCryptoKeyExportsRejected( + privateKey, + { name: 'ECDSA', namedCurve: 'P-256' }, + ['sign']); + await assertWebCryptoSignVerify( + privateKey, + publicKey, + { name: 'ECDSA', namedCurve: 'P-256' }, + ['sign'], + ['verify'], + { name: 'ECDSA', hash: 'SHA-256' }); +} + +async function testEd25519() { + const privateKey = loadPrivateKey('node-ed25519'); + assertKeyDetails(privateKey, 'private', 'ed25519'); + + const publicKey = assertDerivedPublicKey(privateKey, 'ed25519'); + assertOneShotSignVerify(null, kData, privateKey); + await assertAsyncSignVerify(null, kData, privateKey); + assertPublicExports(publicKey); + assertPrivateExportsRejected(privateKey, 'ed25519'); + await assertPrivateCryptoKeyExportsRejected( + privateKey, + { name: 'Ed25519' }, + ['sign']); + + await assertWebCryptoSignVerify( + privateKey, + publicKey, + { name: 'Ed25519' }, + ['sign'], + ['verify']); +} + +function testEcDiffieHellman() { + const privateKey = loadPrivateKey('node-ecdh'); + assertKeyDetails(privateKey, 'private', 'ec'); + + const publicKey = assertDerivedPublicKey(privateKey, 'ec'); + assertPublicExports(publicKey); + assertPrivateExportsRejected(privateKey, 'ec'); + assertEcdh(privateKey); +} + +async function testEd448() { + const privateKey = loadPrivateKey('node-ed448'); + assertKeyDetails(privateKey, 'private', 'ed448'); + + const publicKey = assertDerivedPublicKey(privateKey, 'ed448'); + assertOneShotSignVerify(null, kData, privateKey); + await assertAsyncSignVerify(null, kData, privateKey); + assertPublicExports(publicKey); + assertPrivateExportsRejected(privateKey, 'ed448'); + await assertPrivateCryptoKeyExportsRejected( + privateKey, + { name: 'Ed448' }, + ['sign']); + + await assertWebCryptoSignVerify( + privateKey, + publicKey, + { name: 'Ed448' }, + ['sign'], + ['verify']); +} + +async function runTest() { + assertStoreOptions(); + assertPassphraseHandling(); + assertBadProperties(); + assertPermissionModel(); + + await testRsa(); + await testEc(); + testEcDiffieHellman(); + await testEd25519(); + await testEd448(); +} + +if (process.env.NODE_TEST_PKCS11_CHILD === '1') { + runTest().then(common.mustCall()).catch((err) => { + process.nextTick(() => { + throw err; + }); + }); +} else { + runInChild(); +} diff --git a/test/parallel/test-crypto-key-store.js b/test/parallel/test-crypto-key-store.js new file mode 100644 index 000000000000..b6f012416673 --- /dev/null +++ b/test/parallel/test-crypto-key-store.js @@ -0,0 +1,304 @@ +'use strict'; +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const { hasOpenSSL } = require('../common/crypto'); +if (!hasOpenSSL(3)) + common.skip('requires OpenSSL 3.x'); + +// Verifies that crypto.createPrivateKey() can pass a WHATWG URL (here a file: +// URI) to an OpenSSL STORE loader, and that the resulting KeyObject works for +// signing and verification. + +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); +const { pathToFileURL } = require('url'); +const { + createPublicKey, + createPrivateKey, + createVerify, + decapsulate, + diffieHellman, + encapsulate, + generateKeyPairSync, + privateDecrypt, + privateEncrypt, + publicDecrypt, + publicEncrypt, + sign, + verify, +} = require('crypto'); +const tmpdir = require('../common/tmpdir'); +tmpdir.refresh(); + +const data = Buffer.from('hello store'); + +{ + const { privateKey, publicKey } = generateKeyPairSync('ed25519'); + const file = path.join(tmpdir.path, 'priv.pem'); + fs.writeFileSync(file, privateKey.export({ format: 'pem', type: 'pkcs8' })); + const url = pathToFileURL(file); + + const pk = createPrivateKey(url); + assert.strictEqual(pk.type, 'private'); + assert.strictEqual(pk.asymmetricKeyType, 'ed25519'); + + const sig = sign(null, data, pk); + assert.strictEqual(verify(null, data, publicKey, sig), true); + + const pkWithProperties = createPrivateKey({ key: url, properties: '' }); + assert.strictEqual(pkWithProperties.type, 'private'); + assert.strictEqual(pkWithProperties.asymmetricKeyType, 'ed25519'); + assert.strictEqual( + verify(null, data, publicKey, sign(null, data, pkWithProperties)), + true); + + // Passing the URL inline to sign() behaves like createPrivateKey(). + assert.strictEqual(verify(null, data, publicKey, sign(null, data, url)), true); + + assert.throws(() => createPrivateKey({ key: url, properties: 1 }), { + code: 'ERR_INVALID_ARG_TYPE', + }); +} + +{ + const { privateKey, publicKey } = generateKeyPairSync('rsa', { + modulusLength: 2048, + }); + const file = path.join(tmpdir.path, 'rsa.pem'); + fs.writeFileSync(file, privateKey.export({ format: 'pem', type: 'pkcs8' })); + const url = pathToFileURL(file); + const plaintext = Buffer.from('hello rsa store'); + + const ciphertext = publicEncrypt(publicKey, plaintext); + assert.deepStrictEqual(privateDecrypt(url, ciphertext), plaintext); + assert.deepStrictEqual(privateDecrypt({ key: url }, ciphertext), plaintext); + + const encrypted = privateEncrypt(url, plaintext); + assert.deepStrictEqual(publicDecrypt(publicKey, encrypted), plaintext); + + const encryptedFromObject = privateEncrypt({ key: url }, plaintext); + assert.deepStrictEqual(publicDecrypt(publicKey, encryptedFromObject), + plaintext); +} + +{ + const alice = generateKeyPairSync('x25519'); + const bob = generateKeyPairSync('x25519'); + const file = path.join(tmpdir.path, 'x25519.pem'); + fs.writeFileSync(file, alice.privateKey.export({ + format: 'pem', + type: 'pkcs8', + })); + const url = pathToFileURL(file); + + const expected = diffieHellman({ + privateKey: alice.privateKey, + publicKey: bob.publicKey, + }); + assert.deepStrictEqual( + diffieHellman({ privateKey: url, publicKey: bob.publicKey }), + expected); + + if (hasOpenSSL(3, 2)) { + const { sharedKey, ciphertext } = encapsulate(alice.publicKey); + assert.deepStrictEqual(decapsulate(url, ciphertext), sharedKey); + } +} + +{ + // Encrypted PKCS#8 with passphrase via { key: url, passphrase }. + const passphrase = 'correct-passphrase'; + const { privateKey, publicKey } = generateKeyPairSync('ed25519'); + const file = path.join(tmpdir.path, 'enc.pem'); + fs.writeFileSync(file, privateKey.export({ + format: 'pem', type: 'pkcs8', cipher: 'aes-256-cbc', passphrase, + })); + const url = pathToFileURL(file); + + const sig = sign(null, data, { key: url, passphrase: Buffer.from(passphrase) }); + assert.strictEqual(verify(null, data, publicKey, sig), true); + + assert.throws(() => createPrivateKey(url), { + code: 'ERR_MISSING_PASSPHRASE', + }); + + assert.throws(() => createPrivateKey({ key: url, passphrase: 'wrong-passphrase' }), + common.expectsError({ + name: 'Error', + code: /^ERR_OSSL_/, + })); +} + +{ + // A URL is only accepted in private-key contexts. + const url = pathToFileURL(path.join(tmpdir.path, 'priv.pem')); + assert.throws(() => createPublicKey(url), { + code: 'ERR_INVALID_ARG_TYPE', + }); + assert.throws(() => createPublicKey({ key: url }), { + code: 'ERR_INVALID_ARG_TYPE', + }); + assert.throws(() => publicEncrypt(url, data), { + code: 'ERR_INVALID_ARG_TYPE', + }); + assert.throws(() => publicEncrypt({ key: url }, data), { + code: 'ERR_INVALID_ARG_TYPE', + }); + assert.throws(() => publicDecrypt(url, Buffer.alloc(0)), { + code: 'ERR_INVALID_ARG_TYPE', + }); + assert.throws(() => verify(null, data, url, Buffer.alloc(0)), { + code: 'ERR_INVALID_ARG_TYPE', + }); + assert.throws(() => verify(null, data, { key: url }, Buffer.alloc(0)), { + code: 'ERR_INVALID_ARG_TYPE', + }); + const verifier = createVerify('sha256'); + verifier.update(data); + assert.throws(() => verifier.verify(url, Buffer.alloc(0)), { + code: 'ERR_INVALID_ARG_TYPE', + }); + assert.throws(() => encapsulate(url), { + code: 'ERR_INVALID_ARG_TYPE', + }); + assert.throws(() => encapsulate({ key: url }), { + code: 'ERR_INVALID_ARG_TYPE', + }); + assert.throws(() => diffieHellman({ + privateKey: createPrivateKey(url), + publicKey: url, + }), { + code: 'ERR_INVALID_ARG_TYPE', + }); + + assert.throws(() => createPrivateKey(1), { + code: 'ERR_INVALID_ARG_TYPE', + message: /URL/, + }); +} + +{ + // A readable URI that holds no private key is distinguishable from a URI + // that could not be opened at all. + const file = path.join(tmpdir.path, 'nope.pem'); + fs.writeFileSync(file, 'not a key'); + assert.throws(() => createPrivateKey(pathToFileURL(file)), { + code: 'ERR_CRYPTO_OPERATION_FAILED', + }); + + // OpenSSL has no reason string for system library errors, so error.code + // cannot be derived for these. Which entry becomes the message is not + // portable either: some builds leave a generic STORE `unsupported` on top of + // the error the loader itself raised. The reason is reported either way. + assert.throws( + () => createPrivateKey(pathToFileURL(path.join(tmpdir.path, 'missing.pem'))), + (err) => { + assert.match([err.message, ...err.opensslErrorStack ?? []].join('\n'), + /No such file or directory/); + return true; + }); +} + +{ + // Failures report the loader that actually handled the URI, not the `file` + // loader that OpenSSL always probes first for URIs without an authority. + assert.throws(() => createPrivateKey(new URL('pkcs11:object=nope')), { + code: 'ERR_OSSL_OSSL_STORE_UNSUPPORTED', + }); +} + +{ + // Only a genuine URL selects the STORE loader. A plain object that merely + // exposes `href` and `protocol` must not be treated as one, otherwise an + // attacker-supplied JWK could redirect the load to a URI of their choosing. + const file = path.join(tmpdir.path, 'priv.pem'); + const spoofed = { + kty: 'EC', + crv: 'P-256', + x: 'a', + y: 'b', + d: 'c', + href: pathToFileURL(file).href, + protocol: 'file:', + }; + assert.throws(() => createPrivateKey({ key: spoofed, format: 'jwk' }), { + code: 'ERR_CRYPTO_INVALID_JWK', + }); + assert.throws(() => createPrivateKey(spoofed), { + code: 'ERR_INVALID_ARG_TYPE', + }); + assert.throws( + () => sign(null, data, { key: spoofed, format: 'jwk' }), + { code: 'ERR_CRYPTO_INVALID_JWK' }); +} + +{ + // Read the URI from the URL's private state. Public accessors on a branded + // subclass must not redirect a previously created URL to a different key. + const trustedHref = pathToFileURL( + path.join(tmpdir.path, 'priv.pem')).href; + const redirectHref = pathToFileURL( + path.join(tmpdir.path, 'rsa.pem')).href; + class RedirectingURL extends URL { + get href() { return redirectHref; } + } + const subclassURL = new RedirectingURL(trustedHref); + assert.strictEqual( + URL.prototype.toString.call(subclassURL), trustedHref); + assert.strictEqual( + createPrivateKey(subclassURL).asymmetricKeyType, 'ed25519'); + + // The same applies when the accessor is replaced on URL.prototype. + const prototypeURL = new URL(trustedHref); + const hrefDescriptor = Object.getOwnPropertyDescriptor(URL.prototype, 'href'); + try { + Object.defineProperty(URL.prototype, 'href', { + ...hrefDescriptor, + get() { return redirectHref; }, + }); + assert.strictEqual( + URL.prototype.toString.call(prototypeURL), trustedHref); + assert.strictEqual( + createPrivateKey(prototypeURL).asymmetricKeyType, 'ed25519'); + } finally { + Object.defineProperty(URL.prototype, 'href', hrefDescriptor); + } + + // Replacing `protocol` must not turn an opaque STORE URI into a file path. + const filePathname = pathToFileURL( + path.join(tmpdir.path, 'priv.pem')).pathname; + const opaqueURL = new URL(`pkcs11:${filePathname}`); + const protocolDescriptor = Object.getOwnPropertyDescriptor( + URL.prototype, 'protocol'); + try { + Object.defineProperty(URL.prototype, 'protocol', { + ...protocolDescriptor, + get() { return 'file:'; }, + }); + assert.throws(() => createPrivateKey(opaqueURL), { + code: 'ERR_OSSL_OSSL_STORE_UNSUPPORTED', + }); + } finally { + Object.defineProperty(URL.prototype, 'protocol', protocolDescriptor); + } +} + +{ + // The URI is handed to OpenSSL as a NUL-terminated C string, so an embedded + // NUL must be rejected rather than silently truncating the path. + const file = path.join(tmpdir.path, 'priv.pem'); + assert.throws( + () => createPrivateKey(new URL(`${pathToFileURL(file).href}%00.txt`)), { + code: 'ERR_INVALID_ARG_VALUE', + }); + + // Same for the property query. + assert.throws(() => createPrivateKey({ + key: pathToFileURL(file), + properties: `provider=def${'\u0000'}ault`, + }), { + code: 'ERR_INVALID_ARG_VALUE', + }); +} diff --git a/test/parallel/test-crypto-keygen.js b/test/parallel/test-crypto-keygen.js index 206d6f7a84b5..111d3dcbfd48 100644 --- a/test/parallel/test-crypto-keygen.js +++ b/test/parallel/test-crypto-keygen.js @@ -376,25 +376,20 @@ const isBoringSSL = process.features.openssl_is_boringssl; } // Test invalid exponents. (caught by OpenSSL) + let invalidExponentError = /bad e value/; + if (isBoringSSL) { + invalidExponentError = /BAD_E_VALUE/; + } else if (hasOpenSSL3) { + invalidExponentError = /exponent/; + } for (const publicExponent of [1, 1 + 0x10001]) { - if (isBoringSSL) { - assert.throws(() => generateKeyPair('rsa', { - modulusLength: 4096, - publicExponent - }, common.mustNotCall()), { - name: 'RangeError', - code: 'ERR_OUT_OF_RANGE', - message: 'publicExponent is invalid', - }); - } else { - generateKeyPair('rsa', { - modulusLength: 4096, - publicExponent - }, common.mustCall((err) => { - assert.strictEqual(err.name, 'Error'); - assert.match(err.message, hasOpenSSL3 ? /exponent/ : /bad e value/); - })); - } + generateKeyPair('rsa', { + modulusLength: 4096, + publicExponent + }, common.mustCall((err) => { + assert.strictEqual(err.name, 'Error'); + assert.match(err.message, invalidExponentError); + })); } } diff --git a/test/parallel/test-crypto-no-algorithm.js b/test/parallel/test-crypto-no-algorithm.js index 76063a04227e..db781c66a6d6 100644 --- a/test/parallel/test-crypto-no-algorithm.js +++ b/test/parallel/test-crypto-no-algorithm.js @@ -30,7 +30,7 @@ if (isMainThread) { const derivations = [ ['HKDF', () => crypto.hkdfSync('sha256', Buffer.alloc(32), Buffer.alloc(8), Buffer.alloc(0), 32)], - ['PBKDF2', () => crypto.pbkdf2Sync('secret', Buffer.alloc(16), 1000, 32, + ['PBKDF2', () => crypto.pbkdf2Sync('passphrase', Buffer.alloc(16), 1000, 32, 'sha256')], ]; for (const { 0: name, 1: derive } of derivations) { diff --git a/test/parallel/test-crypto-random.js b/test/parallel/test-crypto-random.js index ceaa859a0e03..88b6fcba84d7 100644 --- a/test/parallel/test-crypto-random.js +++ b/test/parallel/test-crypto-random.js @@ -218,6 +218,55 @@ common.expectWarning('DeprecationWarning', })); } +{ + const buf = new Uint16Array(10); + const before = Buffer.from(buf.buffer).toString('hex'); + crypto.randomFillSync(buf, 1, 8); + const after = Buffer.from(buf.buffer).toString('hex'); + assert.notStrictEqual(before, after); + assert.deepStrictEqual(before.slice(0, 4), after.slice(0, 4)); + assert.deepStrictEqual(before.slice(-4), after.slice(-4)); +} + +{ + const buf = new Uint32Array(10); + const before = Buffer.from(buf.buffer).toString('hex'); + crypto.randomFillSync(buf, 1, 8); + const after = Buffer.from(buf.buffer).toString('hex'); + assert.notStrictEqual(before, after); + assert.deepStrictEqual(before.slice(0, 8), after.slice(0, 8)); + assert.deepStrictEqual(before.slice(-8), after.slice(-8)); +} + +{ + const buf = new Uint16Array(10); + const before = Buffer.from(buf.buffer).toString('hex'); + crypto.randomFill(buf, 1, 8, common.mustSucceed((buf) => { + const after = Buffer.from(buf.buffer).toString('hex'); + assert.notStrictEqual(before, after); + assert.deepStrictEqual(before.slice(0, 4), after.slice(0, 4)); + assert.deepStrictEqual(before.slice(-4), after.slice(-4)); + })); +} + +{ + const buf = new Uint32Array(10); + const before = Buffer.from(buf.buffer).toString('hex'); + crypto.randomFill(buf, 1, 8, common.mustSucceed((buf) => { + const after = Buffer.from(buf.buffer).toString('hex'); + assert.notStrictEqual(before, after); + assert.deepStrictEqual(before.slice(0, 8), after.slice(0, 8)); + assert.deepStrictEqual(before.slice(-8), after.slice(-8)); + })); +} + +{ + // randomFill() with an offset and no size must not throw for types + // without a .length property, matching randomFillSync(). + crypto.randomFill(new ArrayBuffer(10), 2, common.mustSucceed()); + crypto.randomFill(new DataView(new ArrayBuffer(10)), 2, common.mustSucceed()); +} + { [ Buffer.alloc(10), diff --git a/test/parallel/test-crypto-sec-level.js b/test/parallel/test-crypto-sec-level.js index d7d2252be6c3..f2c0e3900624 100644 --- a/test/parallel/test-crypto-sec-level.js +++ b/test/parallel/test-crypto-sec-level.js @@ -15,4 +15,8 @@ const assert = require('assert'); // This test simply validates that we can get some value for the secLevel // when needed by tests. const secLevel = require('internal/crypto/util').getOpenSSLSecLevel(); -assert.ok(secLevel >= 0 && secLevel <= 5); +if (process.features.openssl_is_boringssl) { + assert.strictEqual(secLevel, 0); +} else { + assert.ok(secLevel >= 0 && secLevel <= 5); +} diff --git a/test/parallel/test-crypto-sign-verify.js b/test/parallel/test-crypto-sign-verify.js index 3dd5e8e83252..808c8d076a28 100644 --- a/test/parallel/test-crypto-sign-verify.js +++ b/test/parallel/test-crypto-sign-verify.js @@ -625,6 +625,41 @@ if (hasOpenSSL(3, 2)) { assert.throws(() => crypto.verify(null, data, 'test', input), errObj); }); +// Preserve the current behavior from https://github.com/nodejs/node/issues/53761: +// one-shot verify does not accept SM2 signatures produced by the streaming path. +if (hasOpenSSL(3) && crypto.getHashes().includes('sm3')) { + const data = Buffer.from('AABB'); + const privateKey = crypto.createPrivateKey(`-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgbjCNHopgvyGVfLaP +PamI9E9lf6jXT+xm1Pns1t/xQTihRANCAATV+I7HUGF2gC+miVl3JfjpoZaU2hrZ +QqHwKUNtIDE/uxxWNLBbYKaiLOWrbYA8skrWQWl3RkbXW4ZI28afRw9g +-----END PRIVATE KEY----- +`); + const publicKey = crypto.createPublicKey(`-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE1fiOx1BhdoAvpolZdyX46aGWlNoa +2UKh8ClDbSAxP7scVjSwW2Cmoizlq22APLJK1kFpd0ZG11uGSNvGn0cPYA== +-----END PUBLIC KEY-----`); + // Generate the signatures in-test so this checks API behavior rather than + // provider-version-specific SM2 signature fixtures. + const validOneShotSignature = crypto.sign('sm3', data, privateKey); + const streamingSign = crypto.createSign('sm3'); + streamingSign.update(data); + const streamingOnlySignature = streamingSign.sign(privateKey); + + assert.strictEqual( + crypto.verify('sm3', data, publicKey, validOneShotSignature), + true); + assert.strictEqual( + crypto.verify('sm3', data, publicKey, streamingOnlySignature), + false); + + const streamingVerify = crypto.createVerify('sm3'); + streamingVerify.update(data); + assert.strictEqual( + streamingVerify.verify(publicKey, streamingOnlySignature), + true); +} + { const data = Buffer.from('Hello world'); const keys = [['ec-key.pem', 64], ['dsa_private_1025.pem', 40]]; @@ -734,13 +769,9 @@ if (hasOpenSSL(3, 2)) { // RSA-PSS Sign test by verifying with 'openssl dgst -verify' -// Note: this particular test *must* be the last in this file as it will exit -// early if no openssl binary is found -{ - if (!opensslCli) { - common.skip('node compiled without OpenSSL CLI.'); - } - +if (!opensslCli) { + common.printSkipMessage('node compiled without OpenSSL CLI.'); +} else { const pubfile = fixtures.path('keys', 'rsa_public_2048.pem'); const privkey = fixtures.readKey('rsa_private_2048.pem'); diff --git a/test/parallel/test-debugger-no-inspect-brk.js b/test/parallel/test-debugger-no-inspect-brk.js new file mode 100644 index 000000000000..611d28fd9f3e --- /dev/null +++ b/test/parallel/test-debugger-no-inspect-brk.js @@ -0,0 +1,158 @@ +// Flags: --expose-internals + +// This tests that child --no-inspect and --no-inspect-brk options cannot leave +// the inspector setup disabled, while remaining valid as application args. +'use strict'; + +const common = require('../common'); +common.skipIfInspectorDisabled(); + +const assert = require('assert'); +const fixtures = require('../common/fixtures'); +const { + spawnSyncAndAssert, + spawnSyncAndExit, +} = require('../common/child_process'); +const { assertProbeJson } = require('../common/debugger-probe'); +const { launchChildProcess } = require('internal/debugger/inspect_helpers'); + +const cwd = fixtures.path('debugger'); +const probeUrl = fixtures.fileURL('debugger', 'probe.js').href; +const probeArgs = [ + '--probe', 'probe.js:12', + '--expr', 'finalValue', +]; +const incompatibleInspectBrk = + /--no-inspect-brk is incompatible with node inspect before the child script/; +const incompatibleInspect = + /--no-inspect is incompatible with node inspect before the child script/; + +function assertSuccessfulProbe(childArgs) { + spawnSyncAndAssert(process.execPath, [ + 'inspect', + '--json', + ...probeArgs, + '--', + ...childArgs, + ], { cwd }, { + stdout(output) { + assertProbeJson(output, { + v: 2, + probes: [{ + expr: 'finalValue', + target: { suffix: 'probe.js', line: 12 }, + }], + results: [{ + probe: 0, + event: 'hit', + hit: 1, + location: { url: probeUrl, line: 12, column: 1 }, + result: { type: 'number', value: 81, description: '81' }, + }, { + event: 'completed', + }], + }); + }, + trim: true, + }); +} + +for (const childOptions of [ + ['--require', 'assert', '--no-inspect-brk'], + ['--require=assert', '--no-inspect-brk'], + ['-r', 'assert', '--no_inspect_brk'], +]) { + spawnSyncAndExit(process.execPath, [ + 'inspect', + ...probeArgs, + '--', + ...childOptions, + 'probe.js', + ], { cwd }, { + signal: null, + status: 1, + stderr: incompatibleInspectBrk, + trim: true, + }); +} + +spawnSyncAndExit(process.execPath, [ + 'inspect', + ...probeArgs, + '--', + '--require', 'assert', + '--no-inspect', + 'probe.js', +], { cwd }, { + signal: null, + status: 1, + stderr: incompatibleInspect, + trim: true, +}); + +for (const { option, error } of [ + { option: '--no-inspect-brk', error: incompatibleInspectBrk }, + { option: '--no-inspect', error: incompatibleInspect }, +]) { + spawnSyncAndExit(process.execPath, [ + 'inspect', + option, + 'probe.js', + ], { cwd }, { + signal: null, + status: 1, + stderr: error, + trim: true, + }); + + assertSuccessfulProbe(['probe.js', option]); +} + +// Node options are last-write-wins. A later --inspect-brk restores both +// startup requirements. +assertSuccessfulProbe([ + '--no-inspect', + '--no-inspect-brk', + '--inspect-brk', + 'probe.js', +]); + +// ConfigReader rewrites these bare options to use the default path without +// consuming the following argument. +Promise.all([ + assert.rejects( + launchChildProcess([ + '--experimental-config-file', + '--no-inspect-brk', + 'probe.js', + ], '127.0.0.1', 0, () => {}), + incompatibleInspectBrk, + ), + assert.rejects( + launchChildProcess([ + '--experimental-default-config-file', + '--no-inspect-brk', + 'probe.js', + ], '127.0.0.1', 0, () => {}), + incompatibleInspectBrk, + ), + // These options imply --inspect, but do not restore --inspect-brk. + assert.rejects( + launchChildProcess([ + '--no-inspect', + '--inspect-wait', + '--no-inspect-brk', + 'probe.js', + ], '127.0.0.1', 0, () => {}), + incompatibleInspectBrk, + ), + assert.rejects( + launchChildProcess([ + '--no-inspect', + '--inspect-brk-node', + '--no-inspect-brk', + 'probe.js', + ], '127.0.0.1', 0, () => {}), + incompatibleInspectBrk, + ), +]).then(common.mustCall()); diff --git a/test/parallel/test-debugger-pid.js b/test/parallel/test-debugger-pid.js index 157939c05c73..6fcdac4d9d1d 100644 --- a/test/parallel/test-debugger-pid.js +++ b/test/parallel/test-debugger-pid.js @@ -18,7 +18,9 @@ interfacer.stderr.setEncoding('utf-8'); const onData = (data) => { data = (buffer + data).split('\n'); buffer = data.pop(); - data.forEach((line) => interfacer.emit('line', line)); + for (const line of data) { + interfacer.emit('line', line); + } }; interfacer.stdout.on('data', onData); interfacer.stderr.on('data', onData); diff --git a/test/parallel/test-debugger-probe-failure-hang-during-evaluate.js b/test/parallel/test-debugger-probe-failure-hang-during-evaluate.js index 82ff78ca6f78..705557285c6c 100644 --- a/test/parallel/test-debugger-probe-failure-hang-during-evaluate.js +++ b/test/parallel/test-debugger-probe-failure-hang-during-evaluate.js @@ -12,7 +12,7 @@ const { assertProbeJson } = require('../common/debugger-probe'); const cwd = fixtures.path('debugger'); const fixture = 'probe-inspector-close-two-probes.js'; const marker = 'probe-inspector-close-marker'; -const timeoutMs = common.platformTimeout(1000); +const timeoutMs = common.platformTimeout(3000); const probes = [ { expr: 'closeInspector()', target: { suffix: fixture, line: 10 } }, { expr: 'firstProbeLine', target: { suffix: fixture, line: 11 } }, diff --git a/test/parallel/test-debugger-probe-startup-disconnect.js b/test/parallel/test-debugger-probe-startup-disconnect.js new file mode 100644 index 000000000000..68c8432dc552 --- /dev/null +++ b/test/parallel/test-debugger-probe-startup-disconnect.js @@ -0,0 +1,56 @@ +// Flags: --expose-internals +// This tests that a disconnect while probe mode is waiting for target startup +// is reported as a structured probe failure instead of an internal error. +'use strict'; + +const common = require('../common'); +common.skipIfInspectorDisabled(); + +const assert = require('assert'); +const { EventEmitter } = require('events'); +const { assertProbeJson } = require('../common/debugger-probe'); +const { ProbeInspectorSession } = require('internal/debugger/inspect_probe'); + +const probe = { + expr: 'value', + target: { suffix: 'probe-target.js', line: 1 }, +}; +const client = new EventEmitter(); +client.connect = common.mustCall(); +client.callMethod = common.mustCall((method) => { + assert.strictEqual(method, 'NodeRuntime.enable'); + setImmediate(() => client.emit('close')); + return new Promise(() => {}); +}); +client.reset = common.mustCall(); + +const session = new ProbeInspectorSession({ + childArgv: ['-e', ''], + host: '127.0.0.1', + port: 0, + probes: [probe], + skipPortPreflight: true, +}); +session.client = client; + +session.run().then(common.mustCall(({ code, report }) => { + assert.strictEqual(code, 1); + assertProbeJson(report, { + v: 2, + probes: [probe], + results: [{ + event: 'error', + pending: [0], + error: { + code: 'probe_failure', + message: + 'Inspector connection lost before probes started before probes: ' + + 'probe-target.js:1. The target startup may have torn down the ' + + 'inspector. If startup does not touch the inspector, this is likely ' + + 'a Node.js bug. Please file an issue.', + stderr: '', + details: { lastCdpMethod: 'NodeRuntime.enable' }, + }, + }], + }); +})); diff --git a/test/parallel/test-debugger-run-restart-init.js b/test/parallel/test-debugger-run-restart-init.js index 78f237353baf..b57939135f80 100644 --- a/test/parallel/test-debugger-run-restart-init.js +++ b/test/parallel/test-debugger-run-restart-init.js @@ -79,9 +79,29 @@ async function assertCommandWaitsForInit(repl, command, gate, calls) { const runGate = createGate(); const restartGate = createGate(); const gates = [null, runGate, restartGate]; + const client = new EventEmitter(); + let nodeRuntimeEnableCount = 0; + client.callMethod = common.mustCall(async (method) => { + calls.push(method); + if (method === 'NodeRuntime.enable') { + const emitWaiting = () => { + calls.push('NodeRuntime.waitingForDebugger'); + client.emit('NodeRuntime.waitingForDebugger'); + }; + // Cover notifications arriving both before and after the enable reply. + if (nodeRuntimeEnableCount++ % 2 === 0) { + emitWaiting(); + } else { + setImmediate(emitWaiting); + } + } else { + assert.strictEqual(method, 'NodeRuntime.disable'); + } + }, 6); const inspector = { - client: new EventEmitter(), + client, domainNames: ['Debugger', 'HeapProfiler', 'Profiler', 'Runtime'], + options: { script: 'debugger-target.js' }, stdin: new PassThrough(), stdout: new PassThrough(), run: common.mustCall(async () => { @@ -101,6 +121,29 @@ async function assertCommandWaitsForInit(repl, command, gate, calls) { await assertCommandWaitsForInit(repl, 'run', runGate, calls); await assertCommandWaitsForInit(repl, 'restart', restartGate, calls); + assert.deepStrictEqual( + calls.filter((call) => ( + call === 'NodeRuntime.enable' || + call === 'NodeRuntime.waitingForDebugger' || + call === 'NodeRuntime.disable' || + call === 'Runtime.runIfWaitingForDebugger' + )), + [ + 'NodeRuntime.enable', + 'NodeRuntime.waitingForDebugger', + 'NodeRuntime.disable', + 'Runtime.runIfWaitingForDebugger', + 'NodeRuntime.enable', + 'NodeRuntime.waitingForDebugger', + 'NodeRuntime.disable', + 'Runtime.runIfWaitingForDebugger', + 'NodeRuntime.enable', + 'NodeRuntime.waitingForDebugger', + 'NodeRuntime.disable', + 'Runtime.runIfWaitingForDebugger', + ], + ); + assert.deepStrictEqual( calls.filter((call) => ( call === 'inspector.run' || @@ -116,4 +159,25 @@ async function assertCommandWaitsForInit(repl, command, gate, calls) { ); repl.close(); + + const attachCalls = []; + const attachClient = new EventEmitter(); + attachClient.callMethod = common.mustNotCall(); + const attachInspector = { + client: attachClient, + domainNames: ['Debugger', 'HeapProfiler', 'Profiler', 'Runtime'], + options: {}, + stdin: new PassThrough(), + stdout: new PassThrough(), + suspendReplWhile(fn) { + return fn(); + }, + }; + + for (const domain of attachInspector.domainNames) { + attachInspector[domain] = createAgent(domain, attachCalls, []); + } + + const attachRepl = await createRepl(attachInspector)(); + attachRepl.close(); })().then(common.mustCall()); diff --git a/test/parallel/test-debugger-wait-for-debugger.js b/test/parallel/test-debugger-wait-for-debugger.js new file mode 100644 index 000000000000..b438147ea832 --- /dev/null +++ b/test/parallel/test-debugger-wait-for-debugger.js @@ -0,0 +1,137 @@ +// Flags: --expose-internals +'use strict'; + +const common = require('../common'); + +common.skipIfInspectorDisabled(); + +const assert = require('assert'); +const { EventEmitter } = require('events'); +const { + waitForDebugger, +} = require('internal/debugger/inspect_helpers'); + +function assertListenersRemoved(client) { + assert.strictEqual( + client.listenerCount('NodeRuntime.waitingForDebugger'), + 0, + ); + assert.strictEqual(client.listenerCount('close'), 0); +} + +async function testWaitingNotification(beforeEnableReply) { + const client = new EventEmitter(); + const calls = []; + client.callMethod = common.mustCall(async (method) => { + calls.push(method); + const emitWaiting = () => { + client.emit('NodeRuntime.waitingForDebugger'); + }; + if (method === 'NodeRuntime.enable') { + if (beforeEnableReply) { + emitWaiting(); + } else { + setImmediate(emitWaiting); + } + } else { + assert.strictEqual(method, 'NodeRuntime.disable'); + } + }, 2); + + await waitForDebugger(client); + assert.deepStrictEqual(calls, [ + 'NodeRuntime.enable', + 'NodeRuntime.disable', + ]); + assertListenersRemoved(client); +} + +async function testCloseWhileWaiting(beforeEnableReply) { + const client = new EventEmitter(); + client.callMethod = common.mustCall((method) => { + assert.strictEqual(method, 'NodeRuntime.enable'); + setImmediate(() => client.emit('close')); + return beforeEnableReply ? new Promise(() => {}) : Promise.resolve(); + }); + + await assert.rejects( + waitForDebugger(client), + { + code: 'ERR_DEBUGGER_ERROR', + message: 'Debugger session ended while waiting for target startup', + }, + ); + assertListenersRemoved(client); +} + +async function testCloseWhileDisabling() { + const client = new EventEmitter(); + client.callMethod = common.mustCall((method) => { + if (method === 'NodeRuntime.enable') { + client.emit('NodeRuntime.waitingForDebugger'); + return Promise.resolve(); + } + assert.strictEqual(method, 'NodeRuntime.disable'); + setImmediate(() => client.emit('close')); + return new Promise(() => {}); + }, 2); + + await assert.rejects( + waitForDebugger(client), + { + code: 'ERR_DEBUGGER_ERROR', + message: 'Debugger session ended while waiting for target startup', + }, + ); + assertListenersRemoved(client); +} + +async function testEnableFailure() { + const client = new EventEmitter(); + const expected = new Error('NodeRuntime.enable failed'); + client.callMethod = common.mustCall(async (method) => { + assert.strictEqual(method, 'NodeRuntime.enable'); + throw expected; + }); + + await assert.rejects( + waitForDebugger(client), + (error) => { + assert.strictEqual(error, expected); + return true; + }, + ); + assertListenersRemoved(client); +} + +async function testDisableFailure() { + const client = new EventEmitter(); + const expected = new Error('NodeRuntime.disable failed'); + client.callMethod = common.mustCall(async (method) => { + if (method === 'NodeRuntime.enable') { + client.emit('NodeRuntime.waitingForDebugger'); + return; + } + assert.strictEqual(method, 'NodeRuntime.disable'); + throw expected; + }, 2); + + await assert.rejects( + waitForDebugger(client), + (error) => { + assert.strictEqual(error, expected); + return true; + }, + ); + assertListenersRemoved(client); +} + +(async () => { + await testWaitingNotification(true); + await testWaitingNotification(false); + await testCloseWhileWaiting(true); + await testCloseWhileWaiting(false); + await testCloseWhileDisabling(); + await testEnableFailure(); + await testDisableFailure(); +})().then(common.mustCall()); diff --git a/test/parallel/test-dgram-bind-error-callback.js b/test/parallel/test-dgram-bind-error-callback.js new file mode 100644 index 000000000000..d5009f948228 --- /dev/null +++ b/test/parallel/test-dgram-bind-error-callback.js @@ -0,0 +1,23 @@ +'use strict'; +const common = require('../common'); +const assert = require('node:assert'); +const dgram = require('node:dgram'); + +// Ensure that bind errors (e.g. EADDRINUSE) are not silently swallowed +// when socket.bind() is called with a callback but without a user +// 'error' handler. + +const socket1 = dgram.createSocket('udp4'); + +socket1.bind(0, common.mustCall(() => { + const { port } = socket1.address(); + const socket2 = dgram.createSocket('udp4'); + + process.on('uncaughtException', common.mustCall((err) => { + assert.strictEqual(err.code, 'EADDRINUSE'); + socket1.close(); + socket2.close(); + })); + + socket2.bind({ port }, common.mustNotCall()); +})); diff --git a/test/parallel/test-dgram-udp6-link-local-address.js b/test/parallel/test-dgram-udp6-link-local-address.js index 5c090acc6b9e..2320d665cfdd 100644 --- a/test/parallel/test-dgram-udp6-link-local-address.js +++ b/test/parallel/test-dgram-udp6-link-local-address.js @@ -11,9 +11,9 @@ const { isWindows } = common; function linklocal() { for (const [ifname, entries] of Object.entries(os.networkInterfaces())) { - for (const { address, family, scopeid } of entries) { + for (const { address, family } of entries) { if (family === 'IPv6' && address.startsWith('fe80:')) { - return { address, ifname, scopeid }; + return { address, ifname }; } } } @@ -32,6 +32,12 @@ const client = dgram.createSocket('udp6'); // Create the server socket listening on the link-local address. const server = dgram.createSocket('udp6'); +client.on('message', common.mustCall((buf) => { + assert.strictEqual(buf.toString(), message); + server.close(); + client.close(); +})); + server.on('listening', common.mustCall(() => { const port = server.address().port; client.send(message, 0, message.length, port, address); @@ -40,14 +46,15 @@ server.on('listening', common.mustCall(() => { server.on('message', common.mustCall((buf, info) => { const received = buf.toString(); assert.strictEqual(received, message); - // Check that the sender address is the one bound, - // including the link local scope identifier. - assert.strictEqual( - info.address, - isWindows ? `${iface.address}%${iface.scopeid}` : address - ); - server.close(); - client.close(); + // AIX may use `lo0` as the scope ID for a datagram sent to a local interface. + // See https://github.com/nodejs/node/issues/46792#issuecomment-1455049522. + const scopeIndex = info.address.lastIndexOf('%'); + assert.notStrictEqual(scopeIndex, -1); + assert.strictEqual(info.address.slice(0, scopeIndex), iface.address); + assert.notStrictEqual(info.address.slice(scopeIndex + 1), ''); + + // Verify that the scoped sender address can be used for a reply. + server.send(buf, info.port, info.address); }, 1)); server.bind({ address }); diff --git a/test/parallel/test-diagnostics-channel-object-channel-pub-sub.js b/test/parallel/test-diagnostics-channel-object-channel-pub-sub.js index 9498419b806c..f02544936559 100644 --- a/test/parallel/test-diagnostics-channel-object-channel-pub-sub.js +++ b/test/parallel/test-diagnostics-channel-object-channel-pub-sub.js @@ -44,3 +44,5 @@ assert.ok(!channel.unsubscribe(subscriber)); assert.throws(() => { channel.subscribe(null); }, { code: 'ERR_INVALID_ARG_TYPE' }); +assert.ok(!channel.hasSubscribers); +assert.ok(!dc.hasSubscribers('test')); diff --git a/test/parallel/test-diagnostics-channel-pub-sub.js b/test/parallel/test-diagnostics-channel-pub-sub.js index a7232ab58ce8..e3a868b7ce0c 100644 --- a/test/parallel/test-diagnostics-channel-pub-sub.js +++ b/test/parallel/test-diagnostics-channel-pub-sub.js @@ -42,6 +42,8 @@ assert.ok(!dc.unsubscribe(name, subscriber)); assert.throws(() => { dc.subscribe(name, null); }, { code: 'ERR_INVALID_ARG_TYPE' }); +assert.ok(!channel.hasSubscribers); +assert.ok(!dc.hasSubscribers(name)); // Reaching zero subscribers should not delete from the channels map as there // will be no more weakref to incRef if another subscribe happens while the diff --git a/test/parallel/test-dns.js b/test/parallel/test-dns.js index 0977e657f0ca..d8182a8ccf58 100644 --- a/test/parallel/test-dns.js +++ b/test/parallel/test-dns.js @@ -90,6 +90,22 @@ assert(existing.length > 0); }); } +{ + // Out-of-range ports, which should throw a clean error. + const invalidPorts = [2 ** 16, 2 ** 32, 2 ** 64]; + invalidPorts.forEach((port) => { + assert.throws( + () => { + dns.setServers([`1.2.3.4:${port}`]); + }, + { + name: 'RangeError', + code: 'ERR_SOCKET_BAD_PORT' + } + ); + }); +} + const goog = [ '8.8.8.8', '8.8.4.4', @@ -136,6 +152,10 @@ const portsExpected = [ dns.setServers(ports); assert.deepStrictEqual(dns.getServers(), portsExpected); +// Port 0 means "use the default port" for c-ares. +dns.setServers(['4.4.4.4:0', '[2001:4860:4860::8888]:0']); +assert.deepStrictEqual(dns.getServers(), ['4.4.4.4', '2001:4860:4860::8888']); + dns.setServers([]); assert.deepStrictEqual(dns.getServers(), []); @@ -324,6 +344,24 @@ dns.lookup('', { }, err); } +{ + const invalidAddress = Buffer.from('127.0.0.1'); + const err = { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "address" argument must be of type string. ' + + 'Received an instance of Buffer' + }; + + assert.throws(() => { + dnsPromises.lookupService(invalidAddress, 0); + }, err); + + assert.throws(() => { + dns.lookupService(invalidAddress, 0, common.mustNotCall()); + }, err); +} + [null, undefined, 65538, 'test', NaN, Infinity, Symbol(), 0n, true, false, '', () => {}, {}].forEach((port) => { const err = { code: 'ERR_SOCKET_BAD_PORT', diff --git a/test/parallel/test-env-newprotomethod-remove-unnecessary-prototypes.js b/test/parallel/test-env-newprotomethod-remove-unnecessary-prototypes.js index 22c0c8665d14..638c2c3c8722 100644 --- a/test/parallel/test-env-newprotomethod-remove-unnecessary-prototypes.js +++ b/test/parallel/test-env-newprotomethod-remove-unnecessary-prototypes.js @@ -7,13 +7,14 @@ require('../common'); const assert = require('assert'); const { internalBinding } = require('internal/test/binding'); -[ +const testCases = [ internalBinding('udp_wrap').UDP.prototype.bind6, internalBinding('tcp_wrap').TCP.prototype.bind6, internalBinding('udp_wrap').UDP.prototype.send6, internalBinding('tcp_wrap').TCP.prototype.bind, internalBinding('udp_wrap').UDP.prototype.close, internalBinding('tcp_wrap').TCP.prototype.open, -].forEach((binding, i) => { +]; +for (const [i, binding] of testCases.entries()) { assert.strictEqual('prototype' in binding, false, `Test ${i} failed`); -}); +} diff --git a/test/parallel/test-events-uncaught-exception-stack.js b/test/parallel/test-events-uncaught-exception-stack.js index 25fe9d6585f1..c11fcbabcb35 100644 --- a/test/parallel/test-events-uncaught-exception-stack.js +++ b/test/parallel/test-events-uncaught-exception-stack.js @@ -8,9 +8,9 @@ const EventEmitter = require('events'); process.on('uncaughtException', common.mustCall((err) => { const [firstLine, ...lines] = err.stack.split('\n'); assert.strictEqual(firstLine, 'Error'); - lines.forEach((line) => { + for (const line of lines) { assert.match(line, /^ {4}at/); - }); + } })); new EventEmitter().emit('error', new Error()); diff --git a/test/parallel/test-experimental-shared-value-conveyor.js b/test/parallel/test-experimental-shared-value-conveyor.js index 17eb32c66b11..123e212bd1da 100644 --- a/test/parallel/test-experimental-shared-value-conveyor.js +++ b/test/parallel/test-experimental-shared-value-conveyor.js @@ -1,8 +1,8 @@ 'use strict'; const common = require('../common'); const assert = require('assert'); -const { spawnSync } = require('child_process'); const { Worker, parentPort } = require('worker_threads'); +const { spawnSyncAndAssert } = require('../common/child_process'); if (process.env.TEST_CHILD_PROCESS === '1') { // Do not use isMainThread so that this test itself can be run inside a Worker. @@ -29,10 +29,10 @@ if (process.env.TEST_CHILD_PROCESS === '1') { const args = ['--harmony-struct', __filename]; const options = { env: { TEST_CHILD_PROCESS: '1', ...process.env } }; - const child = spawnSync(process.execPath, args, options); - assert.strictEqual(child.stderr.toString().trim(), ''); - assert.strictEqual(child.stdout.toString().trim(), ''); - assert.strictEqual(child.status, 0); - assert.strictEqual(child.signal, null); + spawnSyncAndAssert(process.execPath, args, options, { + stdout: '', + stderr: '', + trim: true + }); } diff --git a/test/parallel/test-fs-buffertype-writesync.js b/test/parallel/test-fs-buffertype-writesync.js index 5649a00569a2..d1738dd3cc35 100644 --- a/test/parallel/test-fs-buffertype-writesync.js +++ b/test/parallel/test-fs-buffertype-writesync.js @@ -6,11 +6,12 @@ require('../common'); const assert = require('assert'); const fs = require('fs'); -[ +const testCases = [ true, false, 0, 1, Infinity, () => {}, {}, [], undefined, null, -].forEach((value) => { +]; +for (const value of testCases) { assert.throws( () => fs.writeSync(1, value), { message: /"buffer"/, code: 'ERR_INVALID_ARG_TYPE' } ); -}); +} diff --git a/test/parallel/test-fs-constants.js b/test/parallel/test-fs-constants.js index 740fa026e6c5..518cb39ee00e 100644 --- a/test/parallel/test-fs-constants.js +++ b/test/parallel/test-fs-constants.js @@ -35,6 +35,10 @@ const knownFsConstantNames = [ 'O_CREAT', 'O_EXCL', 'UV_FS_O_FILEMAP', + 'UV_FS_O_TEMPORARY', + 'UV_FS_O_SHORT_LIVED', + 'UV_FS_O_SEQUENTIAL', + 'UV_FS_O_RANDOM', 'O_NOCTTY', 'O_TRUNC', 'O_APPEND', diff --git a/test/parallel/test-fs-cp-async-verbatim-dir-symlinks-with-filter.mjs b/test/parallel/test-fs-cp-async-verbatim-dir-symlinks-with-filter.mjs new file mode 100644 index 000000000000..8e773bc6065c --- /dev/null +++ b/test/parallel/test-fs-cp-async-verbatim-dir-symlinks-with-filter.mjs @@ -0,0 +1,46 @@ +// This tests that cp with verbatimSymlinks and filter preserves +// the directory symlink type on Windows (does not create a file symlink). +import { mustNotMutateObjectDeep, isWindows } from '../common/index.mjs'; +import { nextdir } from '../common/fs.js'; +import assert from 'node:assert'; +import { + mkdirSync, + writeFileSync, + symlinkSync, + readlinkSync, + readdirSync, + statSync, +} from 'node:fs'; +import { cp } from 'node:fs/promises'; +import { join } from 'node:path'; + +import tmpdir from '../common/tmpdir.js'; +tmpdir.refresh(); + +// Setup source with a relative directory symlink +const src = nextdir(); +mkdirSync(join(src, 'packages', 'my-lib'), mustNotMutateObjectDeep({ recursive: true })); +writeFileSync(join(src, 'packages', 'my-lib', 'index.js'), 'module.exports = "hello"'); +mkdirSync(join(src, 'linked'), mustNotMutateObjectDeep({ recursive: true })); +symlinkSync(join('..', 'packages', 'my-lib'), join(src, 'linked', 'my-lib'), 'dir'); + +// Copy with verbatimSymlinks: true AND a filter function +const dest = nextdir(); +await cp(src, dest, mustNotMutateObjectDeep({ + recursive: true, + verbatimSymlinks: true, + filter: () => true, +})); + +// Verify the symlink target is preserved verbatim +const link = readlinkSync(join(dest, 'linked', 'my-lib')); +if (isWindows) { + assert.strictEqual(link.toLowerCase(), join('..', 'packages', 'my-lib').toLowerCase()); +} else { + assert.strictEqual(link, join('..', 'packages', 'my-lib')); +} + +// Verify the symlink works as a directory (not a file symlink) +const destSymlink = join(dest, 'linked', 'my-lib'); +assert.ok(statSync(destSymlink).isDirectory(), 'symlink target should be accessible as a directory'); +assert.deepStrictEqual(readdirSync(destSymlink), ['index.js']); diff --git a/test/parallel/test-fs-cp-sync-verbatim-dir-symlinks-with-filter.mjs b/test/parallel/test-fs-cp-sync-verbatim-dir-symlinks-with-filter.mjs new file mode 100644 index 000000000000..7aa0d90ff2a4 --- /dev/null +++ b/test/parallel/test-fs-cp-sync-verbatim-dir-symlinks-with-filter.mjs @@ -0,0 +1,46 @@ +// This tests that cpSync with verbatimSymlinks and filter preserves +// the directory symlink type on Windows (does not create a file symlink). +import { mustNotMutateObjectDeep, isWindows } from '../common/index.mjs'; +import { nextdir } from '../common/fs.js'; +import assert from 'node:assert'; +import { + cpSync, + mkdirSync, + writeFileSync, + symlinkSync, + readlinkSync, + readdirSync, + statSync, +} from 'node:fs'; +import { join } from 'node:path'; + +import tmpdir from '../common/tmpdir.js'; +tmpdir.refresh(); + +// Setup source with a relative directory symlink +const src = nextdir(); +mkdirSync(join(src, 'packages', 'my-lib'), mustNotMutateObjectDeep({ recursive: true })); +writeFileSync(join(src, 'packages', 'my-lib', 'index.js'), 'module.exports = "hello"'); +mkdirSync(join(src, 'linked'), mustNotMutateObjectDeep({ recursive: true })); +symlinkSync(join('..', 'packages', 'my-lib'), join(src, 'linked', 'my-lib'), 'dir'); + +// Copy with verbatimSymlinks: true AND a filter function +const dest = nextdir(); +cpSync(src, dest, mustNotMutateObjectDeep({ + recursive: true, + verbatimSymlinks: true, + filter: () => true, +})); + +// Verify the symlink target is preserved verbatim +const link = readlinkSync(join(dest, 'linked', 'my-lib')); +if (isWindows) { + assert.strictEqual(link.toLowerCase(), join('..', 'packages', 'my-lib').toLowerCase()); +} else { + assert.strictEqual(link, join('..', 'packages', 'my-lib')); +} + +// Verify the symlink works as a directory (not a file symlink) +const destSymlink = join(dest, 'linked', 'my-lib'); +assert.ok(statSync(destSymlink).isDirectory(), 'symlink target should be accessible as a directory'); +assert.deepStrictEqual(readdirSync(destSymlink), ['index.js']); diff --git a/test/parallel/test-fs-cp-sync-verbatim-symlinks-invalid.mjs b/test/parallel/test-fs-cp-sync-verbatim-symlinks-invalid.mjs index 3db176487f71..c9ec4e82f414 100644 --- a/test/parallel/test-fs-cp-sync-verbatim-symlinks-invalid.mjs +++ b/test/parallel/test-fs-cp-sync-verbatim-symlinks-invalid.mjs @@ -8,10 +8,10 @@ import fixtures from '../common/fixtures.js'; tmpdir.refresh(); const src = fixtures.path('copy/kitchen-sink'); -[1, [], {}, null, 1n, undefined, null, Symbol(), '', () => {}] - .forEach((verbatimSymlinks) => { - assert.throws( - () => cpSync(src, src, { verbatimSymlinks }), - { code: 'ERR_INVALID_ARG_TYPE' } - ); - }); +const testCases = [1, [], {}, null, 1n, undefined, null, Symbol(), '', () => {}]; +for (const verbatimSymlinks of testCases) { + assert.throws( + () => cpSync(src, src, { verbatimSymlinks }), + { code: 'ERR_INVALID_ARG_TYPE' } + ); +} diff --git a/test/parallel/test-fs-glob.mjs b/test/parallel/test-fs-glob.mjs index bd95bce7d0e3..9226e491358d 100644 --- a/test/parallel/test-fs-glob.mjs +++ b/test/parallel/test-fs-glob.mjs @@ -1,5 +1,6 @@ import * as common from '../common/index.mjs'; import tmpdir from '../common/tmpdir.js'; +import { spawnSync } from 'node:child_process'; import { resolve, dirname, sep, relative, join, isAbsolute } from 'node:path'; import { mkdir, writeFile, symlink, glob as asyncGlob } from 'node:fs/promises'; import { glob, globSync, Dirent, chmodSync, writeFileSync, rmSync } from 'node:fs'; @@ -669,3 +670,78 @@ describe('globSync - ENOTDIR', function() { } }); }); + +describe('glob - seen cache', function() { + // Refs: https://github.com/nodejs/node/issues/62897 + test('does not skip siblings after a seen child path', () => { + // The glob traversal used to return early from the children loop when a + // child path had already been seen through a different pattern context, + // silently dropping the remaining siblings. Whether the bug triggered + // depended on directory iteration order, so the child process pins the + // order by patching readdir before loading the glob implementation. + const script = ` + const assert = require('node:assert'); + const fs = require('node:fs'); + const fsPromises = require('node:fs/promises'); + const path = require('node:path'); + + const cwd = process.argv[1]; + const a = path.join(cwd, 'a'); + fs.mkdirSync(path.join(a, 'b', 'c', 'd'), { recursive: true }); + fs.mkdirSync(path.join(a, 'c', 'd', 'c'), { recursive: true }); + fs.writeFileSync(path.join(a, 'x'), ''); + fs.writeFileSync(path.join(a, 'z'), ''); + + const originalReaddirSync = fs.readdirSync; + const originalReaddir = fsPromises.readdir; + + const reorder = (target, entries) => { + if (!Array.isArray(entries) || target !== a) return entries; + const names = ['c', 'b', 'x', 'z']; + return names.map((name) => entries.find((entry) => entry.name === name)) + .filter(Boolean); + }; + + fs.readdirSync = function(target, options) { + return reorder(target, originalReaddirSync.call(this, target, options)); + }; + fsPromises.readdir = async function(target, options) { + return reorder(target, await originalReaddir.call(this, target, options)); + }; + + const { Glob } = require('internal/fs/glob'); + const expected = ['a/b', 'a/c', 'a/x', 'a/z']; + const normalize = (results) => + results.map((item) => item.replaceAll(path.sep, '/')).sort(); + + (async () => { + const syncResults = normalize(new Glob('a/**/../*', { cwd }).globSync()); + for (const item of expected) { + assert.ok(syncResults.includes(item), + \`missing \${item} from sync results: \${syncResults}\`); + } + + const asyncResults = []; + for await (const item of new Glob('a/**/../*', { cwd }).glob()) { + asyncResults.push(item); + } + const normalized = normalize(asyncResults); + for (const item of expected) { + assert.ok(normalized.includes(item), + \`missing \${item} from async results: \${normalized}\`); + } + })().catch((err) => { + console.error(err); + process.exitCode = 1; + }); + `; + + const seenDir = tmpdir.resolve('glob-seen'); + const child = spawnSync( + process.execPath, + ['--expose-internals', '-e', script, seenDir], + { encoding: 'utf8' }, + ); + assert.strictEqual(child.status, 0, child.stderr || child.stdout); + }); +}); diff --git a/test/parallel/test-fs-readfilesync-utf8-sizes.js b/test/parallel/test-fs-readfilesync-utf8-sizes.js new file mode 100644 index 000000000000..ac8670836d44 --- /dev/null +++ b/test/parallel/test-fs-readfilesync-utf8-sizes.js @@ -0,0 +1,98 @@ +'use strict'; +// fs.readFileSync(path, 'utf8') takes a dedicated native path. Its result must +// equal fs.readFileSync(path).toString('utf8') for every file size (in +// particular around its internal 8 KiB stack buffer and for multi-megabyte +// files), for file descriptors positioned mid-file, and for files whose +// reported size is wrong (procfs reports 0, sysfs reports a page). +const common = require('../common'); +const tmpdir = require('../common/tmpdir'); +const assert = require('assert'); +const fs = require('fs'); + +tmpdir.refresh(); + +function content(size) { + // Multi-byte characters straddling every possible chunk boundary. + const unit = 'abcdé€\u{1F600}\n'; + let s = unit.repeat(Math.ceil(size / unit.length)); + s = s.slice(0, size); + // Avoid ending on a lone surrogate produced by slice(). + if (/[\ud800-\udbff]$/.test(s)) s = s.slice(0, -1) + 'x'; + return s; +} + +const sizes = [0, 1, 8190, 8191, 8192, 8193, 8194, 16383, 16384, 16385, + 65535, 65536, 65537, 100000, (1 << 20) - 1, 1 << 20, (1 << 20) + 1, + (8 << 20) + 5]; +for (const size of sizes) { + const file = tmpdir.resolve(`f-${size}.txt`); + const str = content(size); + fs.writeFileSync(file, str); + const expected = fs.readFileSync(file).toString('utf8'); + assert.strictEqual(fs.readFileSync(file, 'utf8'), expected, `size ${size} by path`); + assert.strictEqual(fs.readFileSync(file, { encoding: 'utf-8' }), expected, `size ${size} utf-8 alias`); + // By fd: from the start (leaves the fd at EOF), then at EOF, then from a + // mid-file position on a fresh fd. + let fd = fs.openSync(file, 'r'); + try { + assert.strictEqual(fs.readFileSync(fd, 'utf8'), expected, `size ${size} by fd`); + assert.strictEqual(fs.readFileSync(fd, 'utf8'), '', `size ${size} by fd at EOF`); + } finally { + fs.closeSync(fd); + } + if (size > 10) { + fd = fs.openSync(file, 'r'); + try { + // Advance the fd 3 bytes (inside the ASCII prefix, so still valid UTF-8). + assert.strictEqual(fs.readSync(fd, Buffer.alloc(3), 0, 3, null), 3); + assert.strictEqual(fs.readFileSync(fd, 'utf8'), Buffer.from(expected).subarray(3).toString('utf8'), + `size ${size} by fd at offset 3`); + } finally { + fs.closeSync(fd); + } + } +} + +// Binary garbage is decoded with replacement characters identically. +{ + const file = tmpdir.resolve('binary.bin'); + const buf = Buffer.alloc(20000); + for (let i = 0; i < buf.length; i++) buf[i] = (i * 7919) & 0xff; + fs.writeFileSync(file, buf); + assert.strictEqual(fs.readFileSync(file, 'utf8'), buf.toString('utf8')); +} + +// Files whose st_size does not describe their content. +if (common.isLinux) { + for (const file of ['/proc/self/status', '/proc/self/smaps', '/proc/cpuinfo', + '/proc/version', '/sys/kernel/mm/transparent_hugepage/enabled']) { + let viaBuffer; + try { + viaBuffer = fs.readFileSync(file); + } catch { + continue; // Not available in this environment. + } + const viaUtf8 = fs.readFileSync(file, 'utf8'); + if (file !== '/proc/version' && file.startsWith('/proc/')) { + // Content legitimately differs between two reads; compare shape instead. + assert.ok(viaUtf8.length > 0); + assert.strictEqual(viaUtf8.split('\n').length > 5, true, file); + // Of these, smaps reliably exceeds the 8 KiB stack buffer. + if (file === '/proc/self/smaps') assert.ok(viaUtf8.length > 8192, `smaps is only ${viaUtf8.length} chars`); + } else { + assert.strictEqual(viaUtf8, viaBuffer.toString('utf8'), file); + } + } +} + +// Directory: same outcome either way (EISDIR, except on platforms where +// read() accepts directories, e.g. AIX). +function outcome(read) { + try { + return read(); + } catch (err) { + return err.code; + } +} +assert.strictEqual(outcome(() => fs.readFileSync(tmpdir.path, 'utf8')), + outcome(() => fs.readFileSync(tmpdir.path).toString('utf8'))); diff --git a/test/parallel/test-fs-readlink-type-check.js b/test/parallel/test-fs-readlink-type-check.js index 58d431308c76..adf2c96126e7 100644 --- a/test/parallel/test-fs-readlink-type-check.js +++ b/test/parallel/test-fs-readlink-type-check.js @@ -4,7 +4,8 @@ const common = require('../common'); const assert = require('assert'); const fs = require('fs'); -[false, 1, {}, [], null, undefined].forEach((i) => { +const testCases = [false, 1, {}, [], null, undefined]; +for (const i of testCases) { assert.throws( () => fs.readlink(i, common.mustNotCall()), { @@ -19,4 +20,4 @@ const fs = require('fs'); name: 'TypeError' } ); -}); +} diff --git a/test/parallel/test-fs-realpath-async-stale-stat-values.js b/test/parallel/test-fs-realpath-async-stale-stat-values.js new file mode 100644 index 000000000000..83e8af7b3eaf --- /dev/null +++ b/test/parallel/test-fs-realpath-async-stale-stat-values.js @@ -0,0 +1,62 @@ +'use strict'; + +// The async realpath() reads the shared stat buffer the same way realpathSync() +// did, to decide whether the walk has reached a pipe or a socket. The walk's +// own fs.stat() does leave the right value there, but it is not read until +// after fs.readlink() and a process.nextTick(), and any stat completing in that +// window replaces it. +// +// Truncating the walk only costs something when a second symlink follows the +// one being resolved, so the path used here has two. + +const common = require('../common'); + +if (common.isWindows) + common.skip('no mkfifo on Windows'); + +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); +const { execFileSync } = require('child_process'); +const tmpdir = require('../common/tmpdir'); + +tmpdir.refresh(); + +const real = tmpdir.resolve('real'); +const pkg = tmpdir.resolve('pkg'); +const fifo = tmpdir.resolve('fifo'); + +fs.mkdirSync(real); +fs.mkdirSync(pkg); +fs.writeFileSync(path.join(real, 'index.js'), ''); +fs.symlinkSync(path.join('..', 'real'), path.join(pkg, 'sub')); +fs.symlinkSync('pkg', tmpdir.resolve('link')); +execFileSync('mkfifo', [fifo]); + +const throughLinks = tmpdir.resolve('link', 'sub', 'index.js'); +const expected = path.join(real, 'index.js'); + +// Keep stats of the FIFO completing for as long as the walk runs, so that one +// of them lands in the buffer during the window. +let settled = false; +(function statFifo() { + if (settled) return; + fs.stat(fifo, statFifo); +})(); + +let error; +let resolvedPath; + +fs.realpath(throughLinks, common.mustCall((err, resolved) => { + settled = true; + error = err; + resolvedPath = resolved; +})); + +// Asserted on exit rather than in the callback. An assertion that fails inside +// this callback is lost: it does not reach an `uncaughtException` handler and +// the process still exits 0, so the test would pass over the bug it covers. +process.on('exit', () => { + assert.ifError(error); + assert.strictEqual(resolvedPath, expected); +}); diff --git a/test/parallel/test-fs-realpath-namespaced-drive-win.js b/test/parallel/test-fs-realpath-namespaced-drive-win.js new file mode 100644 index 000000000000..eac72eb8dfa2 --- /dev/null +++ b/test/parallel/test-fs-realpath-namespaced-drive-win.js @@ -0,0 +1,63 @@ +'use strict'; + +const common = require('../common'); +if (!common.isWindows) { + common.skip('This test is Windows-specific.'); +} + +// Verify that the JavaScript realpath implementation accepts namespaced drive +// paths, including when a junction switches the walk back to a regular drive +// path, and reports a missing entry instead of treating the drive as a file. + +const assert = require('node:assert'); +const fs = require('node:fs'); +const path = require('node:path'); +const { test } = require('node:test'); +const tmpdir = require('../common/tmpdir'); + +tmpdir.refresh(); + +const entry = tmpdir.resolve('entry.js'); +const namespacedEntry = path.toNamespacedPath(entry); +const namespacedMissing = path.toNamespacedPath(tmpdir.resolve('missing.js')); +const targetDir = tmpdir.resolve('target'); +const targetEntry = path.join(targetDir, 'entry.js'); +const junctionDir = tmpdir.resolve('junction'); +const namespacedJunctionEntry = path.toNamespacedPath( + path.join(junctionDir, 'entry.js'), +); + +fs.writeFileSync(entry, ''); +fs.mkdirSync(targetDir); +fs.writeFileSync(targetEntry, ''); +fs.symlinkSync(targetDir, junctionDir, 'junction'); + +function assertNamespacedRealpath(result) { + assert.strictEqual(path.toNamespacedPath(result), namespacedEntry); +} + +test('fs.realpathSync resolves a namespaced drive path', () => { + assertNamespacedRealpath(fs.realpathSync(namespacedEntry)); +}); + +test('fs.realpathSync reports ENOENT for a missing namespaced drive path', () => { + assert.throws(() => fs.realpathSync(namespacedMissing), { code: 'ENOENT' }); +}); + +test('fs.realpathSync resolves a namespaced path through a junction', () => { + assert.strictEqual(fs.realpathSync(namespacedJunctionEntry), targetEntry); +}); + +test('fs.realpath resolves a namespaced drive path', (t, done) => { + fs.realpath(namespacedEntry, common.mustSucceed((result) => { + assertNamespacedRealpath(result); + done(); + })); +}); + +test('fs.realpath resolves a namespaced path through a junction', (t, done) => { + fs.realpath(namespacedJunctionEntry, common.mustSucceed((result) => { + assert.strictEqual(result, targetEntry); + done(); + })); +}); diff --git a/test/parallel/test-fs-realpath-stale-stat-values.js b/test/parallel/test-fs-realpath-stale-stat-values.js new file mode 100644 index 000000000000..2a5dfdad7a45 --- /dev/null +++ b/test/parallel/test-fs-realpath-stale-stat-values.js @@ -0,0 +1,73 @@ +// Flags: --expose-internals +'use strict'; + +// Resolving a path must not depend on what was stat'ed before it. +// +// While walking a path, realpath skips the components it already knows are +// real, and in that branch it consulted the shared stat buffer to decide +// whether the walk had reached a pipe or a socket. That buffer holds the result +// of the last stat made anywhere in the process, so an unrelated stat of a FIFO +// made the walk stop early and hand back the path with its symlinks unresolved. +// The unresolved path is then cached, so every later resolution repeats it. + +const common = require('../common'); + +if (common.isWindows) + common.skip('no mkfifo on Windows'); + +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); +const { execFileSync } = require('child_process'); +const { realpathCacheKey } = require('internal/fs/utils'); +const tmpdir = require('../common/tmpdir'); + +tmpdir.refresh(); + +const pkg = tmpdir.resolve('pkg'); +const link = tmpdir.resolve('pkg-link'); +const fifo = tmpdir.resolve('fifo'); + +fs.mkdirSync(pkg); +fs.writeFileSync(path.join(pkg, 'index.js'), 'module.exports = {};\n'); +fs.writeFileSync(tmpdir.resolve('warm.js'), 'module.exports = {};\n'); +fs.symlinkSync('pkg', link); +execFileSync('mkfifo', [fifo]); + +const throughLink = path.join(link, 'index.js'); +const throughReal = path.join(pkg, 'index.js'); + +// The walk only skips a component once something has established it as real. A +// cache carrying the ancestors is that state, and it is the state the module +// loader's own cache is in after it has resolved anything else under the +// directory. +function ancestorCache() { + const cache = new Map(); + let dir = ''; + for (const part of tmpdir.path.split(path.sep).slice(1)) { + dir += path.sep + part; + cache.set(dir, dir); + } + return cache; +} + +fs.statSync(path.join(pkg, 'index.js')); +assert.strictEqual( + fs.realpathSync(throughLink, { [realpathCacheKey]: ancestorCache() }), + throughReal, +); + +fs.statSync(fifo); +assert.strictEqual( + fs.realpathSync(throughLink, { [realpathCacheKey]: ancestorCache() }), + throughReal, +); + +// What the stale read costs through the module loader, whose cache puts the +// walk in that same state: the symlink stays unresolved, so the file is loaded +// a second time under a second name. +require(tmpdir.resolve('warm.js')); +fs.statSync(fifo); + +assert.strictEqual(require.resolve(throughLink), throughReal); +assert.strictEqual(require(throughLink), require(throughReal)); diff --git a/test/parallel/test-fs-rmSync-eperm-retries.js b/test/parallel/test-fs-rmSync-eperm-retries.js new file mode 100644 index 000000000000..55f1d9b30708 --- /dev/null +++ b/test/parallel/test-fs-rmSync-eperm-retries.js @@ -0,0 +1,85 @@ +'use strict'; + +const common = require('../common'); + +if (!common.isWindows) + common.skip('Windows-specific: EPERM sharing-violation retry in rmSync'); + +const tmpdir = require('../common/tmpdir'); +const assert = require('assert'); +const { once } = require('events'); +const { spawn } = require('child_process'); +const fs = require('fs'); +const path = require('path'); + +tmpdir.refresh(); + +// UV_FS_O_EXLOCK opens with share mode 0, so deletion fails with EPERM +// until this process kills the child. +const lockerScript = ` + const fs = require('fs'); + const UV_FS_O_EXLOCK = 0x10000000; + fs.openSync(process.argv[1], fs.constants.O_RDWR | UV_FS_O_EXLOCK); + process.stdout.write('locked'); + setInterval(() => {}, 60_000); +`; + +async function spawnLocker(file) { + const child = spawn(process.execPath, ['-e', lockerScript, file], + { stdio: ['ignore', 'pipe', 'inherit'] }); + const [data] = await once(child.stdout, 'data'); + assert.strictEqual(data.toString(), 'locked'); + return child; +} + +// Sleep before retry i is i * retryDelay ms, so all retries take at least +// retryDelay * (1 + 2 + ... + maxRetries) ms. +function minRetryTime({ maxRetries, retryDelay }) { + return retryDelay * maxRetries * (maxRetries + 1) / 2; +} + +function timedRmThrowsEPERM(dir, options) { + const start = Date.now(); + assert.throws(() => { + fs.rmSync(dir, { recursive: true, ...options }); + }, { + code: 'EPERM', + name: 'Error', + syscall: 'rm', + }); + return Date.now() - start; +} + +(async () => { + const dir = tmpdir.resolve('rm-eperm-retries'); + const file = path.join(dir, 'locked.txt'); + fs.mkdirSync(dir); + fs.writeFileSync(file, 'hello'); + + const child = await spawnLocker(file); + try { + // Proves the lock is effective: no retries means an immediate EPERM. + timedRmThrowsEPERM(dir, { maxRetries: 0, retryDelay: 0 }); + assert.strictEqual(fs.existsSync(file), true); + + const options = { maxRetries: 4, retryDelay: 100 }; + const expected = minRetryTime(options); // 100+200+300+400 = 1000 ms. + const elapsed = timedRmThrowsEPERM(dir, options); + + // Windows timer granularity may shave a few ms off each Sleep() call. + const slack = 16 * options.maxRetries; + assert.ok(elapsed >= expected - slack, + `rmSync() gave up after ${elapsed}ms; expected it to spend at ` + + `least ~${expected}ms on ${options.maxRetries} retries of ` + + `${options.retryDelay}ms escalating delay`); + + // Catches unit confusion (e.g. seconds vs. milliseconds) in the delay. + assert.ok(elapsed < common.platformTimeout(expected * 10), + `rmSync() gave up after ${elapsed}ms; expected roughly ` + + `${expected}ms for ${options.maxRetries} retries`); + } finally { + child.kill(); + } + await once(child, 'exit'); + assert.strictEqual(fs.existsSync(file), true); +})().then(common.mustCall()); diff --git a/test/parallel/test-fs-rmdir-type-check.js b/test/parallel/test-fs-rmdir-type-check.js index 7014ce27f8e3..321386b0d7d1 100644 --- a/test/parallel/test-fs-rmdir-type-check.js +++ b/test/parallel/test-fs-rmdir-type-check.js @@ -4,7 +4,8 @@ const common = require('../common'); const assert = require('assert'); const fs = require('fs'); -[false, 1, [], {}, null, undefined].forEach((i) => { +const testCases = [false, 1, [], {}, null, undefined]; +for (const i of testCases) { assert.throws( () => fs.rmdir(i, common.mustNotCall()), { @@ -19,4 +20,4 @@ const fs = require('fs'); name: 'TypeError' } ); -}); +} diff --git a/test/parallel/test-fs-stream-windows-handle.js b/test/parallel/test-fs-stream-windows-handle.js new file mode 100644 index 000000000000..299a618802cf --- /dev/null +++ b/test/parallel/test-fs-stream-windows-handle.js @@ -0,0 +1,47 @@ +'use strict'; + +// Tests option validation for the `windowsHandle` option of +// fs.createReadStream()/createWriteStream(). The functional round-trip on +// Windows (where a real Win32 HANDLE is wrapped in a file descriptor) is +// covered by test/addons/fs-windows-handle. + +const common = require('../common'); +const assert = require('assert'); +const fs = require('fs'); + +const handle = 1n; + +for (const create of [fs.createReadStream, fs.createWriteStream]) { + assert.throws(() => create(null, { windowsHandle: handle, fd: 2 }), { + code: 'ERR_INCOMPATIBLE_OPTION_PAIR', + }); +} + +if (!common.isWindows) { + for (const create of [fs.createReadStream, fs.createWriteStream]) { + assert.throws(() => create(null, { windowsHandle: handle }), { + code: 'ERR_FEATURE_UNAVAILABLE_ON_PLATFORM', + }); + } + return; +} + +for (const create of [fs.createReadStream, fs.createWriteStream]) { + // Cannot be combined with a custom `fs` implementation. + assert.throws(() => create(null, { windowsHandle: handle, fs: {} }), { + code: 'ERR_METHOD_NOT_IMPLEMENTED', + }); + + // Must be a bigint. + assert.throws(() => create(null, { windowsHandle: 'nope' }), { + code: 'ERR_INVALID_ARG_TYPE', + }); + assert.throws(() => create(null, { windowsHandle: 1 }), { + code: 'ERR_INVALID_ARG_TYPE', + }); + + // Must fit into 64 bits. + assert.throws(() => create(null, { windowsHandle: 2n ** 64n }), { + code: 'ERR_OUT_OF_RANGE', + }); +} diff --git a/test/parallel/test-fs-unlink-type-check.js b/test/parallel/test-fs-unlink-type-check.js index 006e9ad73485..62c1cf3da71b 100644 --- a/test/parallel/test-fs-unlink-type-check.js +++ b/test/parallel/test-fs-unlink-type-check.js @@ -4,7 +4,8 @@ const common = require('../common'); const assert = require('assert'); const fs = require('fs'); -[false, 1, {}, [], null, undefined].forEach((i) => { +const testCases = [false, 1, {}, [], null, undefined]; +for (const i of testCases) { assert.throws( () => fs.unlink(i, common.mustNotCall()), { @@ -19,4 +20,4 @@ const fs = require('fs'); name: 'TypeError' } ); -}); +} diff --git a/test/parallel/test-heap-embedder-graph.js b/test/parallel/test-heap-embedder-graph.js new file mode 100644 index 000000000000..1873fd1a49ca --- /dev/null +++ b/test/parallel/test-heap-embedder-graph.js @@ -0,0 +1,23 @@ +// Flags: --expose-internals +'use strict'; + +require('../common'); +const assert = require('assert'); +const { internalBinding } = require('internal/test/binding'); + +const { buildEmbedderGraph } = internalBinding('heap_utils'); + +const first = {}; +const second = {}; +const bigint = BigInt('123456789012345678901234567890'); +const sameBigint = BigInt('123456789012345678901234567890'); +const graph = buildEmbedderGraph(first, first, second, bigint, sameBigint); + +function findNodes(value) { + return graph.filter((node) => Object.hasOwn(node, 'value') && + Object.is(node.value, value)); +} + +assert.strictEqual(findNodes(first).length, 1); +assert.strictEqual(findNodes(second).length, 1); +assert.strictEqual(findNodes(bigint).length, 1); diff --git a/test/parallel/test-heap-prof-basic.js b/test/parallel/test-heap-prof-basic.js index 34d8af9a7840..4ddc313ff048 100644 --- a/test/parallel/test-heap-prof-basic.js +++ b/test/parallel/test-heap-prof-basic.js @@ -9,7 +9,7 @@ const fixtures = require('../common/fixtures'); common.skipIfInspectorDisabled(); const assert = require('assert'); -const { spawnSync } = require('child_process'); +const { spawnSyncAndExitWithoutError } = require('../common/child_process'); const tmpdir = require('../common/tmpdir'); @@ -20,18 +20,13 @@ const { { tmpdir.refresh(); - const output = spawnSync(process.execPath, [ + spawnSyncAndExitWithoutError(process.execPath, [ '--heap-prof', fixtures.path('workload', 'allocation.js'), ], { cwd: tmpdir.path, env }); - if (output.status !== 0) { - console.log(output.stderr.toString()); - console.log(output); - } - assert.strictEqual(output.status, 0); const profiles = getHeapProfiles(tmpdir.path); assert.strictEqual(profiles.length, 1); } diff --git a/test/parallel/test-heap-prof-exec-argv.js b/test/parallel/test-heap-prof-exec-argv.js index 02ad4430dba7..186b4d5d631b 100644 --- a/test/parallel/test-heap-prof-exec-argv.js +++ b/test/parallel/test-heap-prof-exec-argv.js @@ -9,7 +9,7 @@ const fixtures = require('../common/fixtures'); common.skipIfInspectorDisabled(); const assert = require('assert'); -const { spawnSync } = require('child_process'); +const { spawnSyncAndExitWithoutError } = require('../common/child_process'); const tmpdir = require('../common/tmpdir'); @@ -20,7 +20,7 @@ const { { tmpdir.refresh(); - const output = spawnSync(process.execPath, [ + const { child: output } = spawnSyncAndExitWithoutError(process.execPath, [ fixtures.path('workload', 'allocation-worker-argv.js'), ], { cwd: tmpdir.path, @@ -29,10 +29,6 @@ const { HEAP_PROF_INTERVAL: '128' } }); - if (output.status !== 0) { - console.log(output.stderr.toString()); - } - assert.strictEqual(output.status, 0); const profiles = getHeapProfiles(tmpdir.path); assert.strictEqual(profiles.length, 1); verifyFrames(output, profiles[0], 'runAllocation'); diff --git a/test/parallel/test-heap-prof-loop-drained.js b/test/parallel/test-heap-prof-loop-drained.js index d0fc4c987849..d8e07b33cb46 100644 --- a/test/parallel/test-heap-prof-loop-drained.js +++ b/test/parallel/test-heap-prof-loop-drained.js @@ -8,7 +8,7 @@ const fixtures = require('../common/fixtures'); common.skipIfInspectorDisabled(); const assert = require('assert'); -const { spawnSync } = require('child_process'); +const { spawnSyncAndExitWithoutError } = require('../common/child_process'); const tmpdir = require('../common/tmpdir'); @@ -21,7 +21,7 @@ const { { tmpdir.refresh(); - const output = spawnSync(process.execPath, [ + const { child: output } = spawnSyncAndExitWithoutError(process.execPath, [ '--heap-prof', '--heap-prof-interval', kHeapProfInterval, @@ -30,11 +30,6 @@ const { cwd: tmpdir.path, env }); - if (output.status !== 0) { - console.log(output.stderr.toString()); - console.log(output); - } - assert.strictEqual(output.status, 0); const profiles = getHeapProfiles(tmpdir.path); assert.strictEqual(profiles.length, 1); verifyFrames(output, profiles[0], 'runAllocation'); diff --git a/test/parallel/test-http-agent-highwatermark-reuse.js b/test/parallel/test-http-agent-highwatermark-reuse.js new file mode 100644 index 000000000000..b78b475ef6f1 --- /dev/null +++ b/test/parallel/test-http-agent-highwatermark-reuse.js @@ -0,0 +1,56 @@ +'use strict'; + +// Regression test: when a pooled socket's writableHighWaterMark differs from +// the new request's highWaterMark, the agent must sync the socket's HWM so +// that backpressure semantics match what the caller requested. +// +// See: https://github.com/nodejs/node/issues/64680 + +const common = require('../common'); +const assert = require('assert'); +const http = require('http'); + +const server = http.createServer(common.mustCall((req, res) => { + req.resume(); + req.on('end', () => res.end('ok')); +}, 2)); + +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const agent = new http.Agent({ keepAlive: true }); + + // Request A: creates socket with HWM=1MB. + http.request({ + host: 'localhost', port, method: 'POST', agent, + highWaterMark: 1024 * 1024, + }, common.mustCall((res) => { + res.resume(); + res.on('end', common.mustCall(() => { + // Wait for socket to return to pool. + setTimeout(common.mustCall(requestB), 100); + })); + })).end('x'); + + function requestB() { + const freeCount = Object.values(agent.freeSockets).flat().length; + assert.strictEqual(freeCount, 1); + + // Request B: HWM=10KB — agent must sync the reused socket's HWM. + const reqB = http.request({ + host: 'localhost', port, method: 'POST', agent, + highWaterMark: 10 * 1024, + }, common.mustCall((res) => { + res.resume(); + res.on('end', common.mustCall(() => { + server.close(); + })); + })); + + reqB.on('socket', common.mustCall((socket) => { + // Socket HWM must be synced to the request's value. + assert.strictEqual(socket.writableHighWaterMark, 10 * 1024); + })); + + reqB.end('y'); + } +})); diff --git a/test/parallel/test-http-agent-keylog-existing-sockets.js b/test/parallel/test-http-agent-keylog-existing-sockets.js new file mode 100644 index 000000000000..1a391c09b8be --- /dev/null +++ b/test/parallel/test-http-agent-keylog-existing-sockets.js @@ -0,0 +1,71 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const http = require('http'); + +// Adding a 'keylog' listener to an agent is wired up by maybeEnableKeylog(), +// which attaches the agent's keylog handler to the sockets the agent already +// owns. `agent.sockets` and `agent.freeSockets` map a name to an *array* of +// sockets, so each bucket has to be walked. Treating the buckets themselves as +// sockets threw a TypeError out of `agent.on('keylog', ...)`, which also meant +// the listener was never registered. + +// Two servers so the two sockets get different names, which keeps one parked +// in freeSockets instead of being reused by the second request. +const idleServer = http.createServer((req, res) => res.end('idle')); +const busyServer = http.createServer((req, res) => { + setTimeout(() => res.end('busy'), common.platformTimeout(200)); +}); + +function countSockets(agent) { + let free = 0; + let active = 0; + for (const bucket of Object.values(agent.freeSockets)) free += bucket.length; + for (const bucket of Object.values(agent.sockets)) active += bucket.length; + return { free, active }; +} + +idleServer.listen(0, common.mustCall(() => { + busyServer.listen(0, common.mustCall(() => { + const agent = new http.Agent({ keepAlive: true, maxSockets: 4 }); + + // First request finishes, so its socket is released into freeSockets. + http.get({ port: idleServer.address().port, agent }, common.mustCall((res) => { + res.resume(); + res.on('end', common.mustCall(() => { + // Second request is still in flight, so its socket is in sockets. + const req = http.get({ port: busyServer.address().port, agent }, + common.mustCall((res2) => { + res2.resume(); + res2.on('end', common.mustCall(() => { + agent.destroy(); + idleServer.close(); + busyServer.close(); + })); + })); + + req.on('socket', common.mustCall(() => { + setImmediate(common.mustCall(() => { + const { free, active } = countSockets(agent); + assert.strictEqual(free, 1); + assert.strictEqual(active, 1); + + // Used to throw `TypeError: sockets[i].on is not a function`. + agent.on('keylog', common.mustNotCall()); + assert.strictEqual(agent.listenerCount('keylog'), 1); + + // Every existing socket, idle or in use, is now listening. + for (const set of [agent.freeSockets, agent.sockets]) { + for (const bucket of Object.values(set)) { + for (const socket of bucket) { + assert.strictEqual(socket.listenerCount('keylog'), 1); + } + } + } + })); + })); + })); + })); + })); +})); diff --git a/test/parallel/test-http-correct-hostname.js b/test/parallel/test-http-correct-hostname.js index c67a6d49f2e7..ea4b3cb25a09 100644 --- a/test/parallel/test-http-correct-hostname.js +++ b/test/parallel/test-http-correct-hostname.js @@ -15,7 +15,7 @@ if (common.hasCrypto) { modules.https = https; } -Object.keys(modules).forEach((module) => { +for (const module of Object.keys(modules)) { const doNotCall = common.mustNotCall( `${module}.request should not connect to ${module}://example.com%60x.example.com` ); @@ -25,4 +25,4 @@ Object.keys(modules).forEach((module) => { 'example.com`x.example.com', ]); req.abort(); -}); +}; diff --git a/test/parallel/test-http-hostname-typechecking.js b/test/parallel/test-http-hostname-typechecking.js index 368766e08701..c143106b115e 100644 --- a/test/parallel/test-http-hostname-typechecking.js +++ b/test/parallel/test-http-hostname-typechecking.js @@ -8,7 +8,8 @@ const http = require('http'); // when passed as the value of either options.hostname or options.host const vals = [{}, [], NaN, Infinity, -Infinity, true, false, 1, 0, new Date()]; -vals.forEach((v) => { + +for (const v of vals) { const received = common.invalidArgTypeHelper(v); assert.throws( () => http.request({ hostname: v }), @@ -31,7 +32,7 @@ vals.forEach((v) => { received } ); -}); +} // These values are OK and should not throw synchronously. // Only testing for 'hostname' validation so ignore connection errors. diff --git a/test/parallel/test-http-outgoing-flush-drain.js b/test/parallel/test-http-outgoing-flush-drain.js new file mode 100644 index 000000000000..12b5a5036cce --- /dev/null +++ b/test/parallel/test-http-outgoing-flush-drain.js @@ -0,0 +1,57 @@ +'use strict'; + +// Regression test: when _flush() hands buffered data to a socket whose +// writableHighWaterMark is higher than the OutgoingMessage's kHighWaterMark, +// drain must still fire. Previously, _flush() gated drain emission on +// writableLength === 0, which included socket.writableLength — but the +// socket was never backpressured (data < socket HWM), so drain never fired. +// +// See: https://github.com/nodejs/node/issues/64680 + +const common = require('../common'); +const assert = require('assert'); +const http = require('http'); + +// Server that delays reading to keep socket.writableLength > 0 during flush. +const server = http.createServer(common.mustCall((req, res) => { + setTimeout(() => { + req.resume(); + req.on('end', () => res.end('ok')); + }, 500); +}, 2)); + +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const agent = new http.Agent({ keepAlive: true }); + + // Request A: creates socket with HWM=2MB. + http.request({ + host: 'localhost', port, method: 'POST', agent, + highWaterMark: 2 * 1024 * 1024, + }, common.mustCall((res) => { + res.resume(); + res.on('end', common.mustCall(() => { + // Wait for socket to return to pool. + setTimeout(common.mustCall(() => { + // Request B: default HWM (64KB), reuses socket (HWM=2MB). + // Write 500KB: above OM HWM (64KB), below socket HWM (2MB). + const reqB = http.request({ + host: 'localhost', port, method: 'POST', agent, + }, common.mustCall((res2) => { + res2.resume(); + res2.on('end', common.mustCall(() => { + server.close(); + })); + })); + + const result = reqB.write(Buffer.alloc(500 * 1024)); + assert.strictEqual(result, false); + + // Drain must fire — no deadlock. + reqB.on('drain', common.mustCall(() => { + reqB.end(); + })); + }), 100); + })); + })).end('x'); +})); diff --git a/test/parallel/test-http-parser-max-header-pairs-cache.js b/test/parallel/test-http-parser-max-header-pairs-cache.js new file mode 100644 index 000000000000..dc8a60f36b0f --- /dev/null +++ b/test/parallel/test-http-parser-max-header-pairs-cache.js @@ -0,0 +1,77 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const { HTTPParser } = require('_http_common'); + +const { REQUEST } = HTTPParser; +const kOnHeaders = HTTPParser.kOnHeaders | 0; +const kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0; +const kOnBody = HTTPParser.kOnBody | 0; +const kOnMessageComplete = HTTPParser.kOnMessageComplete | 0; + +function createParser() { + const parser = new HTTPParser(); + parser.initialize(REQUEST, {}); + parser[kOnHeaders] = () => {}; + parser[kOnHeadersComplete] = () => {}; + parser[kOnBody] = common.mustNotCall(); + parser[kOnMessageComplete] = () => {}; + return parser; +} + +// maxHeaderPairs is cached once for each independent header section. Main +// headers, trailers, the next message, and a reinitialized parser must each +// observe a fresh value. +{ + const parser = createParser(); + const limits = [2, 4, 2, 2]; + + Object.defineProperty(parser, 'maxHeaderPairs', { + configurable: true, + get: common.mustCall(() => limits.shift(), limits.length), + }); + + parser[kOnHeadersComplete] = common.mustCall(undefined, 3); + parser[kOnMessageComplete] = common.mustCall(undefined, 3); + + const pipelined = Buffer.from( + 'POST /first HTTP/1.1\r\n' + + 'Transfer-Encoding: chunked\r\n' + + '\r\n' + + '0\r\n' + + 'X-A: a\r\n' + + 'X-B: b\r\n' + + '\r\n' + + 'GET /second HTTP/1.1\r\n' + + 'X-C: c\r\n' + + '\r\n' + ); + assert.strictEqual(parser.execute(pipelined, 0, pipelined.length), pipelined.length); + + parser.initialize(REQUEST, {}); + const reused = Buffer.from('GET /reused HTTP/1.1\r\nX-D: d\r\n\r\n'); + assert.strictEqual(parser.execute(reused, 0, reused.length), reused.length); + assert.deepStrictEqual(limits, []); +} + +// Preserve the existing exception behavior for the first property lookup. +{ + const parser = createParser(); + const expected = new Error('maxHeaderPairs getter'); + Object.defineProperty(parser, 'maxHeaderPairs', { + get: common.mustCall(() => { throw expected; }), + }); + const request = Buffer.from('GET / HTTP/1.1\r\nX-A: a\r\n\r\n'); + assert.throws(() => parser.execute(request, 0, request.length), expected); +} + +// Non-positive and non-number values continue to mean unlimited. +for (const maxHeaderPairs of [undefined, null, NaN, 0, -1, new Number(2)]) { + const parser = createParser(); + parser.maxHeaderPairs = maxHeaderPairs; + const request = Buffer.from( + 'GET / HTTP/1.1\r\nX-A: a\r\nX-B: b\r\nX-C: c\r\n\r\n' + ); + assert.strictEqual(parser.execute(request, 0, request.length), request.length); +} diff --git a/test/parallel/test-http-req-close-robust-from-tampering.js b/test/parallel/test-http-req-close-robust-from-tampering.js index edfdb309a7e4..75f57ad54133 100644 --- a/test/parallel/test-http-req-close-robust-from-tampering.js +++ b/test/parallel/test-http-req-close-robust-from-tampering.js @@ -7,7 +7,8 @@ const { connect } = require('net'); // cause an error. const server = createServer(common.mustCall((req, res) => { - req.client._events.close.forEach((fn) => { fn.bind(req)(); }); + const closeHandlers = req.client._events.close; + for (const fn of closeHandlers) { fn.bind(req)(); } })); server.unref(); diff --git a/test/parallel/test-http-server-response-standalone.js b/test/parallel/test-http-server-response-standalone.js index bc7ca56f894b..00ca7c0a96d6 100644 --- a/test/parallel/test-http-server-response-standalone.js +++ b/test/parallel/test-http-server-response-standalone.js @@ -15,18 +15,11 @@ const res = new ServerResponse({ httpVersionMinor: 1 }); -let firstChunk = true; - const ws = new Writable({ write: common.mustCall((chunk, encoding, callback) => { - if (firstChunk) { - assert(chunk.toString().endsWith('hello world')); - firstChunk = false; - } else { - assert.strictEqual(chunk.length, 0); - } + assert(chunk.toString().endsWith('hello world')); setImmediate(callback); - }, 2) + }, 1) }); res.assignSocket(ws); diff --git a/test/parallel/test-http-server-stale-close.js b/test/parallel/test-http-server-stale-close.js index 60112f708628..909d02c920eb 100644 --- a/test/parallel/test-http-server-stale-close.js +++ b/test/parallel/test-http-server-stale-close.js @@ -31,11 +31,11 @@ if (process.env.NODE_TEST_FORK_PORT) { method: 'POST', host: '127.0.0.1', port: +process.env.NODE_TEST_FORK_PORT, - }, process.exit); + }, () => process.exit(0)); req.write('BAM'); req.end(); } else { - const server = http.createServer(common.mustCallAtLeast((req, res) => { + const server = http.createServer(common.mustCall((req, res) => { res.writeHead(200, { 'Content-Length': '42' }); req.pipe(res); assert.strictEqual(req.destroyed, false); @@ -45,9 +45,13 @@ if (process.env.NODE_TEST_FORK_PORT) { res.end(); })); })); - server.listen(0, function() { - fork(__filename, { + server.listen(0, common.mustCall(function() { + const cp = fork(__filename, { + stdio: 'inherit', env: { ...process.env, NODE_TEST_FORK_PORT: this.address().port } }); - }); + cp.once('exit', common.mustCall((code) => { + assert.strictEqual(code, 0); + })); + })); } diff --git a/test/parallel/test-http-server-unconsume.js b/test/parallel/test-http-server-unconsume.js index 0a0b5913812a..e92d7c127504 100644 --- a/test/parallel/test-http-server-unconsume.js +++ b/test/parallel/test-http-server-unconsume.js @@ -4,7 +4,8 @@ const assert = require('assert'); const http = require('http'); const net = require('net'); -['on', 'addListener', 'prependListener'].forEach((testFn) => { +const testCases = ['on', 'addListener', 'prependListener']; +for (const testFn of testCases) { let received = ''; const server = http.createServer(function(req, res) { @@ -30,4 +31,4 @@ const net = require('net'); })); })); })); -}); +}; diff --git a/test/parallel/test-http2-server-settimeout-no-callback.js b/test/parallel/test-http2-server-settimeout-no-callback.js index d0352067b7bd..a5cb080609f5 100644 --- a/test/parallel/test-http2-server-settimeout-no-callback.js +++ b/test/parallel/test-http2-server-settimeout-no-callback.js @@ -11,7 +11,8 @@ const http2 = require('http2'); const verifyCallbacks = common.mustCall((server) => { const testTimeout = 10; - [true, 1, {}, [], null, 'test'].forEach((notFunction) => { + const testCases = [true, 1, {}, [], null, 'test']; + for (const notFunction of testCases) { assert.throws( () => server.setTimeout(testTimeout, notFunction), { @@ -19,7 +20,7 @@ const verifyCallbacks = common.mustCall((server) => { code: 'ERR_INVALID_ARG_TYPE', } ); - }); + }; // No callback const returnedVal = server.setTimeout(testTimeout); diff --git a/test/parallel/test-http2-session-destroy-during-receive.js b/test/parallel/test-http2-session-destroy-during-receive.js new file mode 100644 index 000000000000..238d511fd83c --- /dev/null +++ b/test/parallel/test-http2-session-destroy-during-receive.js @@ -0,0 +1,41 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +const fixtures = require('../common/fixtures'); +const http2 = require('http2'); + +// Regression test for closing a session while nghttp2 is processing several +// streams from the same input buffer. No stream created after the close can be +// exposed to JavaScript, so delivering its DATA would call a missing onread. +const server = http2.createSecureServer({ + key: fixtures.readKey('agent2-key.pem'), + cert: fixtures.readKey('agent2-cert.pem') +}); + +server.on('stream', common.mustCallAtLeast((stream) => { + stream.on('error', () => {}); + stream.session.destroy(); +}, 1)); + +server.listen(0, common.mustCall(() => { + const client = http2.connect(`https://localhost:${server.address().port}`, { + rejectUnauthorized: false + }); + client.on('error', () => {}); + client.on('close', common.mustCall(() => server.close())); + + client.on('remoteSettings', common.mustCall(() => { + for (let i = 0; i < 8; i++) { + const stream = client.request({ + ':method': 'POST', + ':path': `/${i}` + }); + stream.on('error', () => {}); + stream.resume(); + stream.end(Buffer.alloc(512)); + } + })); +})); diff --git a/test/parallel/test-http2-status-code-invalid.js b/test/parallel/test-http2-status-code-invalid.js index a906c706d7d7..a8b92aad6369 100644 --- a/test/parallel/test-http2-status-code-invalid.js +++ b/test/parallel/test-http2-status-code-invalid.js @@ -19,9 +19,10 @@ function expectsError(code) { server.on('stream', common.mustCall((stream) => { // Anything lower than 100 and greater than 599 is rejected - [ 99, 700, 1000 ].forEach((i) => { + const testCases = [ 99, 700, 1000 ]; + for (const i of testCases) { assert.throws(() => stream.respond({ ':status': i }), expectsError(i)); - }); + } stream.respond(); stream.end(); diff --git a/test/parallel/test-icu-transcode.js b/test/parallel/test-icu-transcode.js index e9aced128eec..87b45e8649ce 100644 --- a/test/parallel/test-icu-transcode.js +++ b/test/parallel/test-icu-transcode.js @@ -88,3 +88,18 @@ assert.deepStrictEqual( { buffer.transcode(new buffer.SlowBuffer(1), 'utf16le', 'ucs2'); } + +// An odd-length ucs2 source must only convert whole 2-byte code units and +// leave the trailing byte untouched, without reading or writing past the +// conversion buffer. Lengths are chosen to exercise both the on-stack and the +// heap-allocated code paths. +for (const len of [2049, 4099]) { + const src = Buffer.alloc(len, 0x61); + const wholeUnits = src.subarray(0, len - 1); + for (const to of ['latin1', 'ascii']) { + assert.deepStrictEqual( + buffer.transcode(src, 'utf16le', to), + buffer.transcode(wholeUnits, 'utf16le', to), + `ucs2->${to} odd length ${len}`); + } +} diff --git a/test/parallel/test-inspect-address-in-use.js b/test/parallel/test-inspect-address-in-use.js index d900fdfb6795..bd954e4a7bc8 100644 --- a/test/parallel/test-inspect-address-in-use.js +++ b/test/parallel/test-inspect-address-in-use.js @@ -2,7 +2,7 @@ const common = require('../common'); common.skipIfInspectorDisabled(); -const { spawnSync } = require('child_process'); +const { spawnSyncAndExit } = require('../common/child_process'); const { createServer } = require('http'); const assert = require('assert'); const tmpdir = require('../common/tmpdir'); @@ -25,19 +25,18 @@ function testOnServerListen(fn) { function testChildProcess(getArgs, exitCode, options) { testOnServerListen(common.mustCall((server) => { const { port } = server.address(); - const child = spawnSync(process.execPath, getArgs(port), options); - const stderr = child.stderr.toString().trim(); - const stdout = child.stdout.toString().trim(); - console.log('[STDERR]'); - console.log(stderr); - console.log('[STDOUT]'); - console.log(stdout); - const match = stderr.match( - /Starting inspector on 127\.0\.0\.1:(\d+) failed: address already in use/ - ); - assert.notStrictEqual(match, null); - assert.strictEqual(match[1], port + ''); - assert.strictEqual(child.status, exitCode); + spawnSyncAndExit(process.execPath, getArgs(port), options, { + status: exitCode, + signal: null, + trim: true, + stderr: function(str) { + const match = str.match( + /Starting inspector on 127\.0\.0\.1:(\d+) failed: address already in use/ + ); + assert.notStrictEqual(match, null); + assert.strictEqual(match[1], port + ''); + }, + }); })); } diff --git a/test/parallel/test-inspector-async-hook-after-done.js b/test/parallel/test-inspector-async-hook-after-done.js index f9cd7b491360..b4eff0467ecd 100644 --- a/test/parallel/test-inspector-async-hook-after-done.js +++ b/test/parallel/test-inspector-async-hook-after-done.js @@ -34,8 +34,8 @@ function onAttachToWorker({ params: { sessionId } }) { session.once('NodeWorker.receivedMessageFromWorker', onMessageReceived); return; } - // Force a call to node::inspector::Agent::ToggleAsyncHook by changing the - // async call stack depth + // Force a call to node::inspector::Agent::SyncAsyncHookState by changing + // the async call stack depth postToWorkerInspector('Debugger.setAsyncCallStackDepth', { maxDepth: 1 }); // This is were the original crash happened session.post('NodeWorker.detach', { sessionId }, () => { diff --git a/test/parallel/test-messageevent-brandcheck.js b/test/parallel/test-messageevent-brandcheck.js index 17f2b708cc56..a78affb785af 100644 --- a/test/parallel/test-messageevent-brandcheck.js +++ b/test/parallel/test-messageevent-brandcheck.js @@ -3,12 +3,6 @@ require('../common'); const assert = require('assert'); -[ - 'data', - 'origin', - 'lastEventId', - 'source', - 'ports', -].forEach((i) => { +for (const i of ['data', 'origin', 'lastEventId', 'source', 'ports']) { assert.throws(() => Reflect.get(MessageEvent.prototype, i, {}), TypeError); -}); +} diff --git a/test/parallel/test-mime-api.js b/test/parallel/test-mime-api.js index dffead31850b..5cab3f9cf2af 100644 --- a/test/parallel/test-mime-api.js +++ b/test/parallel/test-mime-api.js @@ -185,3 +185,17 @@ assert.throws(() => params.set('x', `x${NOT_HTTP_QUOTED_STRING_CODE_POINT}`), /p assert.strictEqual(params.has('foo'), false); assert.deepStrictEqual([...params], []); } + +{ + // Non-throwing MimeType.parse, works for valid + const mime = MIMEType.parse('text/plain;Charset=value'); + assert.strictEqual(mime.params.get('Charset'), 'value'); + assert.strictEqual(mime.params.get('charset'), 'value'); + assert.strictEqual(mime.params.get('CHARSET'), 'value'); + assert.strictEqual(mime.params.has('Charset'), true); + assert.strictEqual(`${mime.params}`, 'charset=value'); + + // Returns null on Invalid + const invalidMime = MIMEType.parse('text plain'); + assert.strictEqual(invalidMime, null); +} diff --git a/test/parallel/test-module-nearest-parent-package-json-cache.js b/test/parallel/test-module-nearest-parent-package-json-cache.js new file mode 100644 index 000000000000..3d818c9fe1d9 --- /dev/null +++ b/test/parallel/test-module-nearest-parent-package-json-cache.js @@ -0,0 +1,57 @@ +'use strict'; +// Flags: --expose-internals +// The nearest parent package.json lookup that every CommonJS module load +// performs is answered once per directory, not once per file. +const common = require('../common'); +const tmpdir = require('../common/tmpdir'); +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); +const { internalBinding } = require('internal/test/binding'); +const packageJsonReader = require('internal/modules/package_json_reader'); + +tmpdir.refresh(); +const root = tmpdir.resolve('pkg'); +const sub = path.join(root, 'lib', 'sub'); +fs.mkdirSync(sub, { recursive: true }); +fs.writeFileSync(path.join(root, 'package.json'), JSON.stringify({ name: 'pkg', type: 'commonjs' })); +const files = []; +for (const dir of [path.join(root, 'lib'), sub]) { + for (let i = 0; i < 5; i++) { + const file = path.join(dir, `m${i}.js`); + fs.writeFileSync(file, 'module.exports = __filename;'); + files.push(file); + } +} + +const modulesBinding = internalBinding('modules'); +const original = modulesBinding.getNearestParentPackageJSON; +const calls = []; +modulesBinding.getNearestParentPackageJSON = common.mustCallAtLeast((checkPath) => { + calls.push(checkPath); + return original(checkPath); +}, 1); + +for (const file of files) { + assert.strictEqual(require(file), file); +} +// Ten modules in two directories: two lookups reach the binding. +assert.strictEqual(calls.length, 2, `binding called for: ${calls.join(', ')}`); + +// Same answer (and the same object) for every file of a directory, and for +// the directory itself when asked with a trailing separator. +const viaFile = packageJsonReader.getNearestParentPackageJSON(files[0]); +assert.strictEqual(viaFile.data.name, 'pkg'); +assert.strictEqual(packageJsonReader.getNearestParentPackageJSON(files[1]), viaFile); +assert.strictEqual(packageJsonReader.getNearestParentPackageJSON(path.join(root, 'lib') + path.sep), viaFile); +assert.strictEqual(calls.length, 2); + +// A directory that has not been seen yet is looked up once more. +const other = path.join(root, 'other'); +fs.mkdirSync(other); +fs.writeFileSync(path.join(other, 'x.js'), ''); +assert.strictEqual(packageJsonReader.getNearestParentPackageJSON(path.join(other, 'x.js')).data.name, 'pkg'); +assert.strictEqual(packageJsonReader.getNearestParentPackageJSON(path.join(other, 'y.js')).data.name, 'pkg'); +assert.strictEqual(calls.length, 3); + +modulesBinding.getNearestParentPackageJSON = original; diff --git a/test/parallel/test-module-unreadable-package-json.js b/test/parallel/test-module-unreadable-package-json.js new file mode 100644 index 000000000000..4261dad85580 --- /dev/null +++ b/test/parallel/test-module-unreadable-package-json.js @@ -0,0 +1,57 @@ +'use strict'; + +// A package.json that exists but cannot be read must not be treated as +// absent. Doing so silently drops fields such as "exports", which can resolve +// a specifier to a different file than the one the package declares. +// Refs: https://github.com/nodejs/node/issues/65220 + +const common = require('../common'); + +if (common.isWindows) { + common.skip('chmod does not restrict reads on Windows'); +} +if (process.getuid?.() === 0) { + common.skip('cannot make a file unreadable as root'); +} + +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); +const { spawnSync } = require('child_process'); +const tmpdir = require('../common/tmpdir'); + +tmpdir.refresh(); + +const depDir = tmpdir.resolve('node_modules/dep'); +fs.mkdirSync(path.join(depDir, 'lib'), { recursive: true }); +const depPackageJson = path.join(depDir, 'package.json'); +fs.writeFileSync( + depPackageJson, + '{"name":"dep","exports":{".":"./lib/real.js"}}', +); +fs.writeFileSync(path.join(depDir, 'lib', 'real.js'), 'export const which = "real";'); +// If the package config is ignored, resolution falls back to this file. +fs.writeFileSync(path.join(depDir, 'index.js'), 'export const which = "decoy";'); + +fs.writeFileSync(tmpdir.resolve('package.json'), '{"type":"module"}'); +const entry = tmpdir.resolve('main.mjs'); +fs.writeFileSync(entry, 'import { which } from "dep"; console.log(which);'); + +// Sanity check: the export resolves while the package config is readable. +{ + const child = spawnSync(process.execPath, [entry], { encoding: 'utf8' }); + assert.strictEqual(child.stdout.trim(), 'real'); + assert.strictEqual(child.status, 0, child.stderr); +} + +fs.chmodSync(depPackageJson, 0o000); + +try { + const child = spawnSync(process.execPath, [entry], { encoding: 'utf8' }); + // The read failure must be reported rather than resolving to index.js. + assert.doesNotMatch(child.stdout, /decoy/); + assert.match(child.stderr, /Cannot read package config/); + assert.notStrictEqual(child.status, 0); +} finally { + fs.chmodSync(depPackageJson, 0o644); +} diff --git a/test/parallel/test-net-socket-unref-timer-parent-chain.js b/test/parallel/test-net-socket-unref-timer-parent-chain.js new file mode 100644 index 000000000000..36a88f1c158e --- /dev/null +++ b/test/parallel/test-net-socket-unref-timer-parent-chain.js @@ -0,0 +1,25 @@ +'use strict'; +const common = require('../common'); + +// Walking the `_parent` chain must stop on a nullish link, not only strict +// `null`. During connection teardown a socket's `_parent` can be left +// `undefined`, which previously caused `_unrefTimer()` and `_destroy()` to read +// a property off `undefined` and throw. +// Refs: https://github.com/nodejs/node/issues/64490 + +const assert = require('assert'); +const net = require('net'); + +{ + const socket = new net.Socket(); + socket._parent = undefined; + socket._unrefTimer(); +} + +{ + const socket = new net.Socket(); + socket._parent = undefined; + socket.on('error', common.mustNotCall()); + socket.destroy(); + assert.strictEqual(socket.destroyed, true); +} diff --git a/test/parallel/test-net-unref-timer-parent-undefined.js b/test/parallel/test-net-unref-timer-parent-undefined.js new file mode 100644 index 000000000000..01e45e82f908 --- /dev/null +++ b/test/parallel/test-net-unref-timer-parent-undefined.js @@ -0,0 +1,39 @@ +'use strict'; + +const common = require('../common'); + +if (!common.hasCrypto) + common.skip('missing crypto'); + +const tls = require('tls'); +const fixtures = require('../common/fixtures'); + +// A TLS socket whose `_parent` is left `undefined` during teardown must not +// crash when reads land on it (`onStreamRead` -> `_unrefTimer`) or when it is +// destroyed (`_destroy`). Both walk the `_parent` chain. +// Refs: https://github.com/nodejs/node/issues/64490 + +const options = { + key: fixtures.readKey('agent1-key.pem'), + cert: fixtures.readKey('agent1-cert.pem'), +}; + +const server = tls.createServer(options, common.mustCall((conn) => { + setTimeout(() => conn.write('x'), 50); +})); + +server.listen(0, common.mustCall(() => { + const client = tls.connect({ + port: server.address().port, + rejectUnauthorized: false, + }, common.mustCall(() => { + client._parent = undefined; + })); + + client.on('data', common.mustCall(() => { + server.close(); + client.destroy(); + })); + + client.on('error', common.mustNotCall()); +})); diff --git a/test/parallel/test-node-run.js b/test/parallel/test-node-run.js index e24117f6b165..ef9cd5a0f805 100644 --- a/test/parallel/test-node-run.js +++ b/test/parallel/test-node-run.js @@ -9,7 +9,7 @@ const assert = require('node:assert'); const fixtures = require('../common/fixtures'); const envSuffix = common.isWindows ? '-windows' : ''; -describe('node --run [command]', () => { +describe('node --run [command]', { concurrency: !process.env.TEST_PARALLEL }, () => { it('returns error on non-existent file', async () => { const child = await common.spawnPromisified( process.execPath, @@ -34,6 +34,28 @@ describe('node --run [command]', () => { assert.strictEqual(child.code, 1); }); + it('recognizes cmd.exe case-insensitively', { + skip: !common.isWindows, + }, async () => { + const env = { ...process.env }; + const comspecKey = Object.keys(env) + .find((key) => key.toLowerCase() === 'comspec'); + assert.notStrictEqual(comspecKey, undefined); + const comspec = env[comspecKey]; + assert.match(comspec, /cmd\.exe$/i); + delete env[comspecKey]; + env.ComSpec = comspec.replace(/cmd\.exe$/i, 'CMD.EXE'); + + const child = await common.spawnPromisified( + process.execPath, + [ '--run', 'pwd-windows'], + { cwd: fixtures.path('run-script'), env }, + ); + assert.strictEqual(child.stdout.trim(), fixtures.path('run-script')); + assert.strictEqual(child.stderr, ''); + assert.strictEqual(child.code, 0); + }); + it('adds node_modules/.bin to path', async () => { const child = await common.spawnPromisified( process.execPath, @@ -222,4 +244,19 @@ describe('node --run [command]', () => { assert.strictEqual(child.stdout, ''); assert.strictEqual(child.code, 1); }); + + it('escapes shell characters', async () => { + const child = await common.spawnPromisified( + process.execPath, + [ '--run', `positional-args${envSuffix}`, '--', '%PAYLOAD%', '$PAYLOAD'], + { cwd: fixtures.path('run-script'), env: { ...process.env, PAYLOAD: 'env value' } }, + ); + assert.strictEqual( + child.stdout, + common.isWindows ? + `Raw '"^%PAYLOAD^%" "$PAYLOAD"'\r\nArguments: '%PAYLOAD% $PAYLOAD'\r\nThe total number of arguments is: 2\r\n` : + "Arguments: '%PAYLOAD% $PAYLOAD'\nThe total number of arguments is: 2\n"); + assert.strictEqual(child.stderr, ''); + assert.strictEqual(child.code, 0); + }); }); diff --git a/test/parallel/test-openssl-unreadable-config.js b/test/parallel/test-openssl-unreadable-config.js new file mode 100644 index 000000000000..99681e0ecba0 --- /dev/null +++ b/test/parallel/test-openssl-unreadable-config.js @@ -0,0 +1,40 @@ +'use strict'; + +// A default OpenSSL configuration file that cannot be read is fatal, and an +// empty OPENSSL_CONF is the documented way past it. +// Refs: https://github.com/nodejs/node/issues/62230 + +const common = require('../common'); +const assert = require('node:assert'); +const { spawnSync } = require('node:child_process'); + +if (!common.hasCrypto) + common.skip('missing crypto'); +if (!common.isLinux) + common.skip('linux only'); +if (process.config.variables.node_shared_openssl) + common.skip('shared openssl may read a different configuration file'); + +// Replace /etc/ssl with an empty tmpfs in a private mount namespace, where +// openssl.cnf is a symlink loop: opening it then fails with ELOOP instead of +// ENOENT, which OpenSSL ignores on its own. The namespace goes away with the +// process, so the host /etc/ssl is left alone. +const setup = 'mount -t tmpfs tmpfs /etc/ssl && ln -s openssl.cnf /etc/ssl/openssl.cnf'; + +if (spawnSync('unshare', ['-Urm', 'sh', '-c', setup]).status !== 0) + common.skip('cannot set up an unprivileged user and mount namespace'); + +function run(env) { + return spawnSync( + 'unshare', + ['-Urm', 'sh', '-c', `${setup} && exec "$0" -p 42`, process.execPath], + { encoding: 'utf8', env: { ...process.env, ...env } }); +} + +const failed = run({}); +assert.notStrictEqual(failed.status, 0); +assert.match(failed.stderr, /OpenSSL configuration error/); + +const skipped = run({ OPENSSL_CONF: '' }); +assert.strictEqual(skipped.status, 0); +assert.strictEqual(skipped.stdout.trim(), '42'); diff --git a/test/parallel/test-os-homedir-no-envvar.js b/test/parallel/test-os-homedir-no-envvar.js index 2f9b1b47a704..3a47d6d72c4d 100644 --- a/test/parallel/test-os-homedir-no-envvar.js +++ b/test/parallel/test-os-homedir-no-envvar.js @@ -1,9 +1,9 @@ 'use strict'; const common = require('../common'); const assert = require('assert'); -const cp = require('child_process'); const os = require('os'); const path = require('path'); +const { spawnSyncAndExitWithoutError } = require('../common/child_process'); if (process.argv[2] === 'child') { @@ -22,9 +22,7 @@ if (process.argv[2] === 'child') { else delete process.env.HOME; - const child = cp.spawnSync(process.execPath, [__filename, 'child'], { + spawnSyncAndExitWithoutError(process.execPath, [__filename, 'child'], { env: process.env }); - - assert.strictEqual(child.status, 0); } diff --git a/test/parallel/test-perf-hooks-histogram-analysis.js b/test/parallel/test-perf-hooks-histogram-analysis.js new file mode 100644 index 000000000000..acc2b5a7eb2d --- /dev/null +++ b/test/parallel/test-perf-hooks-histogram-analysis.js @@ -0,0 +1,501 @@ +// Flags: --expose-internals --no-warnings --allow-natives-syntax +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const { createHistogram } = require('perf_hooks'); +const { internalBinding } = require('internal/test/binding'); +const { inspect } = require('util'); + +// --------------------------------------------------------------------------- +// cdf(value) — cumulative distribution function +// --------------------------------------------------------------------------- +{ + const h = createHistogram(); + + // Empty histogram returns 0 + assert.strictEqual(h.cdf(1), 0); + + for (let i = 1; i <= 5; i++) h.record(i); + + // Below min → 0 + assert.strictEqual(h.cdf(0), 0); + + // At or above some values → monotonically increasing + assert.ok(h.cdf(1) > 0); + assert.ok(h.cdf(3) >= h.cdf(1)); + assert.ok(h.cdf(5) >= h.cdf(3)); + + // Well above max → 1.0 + assert.strictEqual(h.cdf(1000000), 1.0); + + // Validation + assert.throws(() => h.cdf('hello'), { code: 'ERR_INVALID_ARG_TYPE' }); + assert.throws(() => h.cdf(), { code: 'ERR_INVALID_ARG_TYPE' }); + assert.throws(() => h.cdf(undefined), { code: 'ERR_INVALID_ARG_TYPE' }); +} + +// --------------------------------------------------------------------------- +// ccdf(value) — complementary CDF = 1 - cdf +// --------------------------------------------------------------------------- +{ + const h = createHistogram(); + + // Empty: cdf=0 so ccdf=1 + assert.strictEqual(h.ccdf(1), 1); + + for (let i = 1; i <= 5; i++) h.record(i); + + // CCDF + CDF === 1 for all values + for (const v of [0, 1, 3, 5, 1000000]) { + const sum = h.ccdf(v) + h.cdf(v); + assert.ok(Math.abs(sum - 1) < 1e-10, `ccdf(${v})+cdf(${v})=${sum}`); + } + + // Well above max → 0 + assert.strictEqual(h.ccdf(1000000), 0); + + // Validation + assert.throws(() => h.ccdf('hello'), { code: 'ERR_INVALID_ARG_TYPE' }); +} + +// --------------------------------------------------------------------------- +// countAt(value) — count in equivalent bucket +// --------------------------------------------------------------------------- +{ + const h = createHistogram(); + + // Empty → 0 + assert.strictEqual(h.countAt(1), 0); + + h.record(1); + h.record(1); + h.record(1); + h.record(100); + + assert.strictEqual(h.countAt(1), 3); + assert.strictEqual(h.countAt(100), 1); + assert.strictEqual(h.countAt(999999), 0); + + // Validation + assert.throws(() => h.countAt('hello'), { code: 'ERR_INVALID_ARG_TYPE' }); + assert.throws(() => h.countAt(), { code: 'ERR_INVALID_ARG_TYPE' }); +} + +// --------------------------------------------------------------------------- +// skewness getter +// --------------------------------------------------------------------------- +{ + const h = createHistogram(); + + // Too few values returns 0 + assert.strictEqual(h.skewness, 0); + h.record(1); + assert.strictEqual(h.skewness, 0); + h.record(2); + assert.strictEqual(h.skewness, 0); + + // With 3+ values, returns a number + h.record(3); + assert.strictEqual(typeof h.skewness, 'number'); + assert.ok(!Number.isNaN(h.skewness)); + + // Right-skewed distribution → positive skewness + const right = createHistogram(); + for (let i = 0; i < 100; i++) right.record(1); + for (let i = 0; i < 10; i++) right.record(10000); + assert.ok(right.skewness > 0); + + // Appears in inspect output + assert.ok(inspect(right, { depth: null }).includes('skewness')); + + // Appears in toJSON + const json = right.toJSON(); + assert.ok('skewness' in json); + assert.strictEqual(typeof json.skewness, 'number'); + + // Uniform distribution: zero stddev → returns 0 + const uniform = createHistogram(); + for (let i = 0; i < 10; i++) uniform.record(1); + assert.strictEqual(uniform.skewness, 0); +} + +// --------------------------------------------------------------------------- +// kurtosis getter +// --------------------------------------------------------------------------- +{ + const h = createHistogram(); + + // Too few values returns 0 + assert.strictEqual(h.kurtosis, 0); + h.record(1); + h.record(2); + h.record(3); + assert.strictEqual(h.kurtosis, 0); + + // With 4+ values, returns a number + h.record(4); + assert.strictEqual(typeof h.kurtosis, 'number'); + assert.ok(!Number.isNaN(h.kurtosis)); + + // Appears in inspect and toJSON + const h2 = createHistogram(); + for (let i = 1; i <= 100; i++) h2.record(i); + assert.ok(inspect(h2, { depth: null }).includes('kurtosis')); + const json = h2.toJSON(); + assert.ok('kurtosis' in json); + assert.strictEqual(typeof json.kurtosis, 'number'); + + // Uniform distribution: zero stddev → returns 0 + const uniform = createHistogram(); + for (let i = 0; i < 10; i++) uniform.record(1); + assert.strictEqual(uniform.kurtosis, 0); +} + +// --------------------------------------------------------------------------- +// ksTest(other) — Kolmogorov-Smirnov D-statistic +// --------------------------------------------------------------------------- +{ + const h1 = createHistogram(); + const h2 = createHistogram(); + + // Both empty → 0 + assert.strictEqual(h1.ksTest(h2), 0); + + // Identical distributions → 0 + for (let i = 1; i <= 100; i++) { h1.record(i); h2.record(i); } + assert.strictEqual(h1.ksTest(h2), 0); + + // Same histogram against itself → 0 + assert.strictEqual(h1.ksTest(h1), 0); + + // Different distributions → D > 0 + const h3 = createHistogram(); + for (let i = 1000; i <= 2000; i++) h3.record(i); + const d = h1.ksTest(h3); + assert.ok(d > 0); + assert.ok(d <= 1); + + // Symmetry: D(a,b) === D(b,a) + assert.strictEqual(h1.ksTest(h3), h3.ksTest(h1)); + + // Completely disjoint → D close to 1 + const hLow = createHistogram(); + const hHigh = createHistogram(); + for (let i = 0; i < 100; i++) hLow.record(1); + for (let i = 0; i < 100; i++) hHigh.record(100000); + assert.ok(hLow.ksTest(hHigh) > 0.9); + + // One empty → 0 + const empty = createHistogram(); + assert.strictEqual(h1.ksTest(empty), 0); + + // Validation: non-histogram throws + assert.throws(() => h1.ksTest('not a histogram'), + { code: 'ERR_INVALID_ARG_TYPE' }); + assert.throws(() => h1.ksTest(42), + { code: 'ERR_INVALID_ARG_TYPE' }); + assert.throws(() => h1.ksTest({}), + { code: 'ERR_INVALID_ARG_TYPE' }); +} + +// --------------------------------------------------------------------------- +// percentilesAt(percentiles) — batch percentile query +// --------------------------------------------------------------------------- +{ + const h = createHistogram(); + for (let i = 1; i <= 100; i++) h.record(i); + + // Returns a Map + const result = h.percentilesAt([50, 90, 99]); + assert.ok(result instanceof Map); + assert.strictEqual(result.size, 3); + + // Keys are the requested percentiles + assert.ok(result.has(50)); + assert.ok(result.has(90)); + assert.ok(result.has(99)); + + // Values match individual percentile() calls + assert.strictEqual(result.get(50), h.percentile(50)); + assert.strictEqual(result.get(90), h.percentile(90)); + assert.strictEqual(result.get(99), h.percentile(99)); + + // Single element + const single = h.percentilesAt([50]); + assert.strictEqual(single.size, 1); + + // Unsorted input still works (internally sorted) + const unsorted = h.percentilesAt([99, 50, 90]); + assert.strictEqual(unsorted.get(50), h.percentile(50)); + + // Validation + assert.throws(() => h.percentilesAt('not array'), + { code: 'ERR_INVALID_ARG_TYPE' }); + assert.throws(() => h.percentilesAt([0]), + { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => h.percentilesAt([101]), + { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => h.percentilesAt([NaN]), + { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => h.percentilesAt([-1]), + { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => h.percentilesAt(['hello']), + { code: 'ERR_INVALID_ARG_TYPE' }); +} + +// --------------------------------------------------------------------------- +// linearBuckets(stepSize) — linearly-spaced bucket iteration +// --------------------------------------------------------------------------- +{ + const h = createHistogram(); + for (let i = 1; i <= 100; i++) h.record(i); + + const buckets = h.linearBuckets(10); + assert.ok(buckets instanceof Map); + assert.ok(buckets.size > 0); + + // All keys and values are numbers + for (const [key, value] of buckets) { + assert.strictEqual(typeof key, 'number'); + assert.strictEqual(typeof value, 'number'); + assert.ok(value >= 0); + } + + // Total count across buckets equals histogram count + let total = 0; + for (const [, count] of buckets) total += count; + assert.strictEqual(total, h.count); + + // Different step sizes produce different bucket counts + const finer = h.linearBuckets(5); + assert.ok(finer.size >= buckets.size); + + // Validation + assert.throws(() => h.linearBuckets(0), { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => h.linearBuckets(-1), { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => h.linearBuckets('hello'), + { code: 'ERR_INVALID_ARG_TYPE' }); + assert.throws(() => h.linearBuckets(1.5), { code: 'ERR_OUT_OF_RANGE' }); +} + +// --------------------------------------------------------------------------- +// logBuckets(firstBucket, base) — logarithmically-spaced bucket iteration +// --------------------------------------------------------------------------- +{ + const h = createHistogram(); + for (let i = 1; i <= 1000; i++) h.record(i); + + const buckets = h.logBuckets(1, 2); + assert.ok(buckets instanceof Map); + assert.ok(buckets.size > 0); + + for (const [key, value] of buckets) { + assert.strictEqual(typeof key, 'number'); + assert.strictEqual(typeof value, 'number'); + assert.ok(value >= 0); + } + + // Total count across buckets equals histogram count + let total = 0; + for (const [, count] of buckets) total += count; + assert.strictEqual(total, h.count); + + // Validation + assert.throws(() => h.logBuckets(0, 2), { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => h.logBuckets(-1, 2), { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => h.logBuckets(1, 1), { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => h.logBuckets(1, 0.5), { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => h.logBuckets(1, -2), { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => h.logBuckets('hello', 2), + { code: 'ERR_INVALID_ARG_TYPE' }); + assert.throws(() => h.logBuckets(1, 'hello'), + { code: 'ERR_INVALID_ARG_TYPE' }); + assert.throws(() => h.logBuckets(1.5, 2), { code: 'ERR_OUT_OF_RANGE' }); +} + +// --------------------------------------------------------------------------- +// subtract(other) — subtract histogram counts +// --------------------------------------------------------------------------- +{ + const h1 = createHistogram(); + const h2 = createHistogram(); + + for (let i = 1; i <= 10; i++) h1.record(i); + for (let i = 1; i <= 5; i++) h2.record(i); + + const countBefore = h1.count; + h1.subtract(h2); + + // Count should decrease + assert.ok(h1.count < countBefore); + + // Subtracting from self zeros out + const h3 = createHistogram(); + for (let i = 1; i <= 10; i++) h3.record(i); + h3.subtract(h3); + assert.strictEqual(h3.count, 0); + + // Clamping: subtracting more than present doesn't go negative + const hSmall = createHistogram(); + const hBig = createHistogram(); + hSmall.record(1); + for (let i = 0; i < 100; i++) hBig.record(1); + hSmall.subtract(hBig); + assert.strictEqual(hSmall.count, 0); + + // Validation + assert.throws(() => h1.subtract('not a histogram'), + { code: 'ERR_INVALID_ARG_TYPE' }); + assert.throws(() => h1.subtract(42), + { code: 'ERR_INVALID_ARG_TYPE' }); + assert.throws(() => h1.subtract({}), + { code: 'ERR_INVALID_ARG_TYPE' }); +} + +// --------------------------------------------------------------------------- +// recordCorrected(val, expectedInterval) — coordinated omission correction +// --------------------------------------------------------------------------- +{ + // Basic recording with number args + const h = createHistogram(); + h.recordCorrected(100, 10); + assert.ok(h.count > 0); + + // Should record more values than a plain record (backfilling) + const hPlain = createHistogram(); + hPlain.record(100); + assert.ok(h.count > hPlain.count); + + // BigInt variant + const hBig = createHistogram(); + hBig.recordCorrected(100n, 10n); + assert.ok(hBig.count > 0); + + // Mixed types should throw (bigint val, number interval) + assert.throws(() => h.recordCorrected(100n, 10), + { code: 'ERR_INVALID_ARG_TYPE' }); + + // Validation: non-integer + assert.throws(() => h.recordCorrected('hello', 10), + { code: 'ERR_INVALID_ARG_TYPE' }); + assert.throws(() => h.recordCorrected(100, 'hello'), + { code: 'ERR_INVALID_ARG_TYPE' }); + + // Out of range + assert.throws(() => h.recordCorrected(0, 10), + { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => h.recordCorrected(100, 0), + { code: 'ERR_OUT_OF_RANGE' }); +} + +// --------------------------------------------------------------------------- +// ERR_INVALID_THIS for all new methods on wrong receiver +// --------------------------------------------------------------------------- +{ + const { Histogram } = require('internal/histogram'); + const h = createHistogram(); + const wrongThis = {}; + + // Methods + const methods = [ + ['cdf', [1]], + ['ccdf', [1]], + ['countAt', [1]], + ['ksTest', [h]], + ['linearBuckets', [10]], + ['logBuckets', [1, 2]], + ['percentilesAt', [[50]]], + ]; + + for (const [method, args] of methods) { + assert.throws( + () => Histogram.prototype[method].call(wrongThis, ...args), + { code: 'ERR_INVALID_THIS' }, + `${method} should throw ERR_INVALID_THIS` + ); + } + + // Getters + for (const getter of ['skewness', 'kurtosis']) { + const desc = Object.getOwnPropertyDescriptor( + Histogram.prototype, getter); + assert.throws( + () => desc.get.call(wrongThis), + { code: 'ERR_INVALID_THIS' }, + `${getter} getter should throw ERR_INVALID_THIS` + ); + } +} + +// --------------------------------------------------------------------------- +// Empty histogram edge cases +// --------------------------------------------------------------------------- +{ + const h = createHistogram(); + + assert.strictEqual(h.cdf(1), 0); + assert.strictEqual(h.ccdf(1), 1); + assert.strictEqual(h.countAt(1), 0); + assert.strictEqual(h.skewness, 0); + assert.strictEqual(h.kurtosis, 0); + + const empty2 = createHistogram(); + assert.strictEqual(h.ksTest(empty2), 0); + + const pctAt = h.percentilesAt([50, 99]); + assert.ok(pctAt instanceof Map); + assert.strictEqual(pctAt.size, 2); + + const linear = h.linearBuckets(10); + assert.ok(linear instanceof Map); + + const log = h.logBuckets(1, 2); + assert.ok(log instanceof Map); +} + +// --------------------------------------------------------------------------- +// Single-value histogram edge cases +// --------------------------------------------------------------------------- +{ + const h = createHistogram(); + h.record(42); + + assert.strictEqual(h.skewness, 0); // Needs >= 3 + assert.strictEqual(h.kurtosis, 0); // Needs >= 4 + assert.strictEqual(h.cdf(42), 1); + assert.strictEqual(h.cdf(1), 0); + assert.strictEqual(h.ccdf(42), 0); + assert.strictEqual(h.countAt(42), 1); +} + +// --------------------------------------------------------------------------- +// Fast API call tests for new methods +// --------------------------------------------------------------------------- +{ + const h = createHistogram(); + h.record(1); + h.record(100); + + // Prepare cdf and countAt methods for optimization + eval('%PrepareFunctionForOptimization(h.cdf)'); + eval('%PrepareFunctionForOptimization(h.countAt)'); + + // Warmup call + h.cdf(50); + h.countAt(1); + + // Optimize + eval('%OptimizeFunctionOnNextCall(h.cdf)'); + eval('%OptimizeFunctionOnNextCall(h.countAt)'); + + // Fast-path call + h.cdf(50); + h.countAt(1); + + if (common.isDebug) { + const { getV8FastApiCallCount } = internalBinding('debug'); + assert.strictEqual(getV8FastApiCallCount('histogram.cdf'), 1); + assert.strictEqual(getV8FastApiCallCount('histogram.countAt'), 1); + } +} diff --git a/test/parallel/test-perf-hooks-histogram-stats.js b/test/parallel/test-perf-hooks-histogram-stats.js new file mode 100644 index 000000000000..9b05a1061682 --- /dev/null +++ b/test/parallel/test-perf-hooks-histogram-stats.js @@ -0,0 +1,561 @@ +// Flags: --expose-internals --no-warnings +'use strict'; + +require('../common'); +const assert = require('assert'); +const { createHistogram } = require('perf_hooks'); + +// --------------------------------------------------------------------------- +// welchTest(other) — Welch's t-test +// --------------------------------------------------------------------------- +{ + const h1 = createHistogram(); + const h2 = createHistogram(); + + // Both empty → p-value 1 (no evidence of difference) + const empty = h1.welchTest(h2); + assert.strictEqual(empty.pValue, 1); + assert.strictEqual(empty.tStatistic, 0); + + // Identical distributions → high p-value (not significant) + for (let i = 0; i < 100; i++) { + h1.record(50 + Math.ceil(Math.random() * 10)); + h2.record(50 + Math.ceil(Math.random() * 10)); + } + const identical = h1.welchTest(h2); + assert.strictEqual(typeof identical.tStatistic, 'number'); + assert.strictEqual(typeof identical.degreesOfFreedom, 'number'); + assert.strictEqual(typeof identical.pValue, 'number'); + assert.ok(identical.pValue >= 0 && identical.pValue <= 1); + assert.ok(identical.degreesOfFreedom > 0); + assert.strictEqual(typeof identical.confidenceInterval.lower, 'number'); + assert.strictEqual(typeof identical.confidenceInterval.upper, 'number'); + assert.ok(identical.confidenceInterval.lower <= + identical.confidenceInterval.upper); + + // Very different distributions → low p-value (significant) + const hLow = createHistogram(); + const hHigh = createHistogram(); + for (let i = 0; i < 200; i++) hLow.record(10 + Math.ceil(Math.random() * 5)); + for (let i = 0; i < 200; i++) { + hHigh.record(1000 + Math.ceil(Math.random() * 5)); + } + const different = hLow.welchTest(hHigh); + assert.ok(different.pValue < 0.001, + `Expected p < 0.001, got ${different.pValue}`); + assert.ok(different.tStatistic < 0, 'hLow mean < hHigh mean → negative t'); + + // Confidence interval should not contain 0 when significant + assert.ok(different.confidenceInterval.upper < 0 || + different.confidenceInterval.lower > 0); + + // Same histogram → p-value 1 + const self = hLow.welchTest(hLow); + assert.strictEqual(self.pValue, 1); + + // Custom confidence level + const ci90 = hLow.welchTest(hHigh, { confidence: 0.90 }); + const ci99 = hLow.welchTest(hHigh, { confidence: 0.99 }); + // 99% CI should be wider than 90% CI + const width90 = ci90.confidenceInterval.upper - + ci90.confidenceInterval.lower; + const width99 = ci99.confidenceInterval.upper - + ci99.confidenceInterval.lower; + assert.ok(width99 > width90); + + // Validation + assert.throws(() => h1.welchTest('not a histogram'), + { code: 'ERR_INVALID_ARG_TYPE' }); + assert.throws(() => h1.welchTest(h2, { confidence: 0 }), + { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => h1.welchTest(h2, { confidence: 1 }), + { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => h1.welchTest(h2, { confidence: 'high' }), + { code: 'ERR_INVALID_ARG_TYPE' }); +} + +// --------------------------------------------------------------------------- +// mannWhitneyTest(other) — Mann-Whitney U test +// --------------------------------------------------------------------------- +{ + const h1 = createHistogram(); + const h2 = createHistogram(); + + // Both empty → p-value 1 + const empty = h1.mannWhitneyTest(h2); + assert.strictEqual(empty.pValue, 1); + assert.strictEqual(empty.uStatistic, 0); + assert.strictEqual(empty.zScore, 0); + + // Very different distributions → significant + const hLow = createHistogram(); + const hHigh = createHistogram(); + for (let i = 0; i < 100; i++) hLow.record(1 + Math.ceil(Math.random() * 5)); + for (let i = 0; i < 100; i++) { + hHigh.record(1000 + Math.ceil(Math.random() * 5)); + } + const result = hLow.mannWhitneyTest(hHigh); + assert.strictEqual(typeof result.uStatistic, 'number'); + assert.strictEqual(typeof result.zScore, 'number'); + assert.strictEqual(typeof result.pValue, 'number'); + assert.ok(result.pValue < 0.001, + `Expected p < 0.001, got ${result.pValue}`); + + // Same histogram → p-value 1 + const self = hLow.mannWhitneyTest(hLow); + assert.strictEqual(self.pValue, 1); + + // Identical data → high p-value + const a = createHistogram(); + const b = createHistogram(); + for (let i = 1; i <= 50; i++) { a.record(i); b.record(i); } + const same = a.mannWhitneyTest(b); + assert.ok(same.pValue > 0.05, + `Expected p > 0.05, got ${same.pValue}`); + + // Validation + assert.throws(() => h1.mannWhitneyTest('not a histogram'), + { code: 'ERR_INVALID_ARG_TYPE' }); +} + +// --------------------------------------------------------------------------- +// cohensD(other) — Cohen's d effect size +// --------------------------------------------------------------------------- +{ + const h1 = createHistogram(); + const h2 = createHistogram(); + + // Both empty → 0 + assert.strictEqual(h1.cohensD(h2), 0); + + // Same histogram → 0 + for (let i = 1; i <= 100; i++) h1.record(i); + assert.strictEqual(h1.cohensD(h1), 0); + + // Identical distributions → near 0 + const a = createHistogram(); + const b = createHistogram(); + for (let i = 0; i < 100; i++) { + const v = 50 + Math.ceil(Math.random() * 10); + a.record(v); + b.record(v); + } + assert.ok(Math.abs(a.cohensD(b)) < 0.5); + + // Very different distributions → large |d| + const hLow = createHistogram(); + const hHigh = createHistogram(); + for (let i = 0; i < 200; i++) hLow.record(8 + Math.ceil(Math.random() * 5)); + for (let i = 0; i < 200; i++) { + hHigh.record(998 + Math.ceil(Math.random() * 5)); + } + const d = hLow.cohensD(hHigh); + assert.ok(Math.abs(d) > 1.0, + `Expected |d| > 1, got ${d}`); + // hLow has lower mean → d should be negative + assert.ok(d < 0); + + // Antisymmetry: d(a,b) = -d(b,a) + const dReverse = hHigh.cohensD(hLow); + assert.ok(Math.abs(d + dReverse) < 1e-10); + + // Uniform variance → 0 + const u1 = createHistogram(); + const u2 = createHistogram(); + for (let i = 0; i < 100; i++) u1.record(5); + for (let i = 0; i < 100; i++) u2.record(5); + assert.strictEqual(u1.cohensD(u2), 0); + + // Validation + assert.throws(() => h1.cohensD('not a histogram'), + { code: 'ERR_INVALID_ARG_TYPE' }); +} + +// --------------------------------------------------------------------------- +// cliffsD(other) — Cliff's delta +// --------------------------------------------------------------------------- +{ + const h1 = createHistogram(); + const h2 = createHistogram(); + + // Both empty → 0 + assert.strictEqual(h1.cliffsD(h2), 0); + + // Same histogram → 0 + for (let i = 1; i <= 100; i++) h1.record(i); + assert.strictEqual(h1.cliffsD(h1), 0); + + // All values in h1 > all values in h2 → delta = 1 + const hHigh = createHistogram(); + const hLow = createHistogram(); + for (let i = 0; i < 100; i++) hHigh.record(1000); + for (let i = 0; i < 100; i++) hLow.record(1); + assert.strictEqual(hHigh.cliffsD(hLow), 1); + + // All values in h1 < all values in h2 → delta = -1 + assert.strictEqual(hLow.cliffsD(hHigh), -1); + + // Antisymmetry: d(a,b) = -d(b,a) + const a = createHistogram(); + const b = createHistogram(); + for (let i = 0; i < 50; i++) a.record(1 + Math.ceil(Math.random() * 100)); + for (let i = 0; i < 50; i++) { + b.record(50 + Math.ceil(Math.random() * 100)); + } + const dAB = a.cliffsD(b); + const dBA = b.cliffsD(a); + assert.ok(Math.abs(dAB + dBA) < 1e-10); + + // Range check: -1 <= delta <= 1 + assert.ok(dAB >= -1 && dAB <= 1); + + // Identical data → 0 + const x = createHistogram(); + const y = createHistogram(); + for (let i = 1; i <= 50; i++) { x.record(i); y.record(i); } + assert.strictEqual(x.cliffsD(y), 0); + + // Validation + assert.throws(() => h1.cliffsD('not a histogram'), + { code: 'ERR_INVALID_ARG_TYPE' }); +} + +// --------------------------------------------------------------------------- +// percentileCI(percentile[, options]) — percentile confidence intervals +// --------------------------------------------------------------------------- +{ + const h = createHistogram(); + + // With < 2 samples, lower/upper equal value + h.record(50); + const one = h.percentileCI(99); + assert.strictEqual(one.lower, one.value); + assert.strictEqual(one.upper, one.value); + + // Fill with enough data for a meaningful CI + for (let i = 1; i <= 1000; i++) h.record(i); + const ci = h.percentileCI(50); + assert.strictEqual(typeof ci.value, 'number'); + assert.strictEqual(typeof ci.lower, 'number'); + assert.strictEqual(typeof ci.upper, 'number'); + assert.ok(ci.lower <= ci.value, `lower ${ci.lower} <= value ${ci.value}`); + assert.ok(ci.upper >= ci.value, `upper ${ci.upper} >= value ${ci.value}`); + + // 99% CI should be wider than 90% CI + const ci90 = h.percentileCI(50, { confidence: 0.90 }); + const ci99 = h.percentileCI(50, { confidence: 0.99 }); + assert.ok((ci99.upper - ci99.lower) >= (ci90.upper - ci90.lower), + '99% CI should be at least as wide as 90% CI'); + + // Extreme percentile: p99 CI + const ci99p = h.percentileCI(99); + assert.ok(ci99p.lower <= ci99p.value); + assert.ok(ci99p.upper >= ci99p.value); + + // Constant values → CI collapses to a single value + const constant = createHistogram(); + for (let i = 0; i < 100; i++) constant.record(42); + const constCI = constant.percentileCI(50); + assert.strictEqual(constCI.lower, constCI.value); + assert.strictEqual(constCI.upper, constCI.value); + + // More samples → narrower CI + const small = createHistogram(); + const large = createHistogram(); + for (let i = 1; i <= 50; i++) { small.record(i); large.record(i); } + for (let i = 1; i <= 950; i++) large.record(i % 50 + 1); + const ciSmall = small.percentileCI(50); + const ciLarge = large.percentileCI(50); + assert.ok((ciSmall.upper - ciSmall.lower) >= (ciLarge.upper - ciLarge.lower), + 'CI should narrow with more samples'); + + // Validation + assert.throws(() => h.percentileCI(0), + { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => h.percentileCI(101), + { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => h.percentileCI('fifty'), + { code: 'ERR_INVALID_ARG_TYPE' }); + assert.throws(() => h.percentileCI(50, { confidence: 0 }), + { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => h.percentileCI(50, { confidence: 1 }), + { code: 'ERR_OUT_OF_RANGE' }); +} + +// --------------------------------------------------------------------------- +// EWMA — exponentially weighted moving average +// --------------------------------------------------------------------------- +{ + // Without halfLife, EWMA is disabled (returns 0) + const noEwma = createHistogram(); + for (let i = 1; i <= 100; i++) noEwma.record(i); + assert.strictEqual(noEwma.ewmaMean, 0); + assert.strictEqual(noEwma.ewmaStddev, 0); + + // With halfLife, EWMA tracks the smoothed mean + const h = createHistogram({ halfLife: 10 }); + assert.strictEqual(h.ewmaMean, 0); + assert.strictEqual(h.ewmaStddev, 0); + + // First record initializes the mean + h.record(100); + assert.strictEqual(h.ewmaMean, 100); + assert.strictEqual(h.ewmaStddev, 0); + + // Record the same value repeatedly — mean should stay stable + for (let i = 0; i < 50; i++) h.record(100); + assert.ok(Math.abs(h.ewmaMean - 100) < 1, + `Expected ewmaMean near 100, got ${h.ewmaMean}`); + assert.ok(h.ewmaStddev < 1, + `Expected near-zero stddev for constant input, got ${h.ewmaStddev}`); + + // Shift to a new value — mean should move towards it + const meanBefore = h.ewmaMean; + for (let i = 0; i < 100; i++) h.record(200); + assert.ok(h.ewmaMean > meanBefore, + 'EWMA mean should increase when recording larger values'); + assert.ok(Math.abs(h.ewmaMean - 200) < 5, + `Expected ewmaMean near 200, got ${h.ewmaMean}`); + + // Stddev should be small after converging + for (let i = 0; i < 100; i++) h.record(200); + assert.ok(h.ewmaStddev < 5, + `Expected small stddev after convergence, got ${h.ewmaStddev}`); + + // Reset clears EWMA state + h.reset(); + assert.strictEqual(h.ewmaMean, 0); + assert.strictEqual(h.ewmaStddev, 0); + + // Shorter halfLife reacts faster + const fast = createHistogram({ halfLife: 2 }); + const slow = createHistogram({ halfLife: 100 }); + for (let i = 0; i < 20; i++) { fast.record(100); slow.record(100); } + for (let i = 0; i < 20; i++) { fast.record(200); slow.record(200); } + // Fast should be closer to 200 than slow + assert.ok(fast.ewmaMean > slow.ewmaMean, + `fast.ewmaMean (${fast.ewmaMean}) should be > ` + + `slow.ewmaMean (${slow.ewmaMean})`); + + // toJSON includes separate EWMA fields + const j = createHistogram({ halfLife: 10, threshold: 50 }); + j.record(50); + j.record(60); + const json = j.toJSON(); + // mean/stddev are always the histogram (non-EWMA) values + assert.strictEqual(json.mean, j.mean); + assert.strictEqual(json.stddev, j.stddev); + // EWMA fields are present and match getter values + assert.strictEqual(json.ewmaMean, j.ewmaMean); + assert.strictEqual(json.ewmaStddev, j.ewmaStddev); + assert.strictEqual(json.ewmaErrorRate, j.ewmaErrorRate); + assert.ok(json.ewmaMean > 0); + assert.ok(json.ewmaErrorRate > 0); + + // toJSON still includes EWMA fields when EWMA is not enabled (all zero) + const noEwmaJson = createHistogram(); + noEwmaJson.record(50); + noEwmaJson.record(60); + const json2 = noEwmaJson.toJSON(); + assert.strictEqual(json2.mean, noEwmaJson.mean); + assert.strictEqual(json2.stddev, noEwmaJson.stddev); + assert.strictEqual(json2.ewmaMean, 0); + assert.strictEqual(json2.ewmaStddev, 0); + assert.strictEqual(json2.ewmaErrorRate, 0); + + // Validation + assert.throws(() => createHistogram({ halfLife: -1 }), + { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => createHistogram({ halfLife: 'ten' }), + { code: 'ERR_INVALID_ARG_TYPE' }); +} + +// --------------------------------------------------------------------------- +// ewmaErrorRate / burnRate — SLO error rate tracking +// --------------------------------------------------------------------------- +{ + // Without threshold, error rate is 0 + const noThreshold = createHistogram({ halfLife: 10 }); + for (let i = 0; i < 50; i++) noThreshold.record(100); + assert.strictEqual(noThreshold.ewmaErrorRate, 0); + + // Without halfLife, error rate is 0 even with threshold + const noHalfLife = createHistogram({ threshold: 50 }); + for (let i = 0; i < 50; i++) noHalfLife.record(100); + assert.strictEqual(noHalfLife.ewmaErrorRate, 0); + + // All values below threshold → error rate converges to 0 + const allGood = createHistogram({ halfLife: 10, threshold: 200 }); + for (let i = 0; i < 100; i++) allGood.record(100); + assert.ok(allGood.ewmaErrorRate < 0.01, + `Expected near-zero error rate, got ${allGood.ewmaErrorRate}`); + + // All values above threshold → error rate converges to 1 + const allBad = createHistogram({ halfLife: 10, threshold: 50 }); + for (let i = 0; i < 100; i++) allBad.record(100); + assert.ok(allBad.ewmaErrorRate > 0.99, + `Expected near-1 error rate, got ${allBad.ewmaErrorRate}`); + + // Mixed: ~50% above threshold + const mixed = createHistogram({ halfLife: 50, threshold: 50 }); + for (let i = 0; i < 500; i++) { + mixed.record(i % 2 === 0 ? 100 : 10); // Alternating above/below + } + assert.ok(mixed.ewmaErrorRate > 0.3 && mixed.ewmaErrorRate < 0.7, + `Expected ~0.5 error rate, got ${mixed.ewmaErrorRate}`); + + // burnRate calculation + const h = createHistogram({ halfLife: 10, threshold: 50 }); + for (let i = 0; i < 100; i++) h.record(100); // All exceed + // Error rate ~1.0, SLO target 0.999 → budget 0.001 → burn rate ~1000 + const rate = h.burnRate(0.999); + assert.ok(rate > 500, + `Expected high burn rate, got ${rate}`); + + // When error rate is 0, burn rate is 0 + const perfect = createHistogram({ halfLife: 10, threshold: 200 }); + for (let i = 0; i < 100; i++) perfect.record(100); + assert.ok(perfect.burnRate(0.999) < 1, + `Expected low burn rate, got ${perfect.burnRate(0.999)}`); + + // Reset clears error rate + h.reset(); + assert.strictEqual(h.ewmaErrorRate, 0); + assert.strictEqual(h.burnRate(0.999), 0); + + // burnRate validation + assert.throws(() => h.burnRate(0), + { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => h.burnRate(1), + { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => h.burnRate(NaN), + { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => h.burnRate('high'), + { code: 'ERR_INVALID_ARG_TYPE' }); + + // createHistogram threshold validation + assert.throws(() => createHistogram({ threshold: -1 }), + { code: 'ERR_OUT_OF_RANGE' }); + assert.throws(() => createHistogram({ threshold: 'high' }), + { code: 'ERR_INVALID_ARG_TYPE' }); +} + +// --------------------------------------------------------------------------- +// ERR_INVALID_THIS for all new methods on wrong receiver +// --------------------------------------------------------------------------- +{ + const { Histogram } = require('internal/histogram'); + const h = createHistogram(); + for (let i = 1; i <= 10; i++) h.record(i); + const wrongThis = {}; + + const methods = [ + ['welchTest', [h]], + ['mannWhitneyTest', [h]], + ['cohensD', [h]], + ['cliffsD', [h]], + ['percentileCI', [50]], + ['burnRate', [0.999]], + ]; + + for (const [method, args] of methods) { + assert.throws( + () => Histogram.prototype[method].call(wrongThis, ...args), + { code: 'ERR_INVALID_THIS' }, + `${method} should throw ERR_INVALID_THIS`, + ); + } + + // Getter properties + const getters = ['ewmaMean', 'ewmaStddev', 'ewmaErrorRate']; + for (const getter of getters) { + const desc = Object.getOwnPropertyDescriptor(Histogram.prototype, getter); + assert.throws( + () => desc.get.call(wrongThis), + { code: 'ERR_INVALID_THIS' }, + `${getter} should throw ERR_INVALID_THIS`, + ); + } +} + +// --------------------------------------------------------------------------- +// Undefined return when kHandle is missing native methods +// --------------------------------------------------------------------------- +{ + const { + Histogram, + kHandle, + kSkipThrow, + } = require('internal/histogram'); + const h = createHistogram(); + for (let i = 1; i <= 10; i++) h.record(i); + + // Create a histogram instance with a null handle. This passes + // isHistogram() (null !== undefined) but the optional chaining + // (this[kHandle]?.method()) short-circuits to undefined. + const stub = new Histogram(kSkipThrow); + stub[kHandle] = null; + + assert.strictEqual(stub.welchTest(h), undefined); + assert.strictEqual(stub.mannWhitneyTest(h), undefined); + assert.strictEqual(stub.percentileCI(50), undefined); + assert.strictEqual(stub.burnRate(0.999), undefined); +} + +// --------------------------------------------------------------------------- +// Fast API path coverage for EWMA getters +// --------------------------------------------------------------------------- +{ + const h = createHistogram({ halfLife: 10, threshold: 50 }); + for (let i = 1; i <= 100; i++) h.record(i); + + // Call in a tight loop to trigger V8 fast-path optimization. + function readEwma(histogram, iterations) { + let mean = 0; + let stddev = 0; + let errorRate = 0; + for (let i = 0; i < iterations; i++) { + mean = histogram.ewmaMean; + stddev = histogram.ewmaStddev; + errorRate = histogram.ewmaErrorRate; + } + return { mean, stddev, errorRate }; + } + + const result = readEwma(h, 1e4); + assert.strictEqual(typeof result.mean, 'number'); + assert.ok(result.mean > 0); + assert.strictEqual(typeof result.stddev, 'number'); + assert.ok(result.stddev > 0); + assert.strictEqual(typeof result.errorRate, 'number'); + assert.ok(result.errorRate > 0); +} + +// --------------------------------------------------------------------------- +// Cross-consistency: when welchTest is significant, cohensD should +// indicate a non-trivial effect, and cliffsD should agree on direction. +// --------------------------------------------------------------------------- +{ + const baseline = createHistogram(); + const regressed = createHistogram(); + for (let i = 0; i < 500; i++) { + baseline.record(10 + Math.ceil(Math.random() * 20)); + } + for (let i = 0; i < 500; i++) { + regressed.record(50 + Math.ceil(Math.random() * 20)); + } + + const welch = baseline.welchTest(regressed); + const d = baseline.cohensD(regressed); + const cliff = baseline.cliffsD(regressed); + + // Should be highly significant + assert.ok(welch.pValue < 0.001); + // Cohen's d should indicate a large effect (|d| > 0.8) + assert.ok(Math.abs(d) > 0.8); + // Cliff's delta should indicate baseline < regressed + assert.ok(cliff < -0.5); + // All three agree on the direction + assert.ok(d < 0); // Baseline mean < regressed mean + assert.ok(welch.tStatistic < 0); +} diff --git a/test/parallel/test-permission-has.js b/test/parallel/test-permission-has.js index 36a02aeba4f1..2a24800aaa33 100644 --- a/test/parallel/test-permission-has.js +++ b/test/parallel/test-permission-has.js @@ -30,6 +30,7 @@ const assert = require('assert'); assert.ok(!process.permission.has('fs')); assert.ok(process.permission.has('fs.read')); assert.ok(!process.permission.has('fs.write')); + assert.ok(!process.permission.has('openssl.store')); assert.ok(!process.permission.has('wasi')); assert.ok(!process.permission.has('worker')); assert.ok(!process.permission.has('inspector')); diff --git a/test/parallel/test-permission-linked-binding-drop.js b/test/parallel/test-permission-linked-binding-drop.js new file mode 100644 index 000000000000..865761a2bd7e --- /dev/null +++ b/test/parallel/test-permission-linked-binding-drop.js @@ -0,0 +1,19 @@ +// Flags: --permission --allow-addons --allow-fs-read=* +'use strict'; + +const common = require('../common'); +const assert = require('node:assert'); + +assert.strictEqual(process.permission.has('addon'), true); + +process.permission.drop('addon'); + +assert.strictEqual(process.permission.has('addon'), false); + +assert.throws(() => { + process._linkedBinding('missing'); +}, common.expectsError({ + code: 'ERR_ACCESS_DENIED', + permission: 'Addon', + resource: 'missing', +})); diff --git a/test/parallel/test-permission-linked-binding.js b/test/parallel/test-permission-linked-binding.js new file mode 100644 index 000000000000..b30ea9aaa24b --- /dev/null +++ b/test/parallel/test-permission-linked-binding.js @@ -0,0 +1,15 @@ +// Flags: --permission --allow-fs-read=* +'use strict'; + +const common = require('../common'); +const assert = require('node:assert'); + +assert.strictEqual(process.permission.has('addon'), false); + +assert.throws(() => { + process._linkedBinding('missing'); +}, common.expectsError({ + code: 'ERR_ACCESS_DENIED', + permission: 'Addon', + resource: 'missing', +})); diff --git a/test/parallel/test-permission-openssl-store.js b/test/parallel/test-permission-openssl-store.js new file mode 100644 index 000000000000..ca2f240a9520 --- /dev/null +++ b/test/parallel/test-permission-openssl-store.js @@ -0,0 +1,93 @@ +// Flags: --permission --allow-fs-read=* --allow-fs-write=* --allow-openssl-store --allow-child-process +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const { hasOpenSSL3 } = require('../common/crypto'); +if (!hasOpenSSL3) + common.skip('requires OpenSSL 3.x'); + +// Verifies the openssl.store permission: allowed when --allow-openssl-store is +// set, can be dropped at runtime, and denied by default in a child process. + +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const fs = require('fs'); +const path = require('path'); +const { pathToFileURL } = require('url'); +const { createPrivateKey, generateKeyPairSync } = require('crypto'); +const { spawnSync } = require('child_process'); +const tmpdir = require('../common/tmpdir'); +tmpdir.refresh(); + +const file = path.join(tmpdir.path, 'priv.pem'); +fs.writeFileSync( + file, generateKeyPairSync('ed25519').privateKey.export({ + format: 'pem', type: 'pkcs8', + })); +const url = pathToFileURL(file); + +assert.strictEqual(process.permission.has('openssl.store'), true); +assert.strictEqual(createPrivateKey(url).type, 'private'); +// A plain object that merely looks like a URL is not one, so it never reaches +// a STORE loader and cannot be used to sidestep this permission. +assert.throws(() => createPrivateKey({ + href: file, + protocol: 'pkcs11:', +}), { code: 'ERR_INVALID_ARG_TYPE' }); + +process.permission.drop('openssl.store'); +assert.strictEqual(process.permission.has('openssl.store'), false); + +const secret = 'store-permission-secret'; +const messages = []; +dc.subscribe('node:permission-model:openssl-store', (message) => { + messages.push(message); +}); +assert.throws( + () => createPrivateKey(new URL(`pkcs11:object=key;pin-value=${secret}`)), + (error) => { + assert.strictEqual(error.code, 'ERR_ACCESS_DENIED'); + assert.strictEqual(error.permission, 'OpenSSLStore'); + assert.strictEqual(error.resource, ''); + assert.doesNotMatch(error.stack, new RegExp(secret)); + return true; + }); +assert.strictEqual(messages.length, 1); +assert.strictEqual(messages[0].permission, 'OpenSSLStore'); +assert.strictEqual(messages[0].resource, ''); +assert.doesNotMatch(JSON.stringify(messages[0]), new RegExp(secret)); + +// Denied by default when the flag is not provided. +{ + const { status, stdout } = spawnSync(process.execPath, [ + '--permission', '--allow-fs-read=*', + '-e', `try { require('crypto').createPrivateKey(new URL(${JSON.stringify(url.href)})); console.log('LOADED'); } catch (e) { console.log(e.code, e.permission); }`, + ]); + assert.strictEqual(status, 0); + assert.match(stdout.toString(), /ERR_ACCESS_DENIED OpenSSLStore/); +} + +// openssl.store grants the STORE loader authority to access files even when +// fs.read is not granted. +{ + const { status, stdout } = spawnSync(process.execPath, [ + '--permission', '--allow-openssl-store', + '-e', `try { require('crypto').createPrivateKey(new URL(${JSON.stringify(url.href)})); console.log('LOADED'); } catch (e) { console.log(e.code, e.permission); }`, + ]); + assert.strictEqual(status, 0); + assert.match(stdout.toString(), /LOADED/); +} + +// OpenSSL tries the file loader before the loader identified by an opaque URI. +{ + const opaqueFile = 'pkcs11:priv.pem'; + fs.copyFileSync(file, path.join(tmpdir.path, opaqueFile)); + const { status, stdout } = spawnSync(process.execPath, [ + '--permission', '--allow-openssl-store', + '-e', `try { require('crypto').createPrivateKey(new URL(${JSON.stringify(opaqueFile)})); console.log('LOADED'); } catch (e) { console.log(e.code, e.permission); }`, + ], { cwd: tmpdir.path }); + assert.strictEqual(status, 0); + assert.match(stdout.toString(), /LOADED/); +} diff --git a/test/parallel/test-permission-warning-flags.js b/test/parallel/test-permission-warning-flags.js index eeb00ecd3517..2e987d79c77d 100644 --- a/test/parallel/test-permission-warning-flags.js +++ b/test/parallel/test-permission-warning-flags.js @@ -10,6 +10,7 @@ const warnFlags = [ '--allow-inspector', '--allow-wasi', '--allow-worker', + '--allow-openssl-store', ]; for (const flag of warnFlags) { diff --git a/test/parallel/test-process-execpath.js b/test/parallel/test-process-execpath.js index 0fce35e2645e..53d8f39fbf7e 100644 --- a/test/parallel/test-process-execpath.js +++ b/test/parallel/test-process-execpath.js @@ -4,7 +4,7 @@ if (common.isWindows) common.skip('symlinks are weird on windows'); const assert = require('assert'); -const child_process = require('child_process'); +const { spawnSyncAndAssert } = require('../common/child_process'); const fs = require('fs'); assert.strictEqual(process.execPath, fs.realpathSync(process.execPath)); @@ -19,8 +19,8 @@ if (process.argv[2] === 'child') { const symlinkedNode = tmpdir.resolve('symlinked-node'); fs.symlinkSync(process.execPath, symlinkedNode); - const proc = child_process.spawnSync(symlinkedNode, [__filename, 'child']); - assert.strictEqual(proc.stderr.toString(), ''); - assert.strictEqual(proc.stdout.toString(), `${process.execPath}\n`); - assert.strictEqual(proc.status, 0); + spawnSyncAndAssert(symlinkedNode, [__filename, 'child'], { + stdout: `${process.execPath}\n`, + stderr: '' + }); } diff --git a/test/parallel/test-quic-h3-callback-errors.mjs b/test/parallel/test-quic-h3-callback-errors.mjs index f4a9477ca873..be8ed391b8d5 100644 --- a/test/parallel/test-quic-h3-callback-errors.mjs +++ b/test/parallel/test-quic-h3-callback-errors.mjs @@ -151,7 +151,7 @@ async function makeServer(onheadersHandler, extraOpts = {}) { ':authority': 'localhost', }, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), ontrailers: mustCall(function() { throw new Error('ontrailers sync error'); @@ -265,7 +265,7 @@ async function makeServer(onheadersHandler, extraOpts = {}) { ':authority': 'localhost', }, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); diff --git a/test/parallel/test-quic-h3-close-behavior.mjs b/test/parallel/test-quic-h3-close-behavior.mjs index d25cd50e4ef5..e3b73ce9b0b9 100644 --- a/test/parallel/test-quic-h3-close-behavior.mjs +++ b/test/parallel/test-quic-h3-close-behavior.mjs @@ -62,7 +62,7 @@ const decoder = new TextDecoder(); ':authority': 'localhost', }, onheaders: mustCall((headers) => { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); @@ -74,7 +74,7 @@ const decoder = new TextDecoder(); ':authority': 'localhost', }, onheaders: mustCall((headers) => { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); diff --git a/test/parallel/test-quic-h3-concurrent-requests.mjs b/test/parallel/test-quic-h3-concurrent-requests.mjs index c81403bf1362..5bd5635008ca 100644 --- a/test/parallel/test-quic-h3-concurrent-requests.mjs +++ b/test/parallel/test-quic-h3-concurrent-requests.mjs @@ -72,7 +72,7 @@ const requests = paths.map(mustCall(async (path) => { ':authority': 'localhost', }, onheaders: mustCall((headers) => { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); headersReceived.resolve(); }), }); diff --git a/test/parallel/test-quic-h3-datagram.mjs b/test/parallel/test-quic-h3-datagram.mjs index 4d081a9f1bce..38aeb971c8fe 100644 --- a/test/parallel/test-quic-h3-datagram.mjs +++ b/test/parallel/test-quic-h3-datagram.mjs @@ -87,7 +87,7 @@ const decoder = new TextDecoder(); ':authority': 'localhost', }, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); @@ -151,7 +151,7 @@ const decoder = new TextDecoder(); ':authority': 'localhost', }, onheaders: mustCall((headers) => { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); diff --git a/test/parallel/test-quic-h3-error-codes.mjs b/test/parallel/test-quic-h3-error-codes.mjs index cd5c9ff0a25a..3a91a2e8f056 100644 --- a/test/parallel/test-quic-h3-error-codes.mjs +++ b/test/parallel/test-quic-h3-error-codes.mjs @@ -55,7 +55,7 @@ const decoder = new TextDecoder(); ':authority': 'localhost', }, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); @@ -106,7 +106,7 @@ const decoder = new TextDecoder(); ':authority': 'localhost', }, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); diff --git a/test/parallel/test-quic-h3-goaway.mjs b/test/parallel/test-quic-h3-goaway.mjs index c3b6e3ae246a..bb0bf8e966c1 100644 --- a/test/parallel/test-quic-h3-goaway.mjs +++ b/test/parallel/test-quic-h3-goaway.mjs @@ -78,7 +78,7 @@ dc.subscribe('quic.session.goaway', mustCall((msg) => { await clientSession.opened; const onClientHeaders = mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); if (++clientHeaderCount === 2) { bothHeadersReceived.resolve(); } diff --git a/test/parallel/test-quic-h3-header-validation.mjs b/test/parallel/test-quic-h3-header-validation.mjs index 873991a89864..a75a884c39b9 100644 --- a/test/parallel/test-quic-h3-header-validation.mjs +++ b/test/parallel/test-quic-h3-header-validation.mjs @@ -91,7 +91,7 @@ const decoder = new TextDecoder(); }, onheaders: mustCall(function(headers) { // Client should also receive lowercased response header names. - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); assert.strictEqual(headers['content-type'], 'text/html'); assert.strictEqual(headers['x-response-header'], 'ResponseValue'); @@ -148,7 +148,7 @@ const decoder = new TextDecoder(); ':authority': 'localhost', }, onheaders: mustCall((headers) => { - assert.strictEqual(headers[':status'], '204'); + assert.strictEqual(headers[':status'], 204); }), }); diff --git a/test/parallel/test-quic-h3-informational-headers.mjs b/test/parallel/test-quic-h3-informational-headers.mjs index 1bab5b26d436..357b507ae0db 100644 --- a/test/parallel/test-quic-h3-informational-headers.mjs +++ b/test/parallel/test-quic-h3-informational-headers.mjs @@ -34,7 +34,7 @@ dc.subscribe('quic.stream.info', mustCall((msg) => { assert.ok(msg.stream, 'stream.info should include stream'); assert.ok(msg.session, 'stream.info should include session'); assert.ok(msg.headers, 'stream.info should include headers'); - assert.strictEqual(msg.headers[':status'], '103'); + assert.strictEqual(msg.headers[':status'], 103); })); // quic.stream.headers also fires for the final response headers. @@ -89,12 +89,12 @@ const stream = await clientSession.createBidirectionalStream({ ':authority': 'localhost', }, oninfo: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '103'); + assert.strictEqual(headers[':status'], 103); assert.strictEqual(headers.link, '; rel=preload; as=style'); clientInfoReceived.resolve(); }), onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); assert.strictEqual(headers['content-type'], 'text/plain'); clientHeadersReceived.resolve(); }), @@ -107,7 +107,7 @@ const body = await bytes(stream); assert.strictEqual(decoder.decode(body), responseBody); // stream.headers should return the final (initial) headers, not 1xx. -assert.strictEqual(stream.headers[':status'], '200'); +assert.strictEqual(stream.headers[':status'], 200); await Promise.all([stream.closed, serverDone.promise]); await clientSession.close(); diff --git a/test/parallel/test-quic-h3-maxstreamdata-external-buffer-failure.mjs b/test/parallel/test-quic-h3-maxstreamdata-external-buffer-failure.mjs new file mode 100644 index 000000000000..df74e4db408b --- /dev/null +++ b/test/parallel/test-quic-h3-maxstreamdata-external-buffer-failure.mjs @@ -0,0 +1,80 @@ +// Flags: --experimental-quic --experimental-stream-iter --no-warnings + +// Test: Quic maxstreamdata updates on http/3 +// Client sends a body that precisely fills the window size, +// and verifies that it is data transfer is not stalled. + +import { hasQuic, skip } from '../common/index.mjs'; +import { readFile } from 'node:fs/promises'; +import { setTimeout as sleep } from 'node:timers/promises'; + +if (!hasQuic) { + skip('QUIC is not enabled'); +} +const { listen, connect } = await import('node:quic'); +const { createPrivateKey } = await import('node:crypto'); +const { drainableProtocol } = await import('stream/iter'); + +const keys = 'test/fixtures/keys'; +const key = createPrivateKey(await readFile(`${keys}/agent1-key.pem`)); +const cert = await readFile(`${keys}/agent1-cert.pem`); + +const WINDOW = 4096; +// Fills the window exactly: HTTP/3 spends 11 of those bytes on framing (8 for +// the HEADERS frame below, 3 for the DATA frame header). The send buffer then +// empties at the same moment the window reaches zero, leaving nothing in +// flight to ack. Any other size leaves bytes queued, and the ack for those +// wakes the writer instead, hiding the bug. +const BODY = WINDOW - 11; + +let letServerRead; +const serverMayRead = new Promise((resolve) => { letServerRead = resolve; }); + +const endpoint = await listen((session) => { + session.onstream = async (stream) => { + await serverMayRead; + // eslint-disable-next-line no-unused-vars + for await (const _ of stream) { /* reading extends the window */ } + }; +}, { + sni: { '*': { keys: [key], certs: [cert] } }, + transportParams: { + initialMaxStreamDataBidiRemote: WINDOW, + initialMaxData: 1024 * 1024, + }, + onheaders() { this.sendHeaders({ ':status': '200' }); }, +}); + +const session = await connect(endpoint.address, { + servername: 'localhost', + verifyPeer: 'manual', +}); +await session.opened; + +// Budget well above the window, so the window is what stops the writer. +const stream = await session.createBidirectionalStream({ budget: 1024 * 1024 }); +stream.sendHeaders({ + ':method': 'POST', + ':path': '/', + ':scheme': 'https', + ':authority': 'localhost', +}, { terminal: false }); + +const writer = stream.writer; +writer.writeSync(new Uint8Array(BODY)); + +// Long enough for every byte to be acked. The peer acks as data arrives, +// whether or not its application has read any of it, so by now the window is +// exhausted, the send buffer is empty, and no further ACK can arrive. +await sleep(500); + +const watchdog = setTimeout(() => { + console.error('STALLED: no drain after MAX_STREAM_DATA'); + process.exit(1); +}, 5000); + +letServerRead(); // Extend the window, with no ack attached +await writer[drainableProtocol](); + +clearTimeout(watchdog); +process.exit(0); diff --git a/test/parallel/test-quic-h3-origin.mjs b/test/parallel/test-quic-h3-origin.mjs index 05e7d166585e..9f80449b6b65 100644 --- a/test/parallel/test-quic-h3-origin.mjs +++ b/test/parallel/test-quic-h3-origin.mjs @@ -77,7 +77,7 @@ const decoder = new TextDecoder(); ':authority': 'example.com', }, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); @@ -173,7 +173,7 @@ const decoder = new TextDecoder(); ':authority': 'custom-port.example.com', }, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); diff --git a/test/parallel/test-quic-h3-pending-stream.mjs b/test/parallel/test-quic-h3-pending-stream.mjs index 836c032e2b99..a6e9c8cfd912 100644 --- a/test/parallel/test-quic-h3-pending-stream.mjs +++ b/test/parallel/test-quic-h3-pending-stream.mjs @@ -64,7 +64,7 @@ const decoder = new TextDecoder(); priority: 'high', incremental: true, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); diff --git a/test/parallel/test-quic-h3-post-filehandle.mjs b/test/parallel/test-quic-h3-post-filehandle.mjs index ce6bec75c57a..a4c583463d24 100644 --- a/test/parallel/test-quic-h3-post-filehandle.mjs +++ b/test/parallel/test-quic-h3-post-filehandle.mjs @@ -76,7 +76,7 @@ writeFileSync(testFile, testContent); }, body: fh, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); clientHeadersReceived.resolve(); }), }); diff --git a/test/parallel/test-quic-h3-post-request.mjs b/test/parallel/test-quic-h3-post-request.mjs index adf874a0e8aa..c5d9635a640c 100644 --- a/test/parallel/test-quic-h3-post-request.mjs +++ b/test/parallel/test-quic-h3-post-request.mjs @@ -84,7 +84,7 @@ const stream = await clientSession.createBidirectionalStream({ }, body: encoder.encode(requestBody), onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); clientHeadersReceived.resolve(); }), }); diff --git a/test/parallel/test-quic-h3-priority.mjs b/test/parallel/test-quic-h3-priority.mjs index fcf7210b703c..10be3d6f216e 100644 --- a/test/parallel/test-quic-h3-priority.mjs +++ b/test/parallel/test-quic-h3-priority.mjs @@ -67,7 +67,7 @@ const decoder = new TextDecoder(); priority: 'high', incremental: false, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); @@ -85,7 +85,7 @@ const decoder = new TextDecoder(); priority: 'low', incremental: true, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); assert.deepStrictEqual(stream2.priority, { level: 'low', incremental: true }); @@ -99,7 +99,7 @@ const decoder = new TextDecoder(); ':authority': 'localhost', }, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); assert.deepStrictEqual(stream3.priority, { level: 'default', incremental: false }); @@ -113,7 +113,7 @@ const decoder = new TextDecoder(); ':authority': 'localhost', }, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); // Default priority initially. @@ -215,7 +215,7 @@ const decoder = new TextDecoder(); }, body: encoder.encode('signal'), onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); assert.deepStrictEqual(stream.priority, { level: 'default', incremental: false }); diff --git a/test/parallel/test-quic-h3-qpack-settings.mjs b/test/parallel/test-quic-h3-qpack-settings.mjs index e56730531c0f..f30b7163cf6b 100644 --- a/test/parallel/test-quic-h3-qpack-settings.mjs +++ b/test/parallel/test-quic-h3-qpack-settings.mjs @@ -35,7 +35,7 @@ async function makeRequest(clientSession, path) { ':authority': 'localhost', }, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); const body = await bytes(stream); diff --git a/test/parallel/test-quic-h3-request-rejected.mjs b/test/parallel/test-quic-h3-request-rejected.mjs new file mode 100644 index 000000000000..6ed987b395af --- /dev/null +++ b/test/parallel/test-quic-h3-request-rejected.mjs @@ -0,0 +1,58 @@ +// Flags: --experimental-quic --no-warnings + +// An incoming HTTP/3 request stream that is rejected without any +// application processing (here, the session has no stream consumer) is +// reset with H3_REQUEST_REJECTED (0x10b) so the peer learns the request +// was not processed. See RFC 9114 section 4.1.1. +// Refs: https://github.com/nodejs/node/issues/65441 + +import { hasQuic, skip, mustCall } from '../common/index.mjs'; +import assert from 'node:assert'; +import * as fixtures from '../common/fixtures.mjs'; + +if (!hasQuic) { + skip('QUIC is not enabled'); +} + +const { listen, connect } = await import('node:quic'); +const { createPrivateKey } = await import('node:crypto'); + +const key = createPrivateKey(fixtures.readKey('agent1-key.pem')); +const cert = fixtures.readKey('agent1-cert.pem'); + +// RFC 9114 H3_REQUEST_REJECTED. +const H3_REQUEST_REJECTED = 0x10bn; + +// The server registers no stream consumer, so an incoming request stream +// is rejected on arrival. +const serverEndpoint = await listen(mustCall((serverSession) => { + serverSession.onerror = () => {}; +}), { + sni: { '*': { keys: [key], certs: [cert] } }, +}); + +const clientSession = await connect(serverEndpoint.address, { + servername: 'localhost', + verifyPeer: 'manual', +}); +await clientSession.opened; + +const reset = Promise.withResolvers(); +const stream = await clientSession.createBidirectionalStream({ + headers: { + ':method': 'GET', + ':path': '/test', + ':scheme': 'https', + ':authority': 'localhost', + }, +}); +stream.onreset = mustCall((err) => { + assert.strictEqual(err.code, 'ERR_QUIC_APPLICATION_ERROR'); + assert.strictEqual(err.errorCode, H3_REQUEST_REJECTED); + reset.resolve(); +}); +await assert.rejects(stream.closed, { code: 'ERR_QUIC_APPLICATION_ERROR' }); + +await reset.promise; +await clientSession.close(); +await serverEndpoint.close(); diff --git a/test/parallel/test-quic-h3-request-response.mjs b/test/parallel/test-quic-h3-request-response.mjs index e359e492f753..cde16684d7e9 100644 --- a/test/parallel/test-quic-h3-request-response.mjs +++ b/test/parallel/test-quic-h3-request-response.mjs @@ -93,7 +93,7 @@ const stream = await clientSession.createBidirectionalStream({ ':authority': 'localhost', }, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); assert.strictEqual(headers['content-type'], 'text/plain'); clientHeadersReceived.resolve(); }), @@ -106,7 +106,7 @@ const body = await bytes(stream); assert.strictEqual(decoder.decode(body), responseBody); // stream.headers should return the buffered response headers. -assert.strictEqual(stream.headers[':status'], '200'); +assert.strictEqual(stream.headers[':status'], 200); await Promise.all([stream.closed, serverDone.promise]); await clientSession.close(); diff --git a/test/parallel/test-quic-h3-settings.mjs b/test/parallel/test-quic-h3-settings.mjs index 3a2bd9387f57..733d3865e872 100644 --- a/test/parallel/test-quic-h3-settings.mjs +++ b/test/parallel/test-quic-h3-settings.mjs @@ -71,7 +71,7 @@ const decoder = new TextDecoder(); 'x-second': 'two', }, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); @@ -129,7 +129,7 @@ const decoder = new TextDecoder(); 'x-long': longValue, }, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); @@ -185,7 +185,7 @@ const decoder = new TextDecoder(); ':authority': 'localhost', }, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); diff --git a/test/parallel/test-quic-h3-status-code-type.mjs b/test/parallel/test-quic-h3-status-code-type.mjs new file mode 100644 index 000000000000..a1bc7178e17a --- /dev/null +++ b/test/parallel/test-quic-h3-status-code-type.mjs @@ -0,0 +1,64 @@ +// Flags: --experimental-quic --experimental-stream-iter --no-warnings + +// Verify incoming :status is exposed as a number, matching HTTP/2 behavior. +// See https://github.com/nodejs/node/issues/63557 + +import { hasQuic, skip, mustCall } from '../common/index.mjs'; +import assert from 'node:assert'; +import * as fixtures from '../common/fixtures.mjs'; + +if (!hasQuic) { + skip('QUIC is not enabled'); +} + +const { listen, connect } = await import('node:quic'); +const { createPrivateKey } = await import('node:crypto'); + +const key = createPrivateKey(fixtures.readKey('agent1-key.pem')); +const cert = fixtures.readKey('agent1-cert.pem'); + +const codes = [200, 204, 404]; +let serverResponses = 0; +const serverDone = Promise.withResolvers(); + +const serverEndpoint = await listen(mustCall(async (ss) => { + ss.onstream = mustCall(() => { + if (++serverResponses === codes.length) { + ss.close(); + serverDone.resolve(); + } + }, codes.length); +}), { + sni: { '*': { keys: [key], certs: [cert] } }, + onheaders: mustCall(function() { + const status = codes[serverResponses - 1]; + this.sendHeaders({ ':status': String(status) }, { terminal: true }); + this.writer.endSync(); + }, codes.length), +}); + +const clientSession = await connect(serverEndpoint.address, { + servername: 'localhost', + verifyPeer: 'manual', +}); +await clientSession.opened; + +for (const expected of codes) { + const stream = await clientSession.createBidirectionalStream({ + headers: { + ':method': 'GET', + ':path': '/', + ':scheme': 'https', + ':authority': 'localhost', + }, + onheaders: mustCall(function(headers) { + assert.strictEqual(typeof headers[':status'], 'number'); + assert.strictEqual(headers[':status'], expected); + }), + }); + await stream.closed; +} + +await serverDone.promise; +await clientSession.close(); +await serverEndpoint.close(); diff --git a/test/parallel/test-quic-h3-stream-without-onstream.mjs b/test/parallel/test-quic-h3-stream-without-onstream.mjs new file mode 100644 index 000000000000..fcd5bbe019ba --- /dev/null +++ b/test/parallel/test-quic-h3-stream-without-onstream.mjs @@ -0,0 +1,244 @@ +// Flags: --experimental-quic --experimental-stream-iter --no-warnings + +// Test: incoming stream consumer checks. +// An incoming stream must not be destroyed just because `onstream` is +// not set: on a session whose application supports headers (HTTP/3), +// session-level stream callbacks (`onheaders` et al) are a consumer +// and the stream must be kept and driven by the application layer. +// Refs: https://github.com/nodejs/node/issues/64192 +// +// A session with no stream consumers at all still destroys incoming +// streams (and emits a warning), so unconsumed streams cannot +// accumulate and hold flow control credit. + +import { hasQuic, skip, mustCall, mustNotCall } from '../common/index.mjs'; +import assert from 'node:assert'; +import * as fixtures from '../common/fixtures.mjs'; + +if (!hasQuic) { + skip('QUIC is not enabled'); +} + +const { listen, connect } = await import('node:quic'); +const { createPrivateKey } = await import('node:crypto'); +const { text } = await import('stream/iter'); + +const key = createPrivateKey(fixtures.readKey('agent1-key.pem')); +const cert = fixtures.readKey('agent1-cert.pem'); + +// The consumer warning must never fire in the first block (onheaders is +// a consumer) and must fire in the second (no runnable consumer). +// common.expectWarning is not usable here: importing node:quic emits +// ExperimentalWarning, which it would reject as unexpected. +const kWarning = + 'A new stream was received but no stream consumer callback was provided'; +function failOnConsumerWarning(warning) { + assert.notStrictEqual(warning.message, kWarning); +} + +// --- An h3 request completes with only session-level stream callbacks --- +{ + process.on('warning', failOnConsumerWarning); + const serverDone = Promise.withResolvers(); + + // Note: no `onstream` callback anywhere on this session. + const serverEndpoint = await listen(mustCall((serverSession) => { + serverSession.onerror = () => {}; + }), { + sni: { '*': { keys: [key], certs: [cert] } }, + onheaders: mustCall(function(headers) { + assert.strictEqual(headers[':path'], '/test'); + this.sendHeaders({ + ':status': '200', + 'content-type': 'text/plain', + }); + const w = this.writer; + w.writeSync('kept without onstream'); + w.endSync(); + serverDone.resolve(); + }), + }); + + const clientSession = await connect(serverEndpoint.address, { + servername: 'localhost', + verifyPeer: 'manual', + }); + await clientSession.opened; + + const headersReceived = Promise.withResolvers(); + const stream = await clientSession.createBidirectionalStream({ + headers: { + ':method': 'GET', + ':path': '/test', + ':scheme': 'https', + ':authority': 'localhost', + }, + onheaders: mustCall((headers) => { + assert.strictEqual(headers[':status'], 200); + headersReceived.resolve(); + }), + }); + + await headersReceived.promise; + const body = await text(stream); + assert.strictEqual(body, 'kept without onstream'); + + await serverDone.promise; + await clientSession.close(); + await serverEndpoint.close(); + process.off('warning', failOnConsumerWarning); +} + +// --- Stream callbacks that cannot run are not a consumer --- +// On a session whose negotiated application does not support headers, +// registered session-level stream callbacks can never fire, so an +// incoming stream with no onstream callback is destroyed with the +// warning. The h3 block above must not trigger that warning. +{ + // Awaiting warned.promise is the assertion: the test times out if the + // warning never fires. + const warned = Promise.withResolvers(); + process.on('warning', function onWarning(warning) { + if (warning.message === kWarning) { + process.off('warning', onWarning); + warned.resolve(); + } + }); + + // The onheaders callback is registered but the ALPN is not h3, + // so it can never run. + const serverEndpoint = await listen(mustCall((serverSession) => { + serverSession.onerror = () => {}; + }), { + sni: { '*': { keys: [key], certs: [cert] } }, + alpn: ['test-proto'], + onheaders: () => {}, + }); + + const clientSession = await connect(serverEndpoint.address, { + servername: 'localhost', + alpn: 'test-proto', + verifyPeer: 'manual', + }); + await clientSession.opened; + + const stream = await clientSession.createUnidirectionalStream(); + stream.writer.writeSync('x'); + + await warned.promise; + await clientSession.close(); + await serverEndpoint.close(); +} + +// Session-level stream callbacks, classified by whether the application is +// guaranteed to hand every incoming stream to that callback. `onheaders` is +// invoked for every incoming h3 request stream; the others are conditional +// (`ontrailers`, `oninfo`) or outbound-only (`onwanttrailers`) and do not +// expose the stream, so registering only those is not a consumer. +const kConsumerCallbacks = ['onheaders']; +const kNonConsumerCallbacks = ['oninfo', 'ontrailers', 'onwanttrailers']; + +// --- Every session-level stream callback is classified --- +// Guard: discover the callbacks the session attaches to an incoming stream +// and assert each one is classified above, so a newly added stream callback +// trips this test until someone puts it in the right list (and, if it is a +// consumer, accepts it in QuicSession#hasStreamConsumer). +{ + // QuicStream is not exported; obtain its prototype from a stream instance, + // then offer every `on*` accessor to listen() and see which ones the + // session actually attaches to a received stream. + const bootstrap = await listen(mustCall((session) => { + session.onerror = () => {}; + }), { sni: { '*': { keys: [key], certs: [cert] } }, onstream: () => {} }); + const bootSession = await connect(bootstrap.address, { + servername: 'localhost', + verifyPeer: 'manual', + }); + await bootSession.opened; + const probeStream = await bootSession.createBidirectionalStream(); + probeStream.onerror = () => {}; + const candidates = Object.getOwnPropertyNames(Object.getPrototypeOf(probeStream)) + .filter((name) => name.startsWith('on')); + await bootSession.close(); + await bootstrap.close(); + + const probes = { __proto__: null }; + for (const name of candidates) probes[name] = () => {}; + + const applied = Promise.withResolvers(); + const serverEndpoint = await listen(mustCall((session) => { + session.onerror = () => {}; + }), { + __proto__: null, + ...probes, + sni: { '*': { keys: [key], certs: [cert] } }, + onstream: mustCall((stream) => { + applied.resolve(candidates.filter((n) => typeof stream[n] === 'function')); + }), + }); + + const clientSession = await connect(serverEndpoint.address, { + servername: 'localhost', + verifyPeer: 'manual', + }); + await clientSession.opened; + const stream = await clientSession.createBidirectionalStream({ + headers: { + ':method': 'GET', + ':path': '/test', + ':scheme': 'https', + ':authority': 'localhost', + }, + }); + stream.onerror = () => {}; + + assert.deepStrictEqual( + (await applied.promise).sort(), + [...kConsumerCallbacks, ...kNonConsumerCallbacks].sort(), + 'A session-level stream callback was added: classify it in ' + + 'kConsumerCallbacks (and accept it in QuicSession#hasStreamConsumer) ' + + 'or kNonConsumerCallbacks.'); + + await clientSession.close(); + await serverEndpoint.close(); +} + +// --- Callbacks that do not expose the stream are not a consumer --- +// A session registering only a non-consumer callback has no way to observe +// an incoming stream, so it must be destroyed with the warning. +for (const callbackName of kNonConsumerCallbacks) { + const warned = Promise.withResolvers(); + process.on('warning', function onWarning(warning) { + if (warning.message === kWarning) { + process.off('warning', onWarning); + warned.resolve(); + } + }); + + const serverEndpoint = await listen(mustCall((serverSession) => { + serverSession.onerror = () => {}; + }), { + sni: { '*': { keys: [key], certs: [cert] } }, + [callbackName]: mustNotCall(), + }); + + const clientSession = await connect(serverEndpoint.address, { + servername: 'localhost', + verifyPeer: 'manual', + }); + await clientSession.opened; + + const stream = await clientSession.createBidirectionalStream({ + headers: { + ':method': 'GET', + ':path': '/test', + ':scheme': 'https', + ':authority': 'localhost', + }, + }); + stream.onerror = () => {}; + + await warned.promise; + await clientSession.close(); + await serverEndpoint.close(); +} diff --git a/test/parallel/test-quic-h3-trailing-headers.mjs b/test/parallel/test-quic-h3-trailing-headers.mjs index e19886fa5bad..f4ffc223d4d5 100644 --- a/test/parallel/test-quic-h3-trailing-headers.mjs +++ b/test/parallel/test-quic-h3-trailing-headers.mjs @@ -94,7 +94,7 @@ const stream = await clientSession.createBidirectionalStream({ ':authority': 'localhost', }, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); clientHeadersReceived.resolve(); }), ontrailers: mustCall(function(trailers) { @@ -114,7 +114,7 @@ assert.strictEqual(decoder.decode(body), responseBody); await clientTrailersReceived.promise; // stream.headers should still be the initial headers, not trailers. -assert.strictEqual(stream.headers[':status'], '200'); +assert.strictEqual(stream.headers[':status'], 200); await Promise.all([stream.closed, serverDone.promise]); await clientSession.close(); diff --git a/test/parallel/test-quic-h3-zero-rtt-rejected-settings.mjs b/test/parallel/test-quic-h3-zero-rtt-rejected-settings.mjs index c17f2ad3994c..755bde188e0b 100644 --- a/test/parallel/test-quic-h3-zero-rtt-rejected-settings.mjs +++ b/test/parallel/test-quic-h3-zero-rtt-rejected-settings.mjs @@ -74,7 +74,7 @@ async function getTicket(endpointOptions) { ':authority': 'localhost', }, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); const body = await bytes(s); diff --git a/test/parallel/test-quic-h3-zero-rtt.mjs b/test/parallel/test-quic-h3-zero-rtt.mjs index ef51c63ee8aa..f836caa1ec4f 100644 --- a/test/parallel/test-quic-h3-zero-rtt.mjs +++ b/test/parallel/test-quic-h3-zero-rtt.mjs @@ -83,7 +83,7 @@ const s1 = await cs1.createBidirectionalStream({ ':authority': 'localhost', }, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); const body1 = await bytes(s1); @@ -111,7 +111,7 @@ const s2 = await cs2.createBidirectionalStream({ ':authority': 'localhost', }, onheaders: mustCall(function(headers) { - assert.strictEqual(headers[':status'], '200'); + assert.strictEqual(headers[':status'], 200); }), }); diff --git a/test/parallel/test-quic-maxstreamdata-external-buffer-failure.mjs b/test/parallel/test-quic-maxstreamdata-external-buffer-failure.mjs new file mode 100644 index 000000000000..79d11e05794a --- /dev/null +++ b/test/parallel/test-quic-maxstreamdata-external-buffer-failure.mjs @@ -0,0 +1,75 @@ +// Flags: --experimental-quic --experimental-stream-iter --no-warnings + +// Test: Quic maxstreamdata updates on pure quic +// Client sends a body that precisely fills the window size, +// and verifies that it is data transfer is not stalled. + +import { hasQuic, skip } from '../common/index.mjs'; +import { readFile } from 'node:fs/promises'; +import { setTimeout as sleep } from 'node:timers/promises'; + +if (!hasQuic) { + skip('QUIC is not enabled'); +} +const { listen, connect } = await import('node:quic'); +const { createPrivateKey } = await import('node:crypto'); +const { drainableProtocol } = await import('stream/iter'); + +const keys = 'test/fixtures/keys'; +const key = createPrivateKey(await readFile(`${keys}/agent1-key.pem`)); +const cert = await readFile(`${keys}/agent1-cert.pem`); + +const WINDOW = 4096; +// Fills the window exactly: HTTP/3 spends 11 of those bytes on framing (8 for +// the HEADERS frame below, 3 for the DATA frame header). The send buffer then +// empties at the same moment the window reaches zero, leaving nothing in +// flight to ack. Any other size leaves bytes queued, and the ack for those +// wakes the writer instead, hiding the bug. +const BODY = WINDOW; + +let letServerRead; +const serverMayRead = new Promise((resolve) => { letServerRead = resolve; }); + +const endpoint = await listen((session) => { + session.onstream = async (stream) => { + await serverMayRead; + // eslint-disable-next-line no-unused-vars + for await (const _ of stream) { /* reading extends the window */ } + }; +}, { + alpn: 'foo', + sni: { '*': { keys: [key], certs: [cert] } }, + transportParams: { + initialMaxStreamDataBidiRemote: WINDOW, + initialMaxData: 1024 * 1024, + } +}); + +const session = await connect(endpoint.address, { + servername: 'localhost', + verifyPeer: 'manual', + alpn: 'foo' +}); +await session.opened; + +// Budget well above the window, so the window is what stops the writer. +const stream = await session.createBidirectionalStream({ budget: 1024 * 1024 }); + +const writer = stream.writer; +writer.writeSync(new Uint8Array(BODY)); + +// Long enough for every byte to be acked. The peer acks as data arrives, +// whether or not its application has read any of it, so by now the window is +// exhausted, the send buffer is empty, and no further ACK can arrive. +await sleep(500); + +const watchdog = setTimeout(() => { + console.error('STALLED: no drain after MAX_STREAM_DATA'); + process.exit(1); +}, 5000); + +letServerRead(); // Extend the window, with no ack attached +await writer[drainableProtocol](); + +clearTimeout(watchdog); +process.exit(0); diff --git a/test/parallel/test-quic-stream-stop-sending-buffered.mjs b/test/parallel/test-quic-stream-stop-sending-buffered.mjs new file mode 100644 index 000000000000..1d41635b4575 --- /dev/null +++ b/test/parallel/test-quic-stream-stop-sending-buffered.mjs @@ -0,0 +1,49 @@ +// Flags: --experimental-quic --no-warnings + +// A peer STOP_SENDING must unschedule buffered outbound data. + +import { hasQuic, mustCall, skip } from '../common/index.mjs'; +import assert from 'node:assert'; + +if (!hasQuic) { + skip('QUIC is not enabled'); +} + +const { connect, listen } = await import('../common/quic.mjs'); + +const serverStreamReady = Promise.withResolvers(); +const clientBuffered = Promise.withResolvers(); +const serverReset = Promise.withResolvers(); + +const serverEndpoint = await listen(mustCall((serverSession) => { + serverSession.onstream = mustCall(async (stream) => { + serverStreamReady.resolve(); + await clientBuffered.promise; + + const closed = assert.rejects(stream.closed, { + code: 'ERR_QUIC_APPLICATION_ERROR', + }); + stream.stopSending(1n); + stream.writer.endSync(); + await closed; + serverSession.close(); + serverReset.resolve(); + }); +})); + +const clientSession = await connect(serverEndpoint.address); +await clientSession.opened; + +const stream = await clientSession.createBidirectionalStream(); +const clientClosed = stream.closed.catch(() => {}); +const writer = stream.writer; +writer.writeSync(new Uint8Array([1])); +await serverStreamReady.promise; + +writer.writeSync(new Uint8Array(64 * 1024)); +clientBuffered.resolve(); + +await serverReset.promise; + +await Promise.all([clientClosed, clientSession.closed]); +await serverEndpoint.close(); diff --git a/test/parallel/test-quic-stream-writer-drain-unhandled-rejection.mjs b/test/parallel/test-quic-stream-writer-drain-unhandled-rejection.mjs new file mode 100644 index 000000000000..6420de02ba95 --- /dev/null +++ b/test/parallel/test-quic-stream-writer-drain-unhandled-rejection.mjs @@ -0,0 +1,78 @@ +// Flags: --experimental-quic --experimental-stream-iter --no-warnings + +// Regression test for https://github.com/nodejs/node/issues/64290 +// When a stream writer has a pending drain promise and the remote peer +// resets the stream, the rejected drain promise must NOT surface as an +// unhandled rejection. + +import { hasQuic, skip, mustCall, mustNotCall } from '../common/index.mjs'; +import assert from 'node:assert'; +import { setImmediate as tick } from 'node:timers/promises'; + +if (!hasQuic) { + skip('QUIC is not enabled'); +} + +const { listen, connect } = await import('../common/quic.mjs'); +const { drainableProtocol } = await import('stream/iter'); + +// The test fails if any unhandled rejection fires. +process.on('unhandledRejection', + mustNotCall('unexpected unhandled rejection')); + +const serverStreamReady = Promise.withResolvers(); + +const serverEndpoint = await listen(mustCall((serverSession) => { + serverSession.onstream = mustCall((stream) => { + serverStreamReady.resolve({ stream, session: serverSession }); + }); +})); + +const clientSession = await connect(serverEndpoint.address); +await clientSession.opened; + +const stream = await clientSession.createBidirectionalStream(); +const writer = stream.writer; + +// Write a small initial chunk so the server materializes the stream. +writer.writeSync(new Uint8Array([1])); + +const { stream: serverStream, session: serverSession } = + await serverStreamReady.promise; + +// Fill the write buffer to create backpressure. After this, +// writeDesiredSize should be <= 0 and canWrite should be false. +const chunk = new Uint8Array(64 * 1024); +while (writer.canWrite) { + if (!writer.writeSync(chunk)) break; +} + +// Create a drain wakeup via the drainable protocol. This simulates +// what the stream/iter infrastructure does when checking for +// backpressure. We deliberately do NOT await the returned promise — +// that is the whole point of the test. +const drainPromise = writer[drainableProtocol](); +assert.ok(drainPromise instanceof Promise, + 'expected a drain promise (buffer should be full)'); + +// Suppress the expected rejection on both sides' closed promises so +// they do not interfere with the unhandledRejection check. +const clientClosed = stream.closed.catch(() => {}); +const serverClosed = serverStream.closed.catch(() => {}); + +// Have the server send STOP_SENDING. This triggers kStopSending on +// the client writer, which rejects the unobserved drain promise. +// Without the fix this surfaces as an unhandled rejection. +serverStream.stopSending(1n); +serverStream.writer.endSync(); + +// Give the event loop time to process the frame and fire any +// unhandled-rejection events. +await tick(); +await tick(); + +// Clean up. +await Promise.all([clientClosed, serverClosed]); +serverSession.close(); +await clientSession.close(); +await serverEndpoint.close(); diff --git a/test/parallel/test-repl-history-load-preserves-pending-entries.js b/test/parallel/test-repl-history-load-preserves-pending-entries.js new file mode 100644 index 000000000000..01e025f4267e --- /dev/null +++ b/test/parallel/test-repl-history-load-preserves-pending-entries.js @@ -0,0 +1,64 @@ +'use strict'; + +// Lines can be evaluated while the history file is still being loaded +// asynchronously by `setupHistory()`, e.g. when the input stream does not +// support pausing. Entries added to the in-memory history in the meantime +// must not be discarded once the file load completes. +// Refs: https://github.com/nodejs/node/issues/64508 + +const common = require('../common'); +const assert = require('assert'); +const fs = require('fs'); +const stream = require('stream'); +const repl = require('repl'); + +if (process.env.TERM === 'dumb') { + common.skip('skipping - dumb terminal'); +} + +common.skipIfInspectorDisabled(); + +const tmpdir = require('../common/tmpdir'); +tmpdir.refresh(); + +const historyPath = tmpdir.resolve('.repl_history'); +fs.writeFileSync(historyPath, 'persisted entry'); + +// An input stream that, unlike a TTY, does not buffer data while paused. +class FakeInput extends stream.Stream { + resume() {} + pause() {} +} +FakeInput.prototype.readable = true; + +const input = new FakeInput(); +const output = new stream.Writable({ + write(chunk, encoding, callback) { + callback(); + }, +}); + +const r = repl.start({ + input, + output, + prompt: '', + terminal: true, + useColors: false, +}); + +r.setupHistory(historyPath, common.mustSucceed(() => { + // The lines evaluated while the history file was being read must be kept, + // newest first, followed by the persisted entries. + assert.deepStrictEqual( + r.history, + ['const b = 2', 'const a = 1', 'persisted entry'], + ); + assert.strictEqual( + fs.readFileSync(historyPath, 'utf8'), + 'const b = 2\nconst a = 1\npersisted entry', + ); + r.close(); +})); + +// Evaluated synchronously, before the history file has been read. +input.emit('data', 'const a = 1\nconst b = 2\n'); diff --git a/test/parallel/test-runner-coverage-default-exclusion.mjs b/test/parallel/test-runner-coverage-default-exclusion.mjs index 44e5f7600d32..f6080612a37c 100644 --- a/test/parallel/test-runner-coverage-default-exclusion.mjs +++ b/test/parallel/test-runner-coverage-default-exclusion.mjs @@ -16,6 +16,16 @@ async function setupFixtures() { await cp(fixtureDir, tmpdir.path, { recursive: true }); } +function assertDefaultExclusions(stdout) { + assert.match(stdout, /# start of coverage report/); + assert.doesNotMatch(stdout, /# file-test\.js\s+\|/); + assert.doesNotMatch(stdout, /# file\.test\.mjs\s+\|/); + assert.doesNotMatch(stdout, /# file\.test\.ts\s+\|/); + assert.doesNotMatch(stdout, /# test\.cjs\s+\|/); + assert.doesNotMatch(stdout, /#\s+not-matching-test-name\.js\s+\|/); + assert.match(stdout, /# end of coverage report/); +} + describe('test runner coverage default exclusion', skipIfNoInspector, () => { before(async () => { await setupFixtures(); @@ -58,18 +68,6 @@ describe('test runner coverage default exclusion', skipIfNoInspector, () => { }); it('should exclude test files from coverage by default', async () => { - const report = [ - '# start of coverage report', - '# --------------------------------------------------------------', - '# file | line % | branch % | funcs % | uncovered lines', - '# --------------------------------------------------------------', - '# logic-file.js | 66.67 | 100.00 | 50.00 | 5-7', - '# --------------------------------------------------------------', - '# all files | 66.67 | 100.00 | 50.00 | ', - '# --------------------------------------------------------------', - '# end of coverage report', - ].join('\n'); - const args = [ '--no-experimental-strip-types', '--test', @@ -82,23 +80,11 @@ describe('test runner coverage default exclusion', skipIfNoInspector, () => { }); assert.strictEqual(result.stderr.toString(), ''); - assert(result.stdout.toString().includes(report)); + assertDefaultExclusions(result.stdout.toString()); assert.strictEqual(result.status, 0); }); it('should exclude ts test files', async () => { - const report = [ - '# start of coverage report', - '# --------------------------------------------------------------', - '# file | line % | branch % | funcs % | uncovered lines', - '# --------------------------------------------------------------', - '# logic-file.js | 66.67 | 100.00 | 50.00 | 5-7', - '# --------------------------------------------------------------', - '# all files | 66.67 | 100.00 | 50.00 | ', - '# --------------------------------------------------------------', - '# end of coverage report', - ].join('\n'); - const args = [ '--test', '--experimental-test-coverage', @@ -111,7 +97,26 @@ describe('test runner coverage default exclusion', skipIfNoInspector, () => { }); assert.strictEqual(result.stderr.toString(), ''); - assert(result.stdout.toString().includes(report)); + assertDefaultExclusions(result.stdout.toString()); + assert.strictEqual(result.status, 0); + }); + + it('should exclude dotfile test files from coverage by default', async () => { + const args = [ + '--no-experimental-strip-types', + '--test', + '--experimental-test-coverage', + '--test-reporter=tap', + 'test/.dotfile.cjs', + ]; + const result = spawnSync(process.execPath, args, { + env: { ...process.env, NODE_TEST_TMPDIR: tmpdir.path }, + cwd: tmpdir.path + }); + + assert.strictEqual(result.stderr.toString(), ''); + assertDefaultExclusions(result.stdout.toString()); + assert.doesNotMatch(result.stdout.toString(), /#\s+\.dotfile\.cjs\s+\|/); assert.strictEqual(result.status, 0); }); }); diff --git a/test/parallel/test-runner-coverage-thresholds.js b/test/parallel/test-runner-coverage-thresholds.js index e45e1191299c..2742464adf64 100644 --- a/test/parallel/test-runner-coverage-thresholds.js +++ b/test/parallel/test-runner-coverage-thresholds.js @@ -170,4 +170,25 @@ for (const coverage of coverages) { assert.strictEqual(result.status, 1); assert(!findCoverageFileForPid(result.pid)); }); + + test(`test failing ${coverage.flag} with dot reporter`, () => { + const result = spawnSync(process.execPath, [ + '--test', + '--experimental-test-coverage', + '--test-coverage-exclude=!test/**', + `${coverage.flag}=99`, + '--test-reporter', 'dot', + fixture, + ]); + + const stdout = result.stdout.toString(); + assert.match( + stdout, + RegExp(`Error: ${coverage.actual.toFixed(2)}% ${coverage.name} coverage does not meet threshold of 99%`) + ); + assert.match(stdout, /start of coverage report/); + assert.match(stdout, /end of coverage report/); + assert.strictEqual(result.status, 1); + assert(!findCoverageFileForPid(result.pid)); + }); } diff --git a/test/parallel/test-runner-mock-dual-package.js b/test/parallel/test-runner-mock-dual-package.js new file mode 100644 index 000000000000..f96837d2cebf --- /dev/null +++ b/test/parallel/test-runner-mock-dual-package.js @@ -0,0 +1,36 @@ +'use strict'; +const common = require('../common'); +const { isMainThread } = require('worker_threads'); + +if (!isMainThread) { + common.skip('registering customization hooks in Workers does not work'); +} + +const fixtures = require('../common/fixtures'); +const assert = require('node:assert'); +const { test } = require('node:test'); + +// Regression test for https://github.com/nodejs/node/issues/58231 +// When a dual package exposes both ESM and CJS entry points via the +// "exports" field with "import"/"require" conditions, the ESM resolver +// picks one file (e.g. index.js) and CJS require() picks another +// (e.g. index.cjs). mock.module() must intercept both so that require() +// of the mocked module does not return the original CJS file. +test('mock.module intercepts dual package require with conditional exports', + async () => { + const cwd = fixtures.path('test-runner'); + const fixture = fixtures.path('test-runner', 'mock-nm-dual-pkg.js'); + const args = ['--experimental-test-module-mocks', fixture]; + const { + code, + stdout, + signal, + } = await common.spawnPromisified(process.execPath, args, { cwd }); + + assert.strictEqual(signal, null); + assert.strictEqual(code, 0, + 'child process exited with non-zero status\n' + + `stdout:\n${stdout}`); + assert.match(stdout, /pass 1/); + assert.match(stdout, /fail 0/); + }); diff --git a/test/parallel/test-runner-mock-timers-with-timeout.js b/test/parallel/test-runner-mock-timers-with-timeout.js index 67f266851fe1..6d98e6e9479a 100644 --- a/test/parallel/test-runner-mock-timers-with-timeout.js +++ b/test/parallel/test-runner-mock-timers-with-timeout.js @@ -1,14 +1,12 @@ 'use strict'; require('../common'); const fixtures = require('../common/fixtures'); -const assert = require('node:assert'); -const { spawnSync } = require('node:child_process'); +const { spawnSyncAndExitWithoutError } = require('../common/child_process'); const { test } = require('node:test'); test('mock timers do not break test timeout cleanup', async () => { const fixture = fixtures.path('test-runner', 'mock-timers-with-timeout.js'); - const cp = spawnSync(process.execPath, ['--test', fixture], { + spawnSyncAndExitWithoutError(process.execPath, ['--test', fixture], { timeout: 30_000, }); - assert.strictEqual(cp.status, 0, `Test failed:\nstdout: ${cp.stdout}\nstderr: ${cp.stderr}`); }); diff --git a/test/parallel/test-runner-reporters.js b/test/parallel/test-runner-reporters.js index 7fed79d45b48..a2f6316a84fe 100644 --- a/test/parallel/test-runner-reporters.js +++ b/test/parallel/test-runner-reporters.js @@ -207,7 +207,7 @@ describe('node:test reporters', { concurrency: true }, () => { assert.match(timestamp, /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/); assert.ok(!Number.isNaN(Date.parse(timestamp)), `expected a valid date, got ${timestamp}`); assert.match(fileContents, /\s*/); - assert.match(fileContents, //); + assert.match(fileContents, //); assert.match(fileContents, //); }); }); diff --git a/test/parallel/test-runner-run.mjs b/test/parallel/test-runner-run.mjs index 3e68c13a4c96..947da4a77d8b 100644 --- a/test/parallel/test-runner-run.mjs +++ b/test/parallel/test-runner-run.mjs @@ -675,6 +675,14 @@ describe('require(\'node:test\').run', { concurrency: true }, () => { })); }); + it('should only allow object in options.env', () => { + [Symbol(), [], () => {}, 0, 1, 0n, 1n, '', '1', true, false] + .forEach((env) => assert.throws(() => run({ files: [], env }), { + code: 'ERR_INVALID_ARG_TYPE', + message: /The "options\.env" property must be of type object\./ + })); + }); + it('should not allow files and globPatterns used together', () => { assert.throws(() => run({ files: ['a.js'], globPatterns: ['*.js'] }), { code: 'ERR_INVALID_ARG_VALUE' @@ -864,6 +872,48 @@ describe('forceExit', () => { }); }); +describe('with isolation="none"', () => { + const isolationNoneFixture = fixtures.path('test-runner', 'test-runner-isolation-none.mjs'); + + it('should pass only to children', async () => { + const child = await common.spawnPromisified(process.execPath, [ + isolationNoneFixture, + '--file', join(testFixtures, 'test_only.js'), + '--only', + ]); + + assert.strictEqual(child.stderr, ''); + assert.strictEqual(child.code, 0); + assert.match(child.stdout, /ok 1 - this should be executed/); + assert.match(child.stdout, /# tests 1/); + }); + + it('should skip tests not matching testNamePatterns - RegExp', async () => { + const child = await common.spawnPromisified(process.execPath, [ + isolationNoneFixture, + '--file', join(testFixtures, 'default-behavior/test/skip_by_name.cjs'), + '--name-pattern', 'executed', + ]); + + assert.strictEqual(child.stderr, ''); + assert.strictEqual(child.code, 0); + assert.match(child.stdout, /ok 1 - this should be executed/); + assert.match(child.stdout, /# tests 1/); + }); + + it('should skip tests matching testSkipPatterns - RegExp', async () => { + const child = await common.spawnPromisified(process.execPath, [ + isolationNoneFixture, + '--file', join(testFixtures, 'default-behavior/test/skip_by_name.cjs'), + '--skip-pattern', 'skipped', + ]); + + assert.strictEqual(child.stderr, ''); + assert.strictEqual(child.code, 0); + assert.match(child.stdout, /ok 1 - this should be executed/); + assert.match(child.stdout, /# tests 1/); + }); +}); // exitHandler doesn't run until after the tests / after hooks finish. process.on('exit', () => { diff --git a/test/parallel/test-runner-tags-events.mjs b/test/parallel/test-runner-tags-events.mjs index 51d578a41ddd..9bf5ebf3e617 100644 --- a/test/parallel/test-runner-tags-events.mjs +++ b/test/parallel/test-runner-tags-events.mjs @@ -87,9 +87,6 @@ describe('tag-bearing event payloads', { concurrency: false }, () => { }); it('test:pass fires only for selected tagged tests when filtered', async () => { - // isolation='none' so the parent applies the filter directly. Under - // 'process', the FileTest wrapper (which has no tags) would itself be - // filtered out by the include filter - same wart as --test-name-pattern. const stream = run({ files: [fixture], testTagFilters: ['db'], isolation: 'none' }); stream.on('test:fail', common.mustNotCall()); // 3 db-tagged tests pass + the db suite itself. @@ -97,4 +94,15 @@ describe('tag-bearing event payloads', { concurrency: false }, () => { // eslint-disable-next-line no-unused-vars for await (const _ of stream); }); + + it('filtering under process isolation runs the file and filters inside it', async () => { + // The FileTest wrapper has no tags and must not be filtered out itself; + // the filter is re-emitted to the child process and applied there. + const stream = run({ files: [fixture], testTagFilters: ['db'], isolation: 'process' }); + stream.on('test:fail', common.mustNotCall()); + // 3 db-tagged tests pass + the db suite itself. + stream.on('test:pass', common.mustCall(4)); + // eslint-disable-next-line no-unused-vars + for await (const _ of stream); + }); }); diff --git a/test/parallel/test-sqlite-backup.mjs b/test/parallel/test-sqlite-backup.mjs index 80061ee6601d..d1e09569e1ca 100644 --- a/test/parallel/test-sqlite-backup.mjs +++ b/test/parallel/test-sqlite-backup.mjs @@ -124,6 +124,15 @@ describe('backup()', () => { message: 'The "options.rate" argument must be an integer.' }); + for (const rate of [0, -1]) { + t.assert.throws(() => { + backup(database, 'hello.db', { rate }); + }, { + code: 'ERR_OUT_OF_RANGE', + message: 'The "options.rate" argument must be a positive integer.' + }); + } + t.assert.throws(() => { backup(database, 'hello.db', { progress: 'invalid' diff --git a/test/parallel/test-sqlite-data-types.js b/test/parallel/test-sqlite-data-types.js index 26af15a777d2..bc4cd1ab5183 100644 --- a/test/parallel/test-sqlite-data-types.js +++ b/test/parallel/test-sqlite-data-types.js @@ -80,6 +80,15 @@ suite('data binding and mapping', () => { text: '', buf: new Uint8Array(), }); + + t.assert.deepStrictEqual( + stmt.run(5, true, false, true, null), + { changes: 1, lastInsertRowid: 5 } + ); + t.assert.deepStrictEqual( + query.get(5), + { __proto__: null, key: 5, int: 1, double: 0, text: '1', buf: null } + ); }); test('large strings are bound correctly', (t) => { diff --git a/test/parallel/test-sqlite-database-sync.js b/test/parallel/test-sqlite-database-sync.js index af7677a3cfc0..08a636c9cbdc 100644 --- a/test/parallel/test-sqlite-database-sync.js +++ b/test/parallel/test-sqlite-database-sync.js @@ -397,6 +397,32 @@ suite('DatabaseSync.prototype.prepare()', () => { message: /The "sql" argument must be a string/, }); }); + + test('throws if sql contains no statements', (t) => { + using db = new DatabaseSync(nextDb()); + + for (const sql of ['', ' ', ';', '-- comment', '/* comment */']) { + t.assert.throws(() => { + db.prepare(sql); + }, { + code: 'ERR_INVALID_ARG_VALUE', + message: /contains no statements/, + }); + } + }); + + test('prepares statements that contain comments', (t) => { + using db = new DatabaseSync(nextDb()); + const queries = [ + '-- lead\nSELECT 1 AS v', + 'SELECT 1 AS v -- trail', + 'SELECT /* mid */ 1 AS v', + ]; + + for (const sql of queries) { + t.assert.strictEqual(db.prepare(sql).get().v, 1); + } + }); }); suite('DatabaseSync.prototype.exec()', () => { diff --git a/test/parallel/test-sqlite-session.js b/test/parallel/test-sqlite-session.js index c36b4352a341..5faea802ccd5 100644 --- a/test/parallel/test-sqlite-session.js +++ b/test/parallel/test-sqlite-session.js @@ -605,6 +605,28 @@ test('session.close() - closing twice', (t) => { }); }); +test('session.close() - while generating changes throws exception', (t) => { + for (const method of ['changeset', 'patchset']) { + const database = new DatabaseSync(':memory:'); + database.exec('CREATE TABLE data(key INTEGER PRIMARY KEY, value TEXT)'); + + const session = database.createSession({ table: 'data' }); + database.exec("INSERT INTO data VALUES (1, 'a'), (2, 'b'), (3, 'c')"); + database.setAuthorizer(() => { + session.close(); + return constants.SQLITE_OK; + }); + + t.assert.throws(() => session[method](), { + code: 'ERR_INVALID_STATE', + message: 'session is currently in use', + }); + + database.setAuthorizer(null); + t.assert.notStrictEqual(session[method]().length, 0); + } +}); + test('session - keeps its database alive after the db handle is dropped', async (t) => { const { gcUntil, onGC } = require('../common/gc'); diff --git a/test/parallel/test-sqlite-template-tag.js b/test/parallel/test-sqlite-template-tag.js index 1a55148cb7b4..20376e199d1b 100644 --- a/test/parallel/test-sqlite-template-tag.js +++ b/test/parallel/test-sqlite-template-tag.js @@ -90,6 +90,43 @@ test('queries with no results', () => { assert.strictEqual(count, 0); }); +test('rejects parameters outside of template expressions', () => { + const ldb = new DatabaseSync(':memory:'); + const lsql = ldb.createTagStore(); + ldb.exec(` + CREATE TABLE secrets(owner TEXT, token TEXT); + INSERT INTO secrets VALUES ('victim', 'secret'); + CREATE TABLE transfers(from_user TEXT, amount INTEGER); + `); + + const expectedError = { + code: 'ERR_INVALID_ARG_VALUE', + message: /must be bound using template literal placeholders/, + }; + + for (const method of ['get', 'all', 'iterate']) { + // Prime the cached statement with a bound value before each attempt. + // eslint-disable-next-line no-unused-expressions + lsql.all`SELECT token FROM secrets WHERE owner = ${'victim'}`; + assert.throws(() => { + // eslint-disable-next-line no-unused-expressions + lsql[method]`SELECT token FROM secrets WHERE owner = ?`; + }, expectedError); + } + + // eslint-disable-next-line no-unused-expressions + lsql.run`INSERT INTO transfers VALUES (${'victim'},${100})`; + assert.throws(() => { + // eslint-disable-next-line no-unused-expressions + lsql.run`INSERT INTO transfers VALUES (?,?)`; + }, expectedError); + assert.strictEqual( + ldb.prepare('SELECT COUNT(*) AS count FROM transfers').get().count, + 1); + + ldb.close(); +}); + test('TagStore capacity, size, and clear', () => { assert.strictEqual(sql.capacity, 10); assert.strictEqual(sql.size, 0); @@ -220,6 +257,40 @@ test('a finished iterator stays done and does not restart', () => { assert.strictEqual(iter.next().done, true); }); +test('createTagStore throws on invalid maxSize', () => { + const db = new DatabaseSync(':memory:'); + + assert.throws(() => db.createTagStore(0), { + code: 'ERR_OUT_OF_RANGE', + message: /maxSize/, + }); + + assert.throws(() => db.createTagStore(-1), { + code: 'ERR_OUT_OF_RANGE', + message: /maxSize/, + }); + + assert.throws(() => db.createTagStore(NaN), { + code: 'ERR_OUT_OF_RANGE', + message: /maxSize/, + }); + + assert.throws(() => db.createTagStore(1.5), { + code: 'ERR_OUT_OF_RANGE', + message: /maxSize/, + }); + + assert.throws(() => db.createTagStore('abc'), { + code: 'ERR_INVALID_ARG_TYPE', + message: /maxSize/, + }); + + assert.throws(() => db.createTagStore(Number.MAX_SAFE_INTEGER), { + code: 'ERR_OUT_OF_RANGE', + message: /maxSize/, + }); +}); + test('sql.db returns the associated DatabaseSync instance', () => { assert.strictEqual(sql.db, db); }); @@ -246,6 +317,29 @@ test('sql error messages are descriptive', () => { }); }); +test('rejects SQL that contains no statements', () => { + const expectedError = { + code: 'ERR_INVALID_ARG_VALUE', + message: /contains no statements/, + }; + + for (const method of ['run', 'get', 'all', 'iterate']) { + assert.throws(() => { + // eslint-disable-next-line no-unused-expressions + sql[method]`-- comment`; + }, expectedError); + + assert.throws(() => { + // eslint-disable-next-line no-unused-expressions + sql[method]``; + }, expectedError); + } + + // A rejected statement must not be cached, so a later valid query with the + // same tag store still works. + assert.strictEqual(sql.run`INSERT INTO foo (text) VALUES (${'bob'})`.changes, 1); +}); + test('a tag store keeps the database alive by itself', () => { const sql = new DatabaseSync(':memory:').createTagStore(); diff --git a/test/parallel/test-sqlite-typed-array-and-data-view.js b/test/parallel/test-sqlite-typed-array-and-data-view.js index 71d7b181a3d7..3e2b62d2d573 100644 --- a/test/parallel/test-sqlite-typed-array-and-data-view.js +++ b/test/parallel/test-sqlite-typed-array-and-data-view.js @@ -14,6 +14,10 @@ function nextDb() { } const arrayBuffer = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]).buffer; +const sharedArrayBuffer = new SharedArrayBuffer(8); +const typedArrayOnSharedArrayBuffer = new Uint8Array(sharedArrayBuffer); +typedArrayOnSharedArrayBuffer.set([1, 2, 3, 4, 5, 6, 7, 8]); + const TypedArrays = [ ['Int8Array', Int8Array], ['Uint8Array', Uint8Array], @@ -60,3 +64,68 @@ suite('StatementSync with TypedArray/DataView', () => { }); } }); + +suite('StatementSync with ArrayBuffer and SharedArrayBuffer', () => { + const buffers = [ + ['ArrayBuffer', arrayBuffer], + ['SharedArrayBuffer', sharedArrayBuffer], + ]; + + for (const [displayName, buffer] of buffers) { + test(`${displayName} - anonymous binding`, (t) => { + const db = new DatabaseSync(':memory:'); + t.after(() => { db.close(); }); + db.exec('CREATE TABLE test (data BLOB)'); + // insert + { + const stmt = db.prepare('INSERT INTO test VALUES (?)'); + stmt.run(buffer); + } + // select all + { + const stmt = db.prepare('SELECT * FROM test'); + const row = stmt.get(); + t.assert.ok(row.data instanceof Uint8Array); + t.assert.strictEqual(row.data.length, 8); + t.assert.deepStrictEqual(row.data, new Uint8Array(arrayBuffer)); + } + // query + { + const stmt = db.prepare('SELECT * FROM test WHERE data = ?'); + const rows = stmt.all(buffer); + t.assert.strictEqual(rows.length, 1); + t.assert.ok(rows[0].data instanceof Uint8Array); + t.assert.strictEqual(rows[0].data.length, 8); + t.assert.deepStrictEqual(rows[0].data, new Uint8Array(arrayBuffer)); + } + }); + + test(`${displayName} - named binding (object)`, (t) => { + const db = new DatabaseSync(':memory:'); + t.after(() => { db.close(); }); + db.exec('CREATE TABLE test (data BLOB)'); + // insert + { + const stmt = db.prepare('INSERT INTO test VALUES ($data)'); + stmt.run({ '$data': buffer }); + } + // select all + { + const stmt = db.prepare('SELECT * FROM test'); + const row = stmt.get(); + t.assert.ok(row.data instanceof Uint8Array); + t.assert.strictEqual(row.data.length, 8); + t.assert.deepStrictEqual(row.data, new Uint8Array(arrayBuffer)); + } + // query + { + const stmt = db.prepare('SELECT * FROM test WHERE data = $data'); + const rows = stmt.all({ '$data': buffer }); + t.assert.strictEqual(rows.length, 1); + t.assert.ok(rows[0].data instanceof Uint8Array); + t.assert.strictEqual(rows[0].data.length, 8); + t.assert.deepStrictEqual(rows[0].data, new Uint8Array(arrayBuffer)); + } + }); + } +}); diff --git a/test/parallel/test-stream-iter-broadcast-backpressure.js b/test/parallel/test-stream-iter-broadcast-backpressure.js index 35a0cf0e238c..698f1821aeea 100644 --- a/test/parallel/test-stream-iter-broadcast-backpressure.js +++ b/test/parallel/test-stream-iter-broadcast-backpressure.js @@ -135,15 +135,99 @@ async function testStrictBackpressureOverflow() { }); } +async function testEndDrainsPendingWrite() { + const chunk1 = new Uint8Array(16384).fill(65); // 'A' + const chunk2 = Uint8Array.of(66); // 'B' + const { writer, broadcast: bc } = broadcast({ + budget: 16384, + backpressure: 'unbounded', + }); + const iter = bc.push()[Symbol.asyncIterator](); + + await writer.write(chunk1); + const pendingWrite = writer.write(chunk2); + const endPromise = writer.end(); + + assert.strictEqual(writer.canWrite, null); + assert.strictEqual(writer.writeSync('late'), false); + await assert.rejects(writer.write('late'), { + code: 'ERR_INVALID_STATE', + }); + + const first = await iter.next(); + assert.strictEqual(first.done, false); + assert.strictEqual(first.value[0][0], 65); + await pendingWrite; + + const second = await iter.next(); + assert.strictEqual(second.done, false); + assert.strictEqual(second.value[0][0], 66); + + let endResolved = false; + endPromise.then(common.mustCall(() => { endResolved = true; })); + await new Promise(setImmediate); + assert.strictEqual(endResolved, false); + + assert.strictEqual((await iter.next()).done, true); + assert.strictEqual(await endPromise, 16385); +} + +async function testEndSyncDrainsPendingWrite() { + const chunk1 = new Uint8Array(16384).fill(65); // 'A' + const chunk2 = Uint8Array.of(66); // 'B' + const { writer, broadcast: bc } = broadcast({ + budget: 16384, + backpressure: 'unbounded', + }); + const iter = bc.push()[Symbol.asyncIterator](); + + await writer.write(chunk1); + const pendingWrite = writer.write(chunk2); + assert.strictEqual(writer.endSync(), -1); + const endPromise = writer.end(); + + assert.strictEqual((await iter.next()).value[0][0], 65); + await pendingWrite; + assert.strictEqual((await iter.next()).value[0][0], 66); + assert.strictEqual((await iter.next()).done, true); + assert.strictEqual(await endPromise, 16385); + assert.strictEqual(writer.endSync(), 16385); +} + +async function testAbortedPendingWriteAllowsEnd() { + const ac = new AbortController(); + const reason = new Error('write aborted'); + const { writer, broadcast: bc } = broadcast({ + budget: 16384, + backpressure: 'unbounded', + }); + const iter = bc.push()[Symbol.asyncIterator](); + + await writer.write(new Uint8Array(16384)); + const pendingWrite = writer.write('blocked', { signal: ac.signal }); + const writeRejected = assert.rejects( + pendingWrite, + (error) => error === reason, + ); + const endPromise = writer.end(); + + ac.abort(reason); + await writeRejected; + assert.strictEqual((await iter.next()).done, false); + assert.strictEqual((await iter.next()).done, true); + assert.strictEqual(await endPromise, 16384); +} + // Writev async path async function testWritevAsync() { const { writer, broadcast: bc } = broadcast({ budget: 16384 }); const consumer = bc.push(); await writer.writev(['hello', ' ', 'world']); + const dataPromise = text(consumer); await writer.end(); - const data = await text(consumer); + const data = await dataPromise; assert.strictEqual(data, 'hello world'); } @@ -167,15 +251,19 @@ async function testZeroByteWrites() { assert.strictEqual(entries, 0); } -// endSync returns the total byte count +// endSync falls back to end() when consumers still need to drain. async function testEndSyncReturnValue() { const { writer, broadcast: bc } = broadcast({ budget: 16384 }); - bc.push(); // Need a consumer to write to + const consumer = bc.push(); writer.writeSync('hello'); // 5 bytes writer.writeSync(' world'); // 6 bytes - const total = writer.endSync(); - assert.strictEqual(total, 11); + assert.strictEqual(writer.endSync(), -1); + + const dataPromise = text(consumer); + assert.strictEqual(await writer.end(), 11); + assert.strictEqual(await dataPromise, 'hello world'); + assert.strictEqual(writer.endSync(), 11); } Promise.all([ @@ -184,6 +272,9 @@ Promise.all([ testBlockBackpressure(), testBlockBackpressureContent(), testStrictBackpressureOverflow(), + testEndDrainsPendingWrite(), + testEndSyncDrainsPendingWrite(), + testAbortedPendingWriteAllowsEnd(), testWritevAsync(), testZeroByteWrites(), testEndSyncReturnValue(), diff --git a/test/parallel/test-stream-iter-broadcast-basic.js b/test/parallel/test-stream-iter-broadcast-basic.js index 0644a28a462d..3dbd3ce97512 100644 --- a/test/parallel/test-stream-iter-broadcast-basic.js +++ b/test/parallel/test-stream-iter-broadcast-basic.js @@ -19,13 +19,14 @@ async function testBasicBroadcast() { assert.strictEqual(bc.consumerCount, 2); - await writer.write('hello'); - await writer.end(); - - const [data1, data2] = await Promise.all([ + const dataPromise = Promise.all([ text(consumer1), text(consumer2), ]); + await writer.write('hello'); + await writer.end(); + + const [data1, data2] = await dataPromise; assert.strictEqual(data1, 'hello'); assert.strictEqual(data2, 'hello'); @@ -39,9 +40,10 @@ async function testMultipleWrites() { await writer.write('a'); await writer.write('b'); await writer.write('c'); + const dataPromise = text(consumer); await writer.end(); - const data = await text(consumer); + const data = await dataPromise; assert.strictEqual(data, 'abc'); } @@ -104,10 +106,11 @@ async function testWriterEnd() { const consumer = bc.push(); await writer.write('data'); + const dataPromise = text(consumer); const totalBytes = await writer.end(); assert.strictEqual(totalBytes, 4); // 'data' = 4 UTF-8 bytes - const data = await text(consumer); + const data = await dataPromise; assert.strictEqual(data, 'data'); } @@ -123,8 +126,59 @@ async function testWriterEndWithPreAbortedSignal() { // A rejected end must leave the writer open. await writer.write('data'); + const dataPromise = text(consumer); + assert.strictEqual(await writer.end(), 4); + assert.strictEqual(await dataPromise, 'data'); +} + +async function testWriterEndWaitsForAllConsumers() { + const { writer, broadcast: bc } = broadcast(); + const iter1 = bc.push()[Symbol.asyncIterator](); + const iter2 = bc.push()[Symbol.asyncIterator](); + + await writer.write('data'); + const endPromise = writer.end(); + let endResolved = false; + endPromise.then(common.mustCall(() => { endResolved = true; })); + + assert.strictEqual((await iter1.next()).done, false); + assert.strictEqual((await iter2.next()).done, false); + assert.strictEqual((await iter1.next()).done, true); + assert.strictEqual(endResolved, false); + + assert.strictEqual((await iter2.next()).done, true); + assert.strictEqual(await endPromise, 4); +} + +async function testWriterEndSignalDoesNotFailWriter() { + const { writer, broadcast: bc } = broadcast(); + const consumer = bc.push(); + const ac = new AbortController(); + const reason = new Error('end aborted'); + + await writer.write('data'); + const signaledEnd = writer.end({ signal: ac.signal }); + const rejected = assert.rejects(signaledEnd, (error) => error === reason); + ac.abort(reason); + await rejected; + + const dataPromise = text(consumer); assert.strictEqual(await writer.end(), 4); - assert.strictEqual(await text(consumer), 'data'); + assert.strictEqual(await dataPromise, 'data'); +} + +async function testWriterFailWhileClosing() { + const { writer, broadcast: bc } = broadcast(); + const iter = bc.push()[Symbol.asyncIterator](); + const reason = new Error('writer failed while closing'); + + await writer.write('data'); + const endPromise = writer.end(); + const endRejected = assert.rejects(endPromise, (error) => error === reason); + writer.fail(reason); + + await endRejected; + await assert.rejects(iter.next(), (error) => error === reason); } async function testWriterFail() { @@ -203,6 +257,17 @@ async function testPushAbortSignalRejectsPendingNext() { await rejected; } +async function testPushPreAbortedSignalDoesNotAddConsumer() { + const reason = new Error('already aborted'); + const signal = AbortSignal.abort(reason); + const { broadcast: bc } = broadcast(); + const iter = bc.push({ signal })[Symbol.asyncIterator](); + + assert.strictEqual(bc.consumerCount, 0); + await assert.rejects(iter.next(), (error) => error === reason); + assert.strictEqual(bc.consumerCount, 0); +} + // ============================================================================= // Writer fail detaches consumers // ============================================================================= @@ -260,15 +325,15 @@ async function testWriterFailIdempotent() { }, { message: 'fail!' }); } -// cancel() with falsy reason (0, "", false) should still treat as error async function testCancelWithFalsyReason() { - const { broadcast: bc } = broadcast(); - const consumer = bc.push(); - const resultPromise = text(consumer).catch((err) => err); - await new Promise((resolve) => setImmediate(resolve)); - bc.cancel(0); - const result = await resultPromise; - assert.strictEqual(result, 0); + for (const reason of [0, '', false, null]) { + const { broadcast: bc } = broadcast(); + const iterator = bc.push()[Symbol.asyncIterator](); + + bc.cancel(reason); + + await assert.rejects(iterator.next(), (error) => error === reason); + } } // Late-joining consumer should read from oldest buffered entry @@ -325,12 +390,16 @@ Promise.all([ testWritevSync(), testWriterEnd(), testWriterEndWithPreAbortedSignal(), + testWriterEndWaitsForAllConsumers(), + testWriterEndSignalDoesNotFailWriter(), + testWriterFailWhileClosing(), testWriterFail(), testCancelWithoutReason(), testCancelWithReason(), testCancelWithFalsyReason(), testPendingNextSettlesAfterReturn(), testPushAbortSignalRejectsPendingNext(), + testPushPreAbortedSignalDoesNotAddConsumer(), testFailDetachesConsumers(), testWriterFailIdempotent(), testLateJoinerSeesBufferedData(), diff --git a/test/parallel/test-stream-iter-pull-async.js b/test/parallel/test-stream-iter-pull-async.js index 6fa3192e5855..3159b718f27e 100644 --- a/test/parallel/test-stream-iter-pull-async.js +++ b/test/parallel/test-stream-iter-pull-async.js @@ -295,6 +295,23 @@ async function testPullStatelessTransformFlushError() { }, { message: 'async flush boom' }); } +// An abort during an async flush must not be swallowed when the flush resolves +// to null and therefore produces no final batch. +async function testPullSignalAbortDuringAsyncFlush() { + const ac = new AbortController(); + const reason = new Error('aborted during flush'); + const transform = async (chunks) => { + if (chunks !== null) return chunks; + ac.abort(reason); + return null; + }; + + await assert.rejects( + () => text(pull(from('x'), transform, { signal: ac.signal })), + (error) => error === reason, + ); +} + // Pull with a sync iterable source (not async) async function testPullWithSyncSource() { function* gen() { @@ -409,6 +426,7 @@ async function testTransformOptionsNotShared() { testPullStatelessTransformFlush(), testPullConsecutiveStatelessTransformFlush(), testPullStatelessTransformFlushError(), + testPullSignalAbortDuringAsyncFlush(), testPullWithSyncSource(), testPullStringSource(), testTransformReturnsSingleUint8Array(), diff --git a/test/parallel/test-stream-iter-share-async.js b/test/parallel/test-stream-iter-share-async.js index f55ca35f6977..c96a0cb0f3c3 100644 --- a/test/parallel/test-stream-iter-share-async.js +++ b/test/parallel/test-stream-iter-share-async.js @@ -132,6 +132,17 @@ async function testShareCancelWithReason() { ); } +async function testShareCancelWithFalsyReason() { + for (const reason of [0, '', false, null]) { + const shared = share(from('data')); + const iterator = shared.pull()[Symbol.asyncIterator](); + + shared.cancel(reason); + + await assert.rejects(iterator.next(), (error) => error === reason); + } +} + async function testShareAbortSignal() { const ac = new AbortController(); const reason = new Error('share aborted'); @@ -215,6 +226,17 @@ async function testSharePullAbortSignalRejectsPendingNext() { shared.cancel(); } +async function testSharePullPreAbortedSignalDoesNotAddConsumer() { + const reason = new Error('already aborted'); + const signal = AbortSignal.abort(reason); + const shared = share(from('data')); + const iter = shared.pull({ signal })[Symbol.asyncIterator](); + + assert.strictEqual(shared.consumerCount, 0); + await assert.rejects(iter.next(), (error) => error === reason); + assert.strictEqual(shared.consumerCount, 0); +} + async function testShareAlreadyAborted() { const shared = share(from('data'), { signal: AbortSignal.abort() }); const consumer = shared.pull(); @@ -357,9 +379,11 @@ Promise.all([ testShareCancel(), testShareCancelMidIteration(), testShareCancelWithReason(), + testShareCancelWithFalsyReason(), testShareAbortSignal(), testShareAbortSignalWhileSourcePullPending(), testSharePullAbortSignalRejectsPendingNext(), + testSharePullPreAbortedSignalDoesNotAddConsumer(), testShareAlreadyAborted(), testShareSourceError(), testShareLateJoiningConsumer(), diff --git a/test/parallel/test-stream-iter-share-from.js b/test/parallel/test-stream-iter-share-from.js index 0b7e22ee5cee..806e30876302 100644 --- a/test/parallel/test-stream-iter-share-from.js +++ b/test/parallel/test-stream-iter-share-from.js @@ -170,40 +170,50 @@ async function testShareDropOldest() { } async function testShareDropNewest() { - // With drop-newest and a stalled consumer, the async path allows the - // buffer to grow beyond budget (the "drop" applies to the - // backpressure signal, not the buffer contents). Both consumers - // ultimately see all items. + let pulls = 0; + let secondPull; + const secondPullStarted = new Promise((resolve) => { + secondPull = resolve; + }); + async function* source() { - for (let i = 0; i < 4; i++) { + for (let i = 0; i < 7; i++) { + pulls++; + if (pulls === 2) secondPull(); const chunk = new Uint8Array(16384); chunk[0] = i; yield [chunk]; } } - const shared = share(source(), { budget: 32768, backpressure: 'drop-newest' }); - const fast = shared.pull(); - const slow = shared.pull(); + const shared = share(source(), { + budget: 16384, + backpressure: 'drop-newest', + }); + const fast = shared.pull()[Symbol.asyncIterator](); + const slow = shared.pull()[Symbol.asyncIterator](); - // Fast consumer reads all items - const fastIndices = []; - for await (const batch of fast) { - for (const chunk of batch) { - fastIndices.push(chunk[0]); - } - } - assert.strictEqual(fastIndices.length, 2); + const first = await fast.next(); + assert.strictEqual(first.value[0][0], 0); - // Slow consumer also sees all items (buffer grew past budget) - const slowIndices = []; - for await (const batch of slow) { - for (const chunk of batch) { - slowIndices.push(chunk[0]); - } - } - assert.strictEqual(slowIndices.length, 2); - assert.strictEqual(slowIndices[0], 0); - assert.strictEqual(slowIndices[1], 1); + let nextSettled = false; + const next = fast.next().then((result) => { + nextSettled = true; + return result; + }); + + await secondPullStarted; + await new Promise(setImmediate); + assert.strictEqual(pulls, 2); + assert.strictEqual(nextSettled, false); + + const slowResult = await slow.next(); + assert.strictEqual(slowResult.value[0][0], 0); + + const nextResult = await next; + assert.strictEqual(nextResult.value[0][0], 2); + assert.strictEqual(pulls, 3); + + shared.cancel(); } // ============================================================================= diff --git a/test/parallel/test-stream-iter-share-sync.js b/test/parallel/test-stream-iter-share-sync.js index 2b0b1944a7ff..20c98d134206 100644 --- a/test/parallel/test-stream-iter-share-sync.js +++ b/test/parallel/test-stream-iter-share-sync.js @@ -87,37 +87,32 @@ function testShareSyncCancelMidIteration() { } function testShareSyncCancelWithReason() { - // When cancel(reason) is called, a consumer that hasn't started - // iterating is already detached, so it sees done:true (not the error). - // But a consumer that is mid-iteration when another consumer cancels - // with a reason will see the error on the next pull after cancel. const enc = new TextEncoder(); function* gen() { yield [enc.encode('a')]; yield [enc.encode('b')]; - yield [enc.encode('c')]; } const shared = shareSync(gen(), { budget: 16384 }); - const c1 = shared.pull(); - const c2 = shared.pull(); + const iterator1 = shared.pull()[Symbol.iterator](); + const iterator2 = shared.pull()[Symbol.iterator](); + const reason = new Error('sync cancel reason'); + + iterator1.next(); + shared.cancel(reason); - // c1 reads one item, then c2 cancels with a reason - const iter1 = c1[Symbol.iterator](); - const first = iter1.next(); - assert.strictEqual(first.done, false); + assert.throws(() => iterator1.next(), (error) => error === reason); + assert.throws(() => iterator2.next(), (error) => error === reason); +} - shared.cancel(new Error('sync cancel reason')); +function testShareSyncCancelWithFalsyReason() { + for (const reason of [0, '', false, null]) { + const shared = shareSync(fromSync('data')); + const iterator = shared.pull()[Symbol.iterator](); - // c1 was already iterating, it's now detached → done - const next = iter1.next(); - assert.strictEqual(next.done, true); + shared.cancel(reason); - // c2 never started, also detached → done (not error) - const batches = []; - for (const batch of c2) { - batches.push(batch); + assert.throws(() => iterator.next(), (error) => error === reason); } - assert.strictEqual(batches.length, 0); } // ============================================================================= @@ -157,6 +152,7 @@ Promise.all([ testShareSyncCancel(), testShareSyncCancelMidIteration(), testShareSyncCancelWithReason(), + testShareSyncCancelWithFalsyReason(), testShareSyncSourceError(), testShareSyncStringSource(), ]).then(common.mustCall()); diff --git a/test/parallel/test-stream-iter-transform-output.js b/test/parallel/test-stream-iter-transform-output.js index d66a20f6e164..90261a33785a 100644 --- a/test/parallel/test-stream-iter-transform-output.js +++ b/test/parallel/test-stream-iter-transform-output.js @@ -59,6 +59,36 @@ async function testSyncTransformReturnsFloat32Array() { assert.strictEqual(data.byteLength, 4); } +// Consecutive stateless transforms normalize intermediate output (async) +async function testConsecutiveTransformsNormalizeIntermediateOutput() { + const first = (chunks) => { + return chunks === null ? null : new Uint8Array([65]); + }; + let receivedBatch = false; + const second = (chunks) => { + if (chunks !== null) receivedBatch = Array.isArray(chunks); + return chunks; + }; + const data = await bytes(pull(from('x'), first, second)); + assert.ok(receivedBatch); + assert.deepStrictEqual(data, new Uint8Array([65])); +} + +// Consecutive stateless transforms normalize intermediate output (sync) +async function testConsecutiveSyncTransformsNormalizeIntermediateOutput() { + const first = (chunks) => { + return chunks === null ? null : new Uint8Array([65]); + }; + let receivedBatch = false; + const second = (chunks) => { + if (chunks !== null) receivedBatch = Array.isArray(chunks); + return chunks; + }; + const data = bytesSync(pullSync(fromSync('x'), first, second)); + assert.ok(receivedBatch); + assert.deepStrictEqual(data, new Uint8Array([65])); +} + // Stateless transform returns a sync generator (iterable) async function testTransformReturnsGenerator() { const tx = (chunks) => { @@ -233,6 +263,8 @@ Promise.all([ testSyncTransformReturnsArrayBuffer(), testTransformReturnsFloat32Array(), testSyncTransformReturnsFloat32Array(), + testConsecutiveTransformsNormalizeIntermediateOutput(), + testConsecutiveSyncTransformsNormalizeIntermediateOutput(), testTransformReturnsGenerator(), testSyncTransformReturnsGenerator(), testTransformReturnsAsyncGenerator(), diff --git a/test/parallel/test-stream-iter-transform-params.js b/test/parallel/test-stream-iter-transform-params.js new file mode 100644 index 000000000000..aa029f9713c9 --- /dev/null +++ b/test/parallel/test-stream-iter-transform-params.js @@ -0,0 +1,30 @@ +// Flags: --experimental-stream-iter +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const { from, pull, bytes } = require('stream/iter'); +const { compressBrotli, compressZstd } = require('zlib/iter'); + +// Type validation of options.params in zlib/iter transforms: plain +// objects and arrays pass the check, any other value rejects with +// ERR_INVALID_ARG_TYPE. Arrays have always passed the typeof-based +// check, so this behavior must be preserved by any refactor. + +const consume = (transform) => bytes(pull(from('test'), transform)); + +(async () => { + for (const compress of [compressBrotli, compressZstd]) { + for (const params of [42, 'bad', true, Symbol(), () => {}, null]) { + await assert.rejects( + consume(compress({ params })), + { code: 'ERR_INVALID_ARG_TYPE' }, + ); + } + + // An empty array has no own keys, so it passes both the type check + // and the per-key validation and compression succeeds. + const out = await consume(compress({ params: [] })); + assert.ok(out.byteLength > 0); + } +})().then(common.mustCall()); diff --git a/test/parallel/test-stream-iter-validation.js b/test/parallel/test-stream-iter-validation.js index 9f77fe330478..8dcfb46f173f 100644 --- a/test/parallel/test-stream-iter-validation.js +++ b/test/parallel/test-stream-iter-validation.js @@ -156,6 +156,15 @@ assert.throws(() => broadcast({ budget: 16383 }), { code: 'ERR_OUT_OF_RANGE' }); assert.throws(() => broadcast({ signal: {} }), { code: 'ERR_INVALID_ARG_TYPE' }); assert.throws(() => broadcast({ backpressure: 'bad' }), { code: 'ERR_INVALID_ARG_VALUE' }); +// Broadcast consumer options.signal must be AbortSignal and validation must +// not leave a consumer registered. +{ + const { broadcast: bc } = broadcast(); + assert.throws(() => bc.push({ signal: {} }), + { code: 'ERR_INVALID_ARG_TYPE' }); + assert.strictEqual(bc.consumerCount, 0); +} + // BroadcastWriter options.signal must be AbortSignal { const { writer } = broadcast(); @@ -212,6 +221,15 @@ assert.throws(() => share(from('a'), { budget: Number.MAX_SAFE_INTEGER + 1 }), assert.throws(() => share(from('a'), { signal: {} }), { code: 'ERR_INVALID_ARG_TYPE' }); assert.throws(() => share(from('a'), { backpressure: 'bad' }), { code: 'ERR_INVALID_ARG_VALUE' }); +// Share consumer options.signal must be AbortSignal and validation must not +// leave a consumer registered. +{ + const shared = share(from('a')); + assert.throws(() => shared.pull({ signal: {} }), + { code: 'ERR_INVALID_ARG_TYPE' }); + assert.strictEqual(shared.consumerCount, 0); +} + // share() values < 16384 are rejected assert.throws(() => share(from('a'), { budget: 0 }), { code: 'ERR_OUT_OF_RANGE' }); assert.throws(() => share(from('a'), { budget: -1 }), { code: 'ERR_OUT_OF_RANGE' }); diff --git a/test/parallel/test-stream-pipeline-http2.js b/test/parallel/test-stream-pipeline-http2.js index c35cd696bd1e..8ffee7786838 100644 --- a/test/parallel/test-stream-pipeline-http2.js +++ b/test/parallel/test-stream-pipeline-http2.js @@ -27,10 +27,12 @@ const http2 = require('http2'); client.close(); })); - let cnt = 10; + let received = 0; req.on('data', (data) => { - cnt--; - if (cnt === 0) rs.destroy(); + received += data.length; + // Bound the data that flows before teardown - bytes per data event vary + // by platform, and letting this run longer hangs on macOS. + if (received >= 32 * 1024) rs.destroy(); }); })); } diff --git a/test/parallel/test-timers-immediate-queue.js b/test/parallel/test-timers-immediate-queue.js index 8b433ddedbf4..517bb280d49d 100644 --- a/test/parallel/test-timers-immediate-queue.js +++ b/test/parallel/test-timers-immediate-queue.js @@ -19,9 +19,13 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +// Flags: --expose-internals --no-warnings + 'use strict'; require('../common'); const assert = require('assert'); +const { internalBinding } = require('internal/test/binding'); +const timersBinding = internalBinding('timers'); // setImmediate should run clear its queued cbs once per event loop turn // but immediates queued while processing the current queue should happen @@ -38,8 +42,8 @@ const QUEUE = 10; function run() { if (hit === 0) { setTimeout(() => { ticked = true; }, 1); - const now = Date.now(); - while (Date.now() - now < 2); + const now = timersBinding.getLibuvNow(); + while (timersBinding.getLibuvNow() - now < 2); } if (ticked) return; diff --git a/test/parallel/test-timers-interval-promisified.js b/test/parallel/test-timers-interval-promisified.js index 8ee8015986d7..b2f94b836807 100644 --- a/test/parallel/test-timers-interval-promisified.js +++ b/test/parallel/test-timers-interval-promisified.js @@ -247,12 +247,10 @@ process.on('multipleResolves', common.mustNotCall()); (async () => { const signal = AbortSignal.abort('boom'); - try { + await assert.rejects(async () => { const iterable = timerPromises.setInterval(2, undefined, { signal }); + // eslint-disable-next-line no-unused-vars, no-empty for await (const _ of iterable) { } - assert.fail('should have failed'); - } catch (err) { - assert.strictEqual(err.cause, 'boom'); - } + }, { cause: 'boom' }, 'should have failed'); })().then(common.mustCall()); diff --git a/test/parallel/test-tls-alpn-protocols-validation.js b/test/parallel/test-tls-alpn-protocols-validation.js new file mode 100644 index 000000000000..2a93cca891ce --- /dev/null +++ b/test/parallel/test-tls-alpn-protocols-validation.js @@ -0,0 +1,85 @@ +'use strict'; +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +const assert = require('assert'); +const tls = require('tls'); + +// Array with empty string should throw (zero-length protocol entry) +assert.throws(() => { + const out = {}; + tls.convertALPNProtocols([''], out); +}, { + code: 'ERR_INVALID_ARG_VALUE', +}); + +// Array with empty string mixed +assert.throws(() => { + const out = {}; + tls.convertALPNProtocols(['h2', ''], out); +}, { + code: 'ERR_INVALID_ARG_VALUE', +}); + +// Buffer wire format with leading zero length +assert.throws(() => { + const out = {}; + tls.convertALPNProtocols(Buffer.from([0]), out); +}, { + code: 'ERR_INVALID_ARG_VALUE', +}); + +// Buffer truncated (claims 2 bytes but only 1 follows) +assert.throws(() => { + const out = {}; + tls.convertALPNProtocols(Buffer.from([2, 0x61]), out); +}, { + code: 'ERR_INVALID_ARG_VALUE', +}); + +// Buffer with trailing invalid byte +assert.throws(() => { + const out = {}; + tls.convertALPNProtocols(Buffer.from([1, 0x61, 0x62, 0x62]), out); +}, { + code: 'ERR_INVALID_ARG_VALUE', +}); + +// Empty array means skip ALPN (allowed) +{ + const out = {}; + tls.convertALPNProtocols([], out); + assert.ok(Buffer.isBuffer(out.ALPNProtocols)); + assert.strictEqual(out.ALPNProtocols.length, 0); +} + +// Empty buffer means skip ALPN (allowed; same as []) +{ + const out = {}; + tls.convertALPNProtocols(Buffer.alloc(0), out); + assert.ok(Buffer.isBuffer(out.ALPNProtocols)); + assert.strictEqual(out.ALPNProtocols.length, 0); +} + +// Empty Uint8Array means skip ALPN +{ + const out = {}; + tls.convertALPNProtocols(new Uint8Array(0), out); + assert.ok(Buffer.isBuffer(out.ALPNProtocols)); + assert.strictEqual(out.ALPNProtocols.length, 0); +} + +// Valid inputs should not throw +{ + const out = {}; + tls.convertALPNProtocols(['h2', 'http/1.1'], out); + assert.ok(out.ALPNProtocols.length > 0); +} +{ + const out = {}; + tls.convertALPNProtocols(Buffer.from([ + 2, 0x61, 0x62, 8, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31, + ]), out); + assert.strictEqual(out.ALPNProtocols.length, 12); +} diff --git a/test/parallel/test-tls-basic-validations.js b/test/parallel/test-tls-basic-validations.js index 0446b6aef219..d2bbc26b003a 100644 --- a/test/parallel/test-tls-basic-validations.js +++ b/test/parallel/test-tls-basic-validations.js @@ -81,17 +81,19 @@ assert.throws(() => tls.createServer({ ticketKeys: Buffer.alloc(0) }), { }); { - const buffer = Buffer.from('abcd'); + const buffer = Buffer.from([3, 0x61, 0x62, 0x63]); const out = {}; tls.convertALPNProtocols(buffer, out); - out.ALPNProtocols.write('efgh'); - assert(buffer.equals(Buffer.from('abcd'))); - assert(out.ALPNProtocols.equals(Buffer.from('efgh'))); + out.ALPNProtocols.write('def', 1); + assert(buffer.equals(Buffer.from([3, 0x61, 0x62, 0x63]))); + assert(out.ALPNProtocols.equals(Buffer.from([3, 0x64, 0x65, 0x66]))); } { - const arrayBufferViewStr = 'abcd'; - const inputBuffer = Buffer.from(arrayBufferViewStr.repeat(8), 'utf8'); + const inputBuffer = Buffer.concat([ + Buffer.from([31]), + Buffer.alloc(31, 0x61), + ]); for (const expectView of common.getArrayBufferViews(inputBuffer)) { const out = {}; const expected = Buffer.from(expectView.buffer.slice(), diff --git a/test/parallel/test-tls-client-cert-resumption.js b/test/parallel/test-tls-client-cert-resumption.js new file mode 100644 index 000000000000..790809678d66 --- /dev/null +++ b/test/parallel/test-tls-client-cert-resumption.js @@ -0,0 +1,199 @@ +'use strict'; +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// Server-side client-certificate authorization must survive TLS session +// resumption. On a resumed handshake the client does not re-send its +// certificate, so the server has to report the same authorization state it +// derived from the original full handshake: +// +// - a trusted certificate stays authorized, +// - an untrusted certificate stays unauthorized with its verification error, +// - a missing certificate stays unauthorized (UNABLE_TO_GET_ISSUER_CERT). +// +// The missing-certificate case is special on TLS 1.3: ncrypto reports X509_V_OK +// for the resumed PSK handshake even though no certificate was presented, so +// the absence has to be detected explicitly (see onServerSocketSecure() in +// lib/internal/tls/wrap.js). The final case checks that such a certificate-less +// resumed session is rejected outright when rejectUnauthorized is set. + +const assert = require('assert'); +const crypto = require('crypto'); +const tls = require('tls'); +const fixtures = require('../common/fixtures'); +const { once } = require('events'); + +const ca = fixtures.readKey('ca1-cert.pem'); +const serverCert = { + key: fixtures.readKey('agent2-key.pem'), + cert: fixtures.readKey('agent2-cert.pem'), +}; + +// Client certificate variants, keyed by the peer state they produce. +const CLIENTS = { + trusted: { // Signed by ca1 + creds: { + key: fixtures.readKey('agent1-key.pem'), + cert: fixtures.readKey('agent1-cert.pem'), + }, + authorized: true, + authorizationError: null, + peerCN: 'agent1', + }, + untrusted: { // Signed by ca2, not trusted + creds: { + key: fixtures.readKey('agent3-key.pem'), + cert: fixtures.readKey('agent3-cert.pem'), + }, + authorized: false, + authorizationError: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE', + peerCN: 'agent3', + }, + missing: { // No client certificate + creds: {}, + authorized: false, + authorizationError: 'UNABLE_TO_GET_ISSUER_CERT', + peerCN: undefined, + }, +}; + +async function handshake(options, captureSession) { + const socket = tls.connect(options); + const sessionPromise = captureSession ? + once(socket, 'session').then(([session]) => session) : null; + + socket.resume(); + await once(socket, 'secureConnect'); + + const closePromise = once(socket, 'close'); + const session = sessionPromise ? await sessionPromise : undefined; + socket.end(); + await closePromise; + return session; +} + +// Test a single resumption configuration and expected result: +async function testResumption(version, name) { + const { creds, authorized, authorizationError, peerCN } = CLIENTS[name]; + + let connections = 0; + const server = tls.createServer({ + ...serverCert, + ca, + requestCert: true, + rejectUnauthorized: false, + minVersion: version, + maxVersion: version, + }, common.mustCall((socket) => { + // 2nd conn must resume: + const resumed = connections++ === 1; + const where = `${version} ${name} ${resumed ? 'resumed' : 'new'}`; + assert.strictEqual(socket.isSessionReused(), resumed, where); + + // Both conns must report same expected auth state: + assert.strictEqual(socket.authorized, authorized, where); + assert.strictEqual(socket.authorizationError, authorizationError, where); + const peer = socket.getPeerCertificate(); + if (peerCN === undefined) + assert.deepStrictEqual(peer, {}, where); + else + assert.strictEqual(peer.subject.CN, peerCN, where); + + // N.b. BoringSSL only sends a ticket after a write: + socket.end('.'); + }, 2)); + + server.listen(0); + await once(server, 'listening'); + + const options = { + port: server.address().port, + host: '127.0.0.1', + checkServerIdentity: () => undefined, + rejectUnauthorized: false, + minVersion: version, + maxVersion: version, + ...creds, + }; + + try { + const session = await handshake(options, true); + assert(session); + await handshake({ ...options, session }); + } finally { + server.close(); + await once(server, 'close'); + } +} + +// Test the special case of resumption from rejectUnauthorized:false to +// rejectUnauthorized:true, which must be rejected even though the original +// session worked initially. +async function testRejectResumedWithoutCert() { + const options = { + ...serverCert, + ca, + requestCert: true, + minVersion: 'TLSv1.3', + maxVersion: 'TLSv1.3', + ticketKeys: crypto.randomBytes(48), + }; + const lenient = tls.createServer({ ...options, rejectUnauthorized: false }); + lenient.on('secureConnection', common.mustCall((socket) => { + assert.strictEqual(socket.authorized, false); + assert.strictEqual(socket.authorizationError, 'UNABLE_TO_GET_ISSUER_CERT'); + socket.end('.'); + })); + + const strict = tls.createServer({ ...options, rejectUnauthorized: true }); + strict.on('secureConnection', common.mustNotCall()); + + const clientOptions = (port) => ({ + port, + host: '127.0.0.1', + rejectUnauthorized: false, + checkServerIdentity: () => undefined, + minVersion: 'TLSv1.3', + maxVersion: 'TLSv1.3', + }); + + lenient.listen(0); + await once(lenient, 'listening'); + const session = await handshake(clientOptions(lenient.address().port), true); + assert(session); + lenient.close(); + await once(lenient, 'close'); + + strict.listen(0); + await once(strict, 'listening'); + + const resumed = tls.connect({ ...clientOptions(strict.address().port), session }); + resumed.on('error', () => {}); // May observe the server's reset. + resumed.resume(); + + // The client completes the resumed handshake (it has the server's Finished) + // before the server's reset can arrive, so this asserts the strict server + // actually resumed rather than falling back to a rejected full handshake. + await once(resumed, 'secureConnect'); + assert.strictEqual(resumed.isSessionReused(), true); + + // Then the socket is destroyed during 'secure', which surfaces as a reset + // rather than a handshake failure. + const [err] = await once(strict, 'tlsClientError'); + assert.strictEqual(err.code, 'ECONNRESET'); + + resumed.destroy(); + strict.close(); + await once(strict, 'close'); +} + +(async function() { + // Run the full matrix of configurations: + for (const version of ['TLSv1.2', 'TLSv1.3']) + for (const name of Object.keys(CLIENTS)) + await testResumption(version, name); + + // Validate the rejectUnauth:false->true case + await testRejectResumedWithoutCert(); +})().then(common.mustCall()); diff --git a/test/parallel/test-tls-client-getephemeralkeyinfo.js b/test/parallel/test-tls-client-getephemeralkeyinfo.js index ea6dec7bdc46..82572c4e4975 100644 --- a/test/parallel/test-tls-client-getephemeralkeyinfo.js +++ b/test/parallel/test-tls-client-getephemeralkeyinfo.js @@ -4,7 +4,7 @@ if (!common.hasCrypto) common.skip('missing crypto'); if (process.features.openssl_is_boringssl) { - require('../common/boringssl').testEphemeralKeyInfoUnsupported(); + require('../common/boringssl').testEphemeralKeyInfo(); return; } diff --git a/test/parallel/test-util-getcallsites-sourcemap.js b/test/parallel/test-util-getcallsites-sourcemap.js index 4499ea106fdd..9259832261ee 100644 --- a/test/parallel/test-util-getcallsites-sourcemap.js +++ b/test/parallel/test-util-getcallsites-sourcemap.js @@ -39,6 +39,18 @@ const fixtures = require('../common/fixtures'); assert.strictEqual(callSite.columnNumber, 1); } +// A source map may omit names, so preserve the function name from the call site. +{ + const file = fixtures.path('source-map', 'get-call-sites-function-name-mapped.js'); + const { status, stderr, stdout } = spawnSync( + process.execPath, + ['--enable-source-maps', file], + ); + assert.strictEqual(status, 0, stderr.toString()); + const callSite = JSON.parse(stdout.toString()); + assert.strictEqual(callSite.functionName, 'foo'); +} + // Without --enable-source-maps the generated file path is preserved. { const file = fixtures.path('source-map', 'get-call-sites-mapped.js'); diff --git a/test/parallel/test-util-inspect.js b/test/parallel/test-util-inspect.js index c8b37f2a264b..1278e4eed471 100644 --- a/test/parallel/test-util-inspect.js +++ b/test/parallel/test-util-inspect.js @@ -2596,6 +2596,15 @@ assert.strictEqual( "'foobar', { x: 1 } },\n inc: [Getter: NaN]\n}"); } +// Getter returning a function. +// https://github.com/nodejs/node/issues/64838 +{ + const obj = { get foo() { return function bar() {}; } }; + assert.strictEqual( + inspect(obj, { getters: true }), + '{ foo: [Getter] [Function: bar] }'); +} + // Property getter throwing an error. { const error = new Error('Oops'); @@ -3524,16 +3533,14 @@ assert.strictEqual( '\x1B[2mdef: \x1B[33m5\x1B[39m\x1B[22m }' ); - assert.match( + assert.strictEqual( inspect(Object.getPrototypeOf(bar), { showHidden: true, getters: true }), - new RegExp('^' + RegExp.escape( - ' Foo [Map] {\n' + - ' [constructor]: [class Bar extends Foo] {\n' + + ' Foo [Map] {\n' + + ' [constructor]: [class Bar extends Foo] {\n' + ' [length]: 0,\n' + " [name]: 'Bar',\n" + - ' [prototype]: [Circular *1],\n' + - ' [Symbol(Symbol.species)]: [Getter: ]\n' + + ' [prototype]: [Circular *2],\n' + + ' [Symbol(Symbol.species)]: [Getter] [Circular *1]\n' + ' },\n' + " [xyz]: [Getter: 'YES!'],\n" + ' [Symbol(nodejs.util.inspect.custom)]: [Function: [nodejs.util.inspect.custom]] {\n' + @@ -3543,7 +3550,6 @@ assert.strictEqual( ' [abc]: [Getter: true],\n' + ' [def]: [Getter/Setter: false]\n' + '}' - ) + '$', 's') ); assert.strictEqual( @@ -4058,3 +4064,9 @@ ${error.stack.split('\n').slice(1).join('\n')}`, assert.match(inspect(DOMException.prototype), /^\[object DOMException\] \{/); delete Error[Symbol.hasInstance]; } + +{ + const obj = { a: 'short string', b: [1, 2], c: { d: true } }; + const expected = "{ a: 'short string', b: [ 1, 2 ], c: { d: true } }"; + assert.strictEqual(util.inspect(obj, { breakLength: Infinity }), expected); +} diff --git a/test/parallel/test-util-stripvtcontrolcharacters.js b/test/parallel/test-util-stripvtcontrolcharacters.js index a33d18d26dbc..efda16687821 100644 --- a/test/parallel/test-util-stripvtcontrolcharacters.js +++ b/test/parallel/test-util-stripvtcontrolcharacters.js @@ -18,9 +18,31 @@ for (const ST of ['\u0007', '\u001B\u005C', '\u009C']) { tests.push( [`\u001B]8;;mailto:no-replay@mail.com${ST}mail\u001B]8;;${ST}`, 'mail'], [`\u001B]8;k=v;https://example-a.com/?a_b=1&c=2#tit%20le${ST}click\u001B]8;;${ST}`, 'click'], + [`\u001B]8;;https://example.com/(foo${ST}label\u001B]8;;${ST}`, 'label'], + [`\u001B]8;;https://example.com/foo)bar${ST}label\u001B]8;;${ST}`, 'label'], + [`\u001B]8;;https://example.com/!foo${ST}label\u001B]8;;${ST}`, 'label'], + [`\u001B]8;;https://example.com/foo+bar${ST}label\u001B]8;;${ST}`, 'label'], + [`\u001B]8;;https://example.com/[foo]${ST}label\u001B]8;;${ST}`, 'label'], + [`\u001B]8;;https://example.com/foo$bar${ST}label\u001B]8;;${ST}`, 'label'], + [`\u001B]8;;https://example.com/foo'bar${ST}label\u001B]8;;${ST}`, 'label'], + [`\u001B]8;;https://example.com/foo*bar${ST}label\u001B]8;;${ST}`, 'label'], + [`\u001B]8;;https://example.com/foo,bar${ST}label\u001B]8;;${ST}`, 'label'], ); } +// Colon-delimited CSI sub-parameters (SGR) should be stripped like the +// semicolon-delimited form. +tests.push( + ['\u001B[38:2:255:0:0mHello\u001B[0m', 'Hello'], + ['\u001B[4:3mUnderline\u001B[4:0m', 'Underline'], +); + +// Unterminated OSC does not match the OSC alternative; the CSI alternative may +// still consume a short prefix (here ESC ] 8 ;; h), leaving the remainder. +tests.push( + ['\u001B]8;;https://example.com/no-terminator', 'ttps://example.com/no-terminator'], +); + test('util.stripVTControlCharacters', (t) => { for (const [before, expected] of tests) { t.assert.strictEqual(util.stripVTControlCharacters(before), expected); diff --git a/test/parallel/test-v8-stop-coverage.js b/test/parallel/test-v8-stop-coverage.js index e9764d60477b..b37f8320abb4 100644 --- a/test/parallel/test-v8-stop-coverage.js +++ b/test/parallel/test-v8-stop-coverage.js @@ -5,7 +5,7 @@ const fixtures = require('../common/fixtures'); const tmpdir = require('../common/tmpdir'); const assert = require('assert'); const fs = require('fs'); -const { spawnSync } = require('child_process'); +const { spawnSyncAndExitWithoutError } = require('../common/child_process'); common.skipIfInspectorDisabled(); @@ -13,7 +13,7 @@ tmpdir.refresh(); const intervals = 20; { - const output = spawnSync(process.execPath, [ + const { child } = spawnSyncAndExitWithoutError(process.execPath, [ '-r', fixtures.path('v8-coverage', 'stop-coverage'), '-r', @@ -27,8 +27,7 @@ const intervals = 20; TEST_INTERVALS: intervals }, }); - console.log(output.stderr.toString()); - assert.strictEqual(output.status, 0); + console.log(child.stderr.toString()); const coverageFiles = fs.readdirSync(tmpdir.path); assert.strictEqual(coverageFiles.length, 0); } diff --git a/test/parallel/test-v8-take-coverage-noop.js b/test/parallel/test-v8-take-coverage-noop.js index 8d49b0f23296..14bb8a2c3a91 100644 --- a/test/parallel/test-v8-take-coverage-noop.js +++ b/test/parallel/test-v8-take-coverage-noop.js @@ -5,7 +5,7 @@ const fixtures = require('../common/fixtures'); const tmpdir = require('../common/tmpdir'); const assert = require('assert'); const fs = require('fs'); -const { spawnSync } = require('child_process'); +const { spawnSyncAndExitWithoutError } = require('../common/child_process'); common.skipIfInspectorDisabled(); @@ -14,7 +14,7 @@ tmpdir.refresh(); // v8.takeCoverage() should be a noop if NODE_V8_COVERAGE is not set. const intervals = 40; { - const output = spawnSync(process.execPath, [ + const { child } = spawnSyncAndExitWithoutError(process.execPath, [ '-r', fixtures.path('v8-coverage', 'take-coverage'), fixtures.path('v8-coverage', 'interval'), @@ -25,8 +25,7 @@ const intervals = 40; TEST_INTERVALS: intervals }, }); - console.log(output.stderr.toString()); - assert.strictEqual(output.status, 0); + console.log(child.stderr.toString()); const coverageFiles = fs.readdirSync(tmpdir.path); assert.strictEqual(coverageFiles.length, 0); } diff --git a/test/parallel/test-v8-take-coverage.js b/test/parallel/test-v8-take-coverage.js index 6b1fe149e992..2119a30d6ad9 100644 --- a/test/parallel/test-v8-take-coverage.js +++ b/test/parallel/test-v8-take-coverage.js @@ -5,7 +5,7 @@ const fixtures = require('../common/fixtures'); const tmpdir = require('../common/tmpdir'); const assert = require('assert'); const fs = require('fs'); -const { spawnSync } = require('child_process'); +const { spawnSyncAndExitWithoutError } = require('../common/child_process'); common.skipIfInspectorDisabled(); @@ -13,7 +13,7 @@ tmpdir.refresh(); const intervals = 40; // Outputs coverage when v8.takeCoverage() is invoked. { - const output = spawnSync(process.execPath, [ + const { child } = spawnSyncAndExitWithoutError(process.execPath, [ '-r', fixtures.path('v8-coverage', 'take-coverage'), fixtures.path('v8-coverage', 'interval'), @@ -25,8 +25,7 @@ const intervals = 40; TEST_INTERVALS: intervals }, }); - console.log(output.stderr.toString()); - assert.strictEqual(output.status, 0); + console.log(child.stderr.toString()); const coverageFiles = fs.readdirSync(tmpdir.path); let coverages = []; diff --git a/test/parallel/test-webcrypto-enforce-range.js b/test/parallel/test-webcrypto-enforce-range.js new file mode 100644 index 000000000000..f3b3ec74ffc5 --- /dev/null +++ b/test/parallel/test-webcrypto-enforce-range.js @@ -0,0 +1,35 @@ +'use strict'; + +const common = require('../common'); + +if (!common.hasCrypto) + common.skip('missing crypto'); + +const assert = require('assert'); +const { SubtleCrypto } = globalThis; +const { subtle } = globalThis.crypto; + +const algorithm = { + name: 'HKDF', + hash: 'SHA-256', + info: new Uint8Array(), + salt: new Uint8Array(32), +}; +const invalidLength = 2 ** 32; +const expectedError = { + code: 'ERR_OUT_OF_RANGE', + name: 'TypeError', +}; + +assert.throws( + () => SubtleCrypto.supports('deriveBits', algorithm, invalidLength), + expectedError); + +(async () => { + const key = await subtle.importKey( + 'raw', new Uint8Array(32), 'HKDF', false, ['deriveBits']); + + await assert.rejects( + subtle.deriveBits(algorithm, key, invalidLength), + expectedError); +})().then(common.mustCall()); diff --git a/test/parallel/test-webcrypto-export-import-ml-kem.js b/test/parallel/test-webcrypto-export-import-ml-kem.js index 31ba739a1e55..32f072e555b1 100644 --- a/test/parallel/test-webcrypto-export-import-ml-kem.js +++ b/test/parallel/test-webcrypto-export-import-ml-kem.js @@ -106,10 +106,8 @@ async function testImportPkcs8({ name, privateUsages }, extractable) { } catch (err) { if (process.features.openssl_is_boringssl) { assert.strictEqual(err.name, 'DataError'); - // It should really only be ERR_OSSL_EVP_PRIVATE_KEY_WAS_NOT_SEED - // but BoringSSL is inconsistent between handling ML-KEM and ML-DSA - // Fixed in https://github.com/google/boringssl/commit/94c4c7f9e0eeeff72ea1ac6abf1aed5bd2a82c0c - assert.match(err.cause.code, /ERR_OSSL_EVP_UNSUPPORTED_ALGORITHM|ERR_OSSL_EVP_PRIVATE_KEY_WAS_NOT_SEED/); + assert.strictEqual(err.cause.code, + 'ERR_OSSL_EVP_PRIVATE_KEY_WAS_NOT_SEED'); common.printSkipMessage('Skipping unsupported private key format test'); return; } diff --git a/test/parallel/test-webcrypto-prototype-pollution.mjs b/test/parallel/test-webcrypto-prototype-pollution.mjs new file mode 100644 index 000000000000..a7104c2b7ae4 --- /dev/null +++ b/test/parallel/test-webcrypto-prototype-pollution.mjs @@ -0,0 +1,470 @@ +// Flags: --expose-internals + +import * as common from '../common/index.mjs'; +import assert from 'node:assert'; +import { createRequire } from 'node:module'; + +if (!common.hasCrypto) common.skip('missing crypto'); + +// Regression tests for prototype pollution reaching WebCrypto input validation +// and normalization, via BufferSource prototype accessors, inherited +// %Object.prototype% keys, or %Array.prototype%[%Symbol.iterator%]. See +// test-webcrypto-promise-prototype-pollution.mjs for the promise side. + +const require = createRequire(import.meta.url); +const { kSupportedAlgorithms } = require('internal/crypto/util'); +const { getFips } = require('node:crypto'); +const { hasOpenSSL } = require('../common/crypto'); +const { subtle } = globalThis.crypto; + +const TypedArrayPrototype = Object.getPrototypeOf(Uint8Array.prototype); +const data = new TextEncoder().encode('prototype pollution'); +const modulusLength = getFips() === 1 ? 2048 : 1024; + +// Avoids SubtleCrypto.supports(), which warns and invokes the registry's +// experimental-algorithm getters. +function supports(operation, name) { + return Object.hasOwn(kSupportedAlgorithms[operation] ?? {}, name); +} + +// Each poison is { target, key, ...descriptor }. +async function withPoisoned(poisons, fn) { + const saved = []; + for (const { target, key, ...descriptor } of poisons) { + saved.push([target, key, Object.getOwnPropertyDescriptor(target, key)]); + Object.defineProperty(target, key, { + __proto__: null, + configurable: true, + ...descriptor, + }); + } + try { + return await fn(); + } finally { + for (let i = saved.length - 1; i >= 0; i--) { + const { 0: target, 1: key, 2: descriptor } = saved[i]; + if (descriptor === undefined) { + delete target[key]; + } else { + Object.defineProperty(target, key, descriptor); + } + } + } +} + +function poisonTypedArrayByteLength(value) { + return [{ target: TypedArrayPrototype, key: 'byteLength', get: () => value }]; +} + +function inherited(key, value) { + return [{ target: Object.prototype, key, value, writable: true }]; +} + +const poisonArrayIterator = [{ + target: Array.prototype, + key: Symbol.iterator, + value: () => ({ next: () => ({ done: true, value: undefined }) }), + writable: true, +}]; + +// A poisoned array iterator breaks assert too, so settle under the poison and +// assert once it has been restored. +async function settleUnderPoison(poisons, fn) { + const outcome = { __proto__: null, value: undefined, error: undefined }; + await withPoisoned(poisons, async () => { + try { + outcome.value = await fn(); + } catch (err) { + outcome.error = err; + } + }); + return outcome; +} + +// validateByteLength(). Unguarded, the empty iv reaches OpenSSL, which also +// fails with OperationError, hence the message assertion. +{ + const key = await subtle.importKey( + 'raw-secret', new Uint8Array(16), 'AES-CBC', false, ['encrypt']); + await withPoisoned(poisonTypedArrayByteLength(16), common.mustCall(() => + assert.rejects( + subtle.encrypt({ name: 'AES-CBC', iv: new Uint8Array(0) }, key, data), + { + name: 'OperationError', + message: /algorithm\.iv must contain exactly 16 bytes/, + }))); +} + +// validateMaxBufferLength(). +{ + const key = await subtle.importKey( + 'raw-secret', new Uint8Array(32), 'HKDF', false, ['deriveBits']); + await withPoisoned(poisonTypedArrayByteLength(0), common.mustCall(() => + assert.rejects( + subtle.deriveBits({ + name: 'HKDF', + hash: 'SHA-256', + salt: new Uint8Array(0), + info: new Uint8Array(4096), + }, key, 8), + { + name: 'OperationError', + message: /algorithm\.info must be at most 1024 bytes/, + }))); +} + +// aesImportKey(). +await withPoisoned(poisonTypedArrayByteLength(16), common.mustCall(async () => { + const key = await subtle.importKey( + 'raw-secret', new Uint8Array(32), 'AES-GCM', true, ['encrypt']); + assert.strictEqual(key.algorithm.length, 256); +})); + +// validateCShakeFunctionName(). +if (supports('digest', 'cSHAKE128')) { + await withPoisoned(poisonTypedArrayByteLength(0), common.mustCall(() => + assert.rejects( + subtle.digest({ + name: 'cSHAKE128', + outputLength: 256, + functionName: new Uint8Array([0x41, 0x42, 0x43, 0x44]), + }, data), + { + name: 'NotSupportedError', + message: /Unsupported CShakeParams functionName/, + }))); + + // asyncDigest() picks the cSHAKE job over plain SHAKE on a non-empty + // customization. + if (hasOpenSSL(3)) { + const algorithm = { + name: 'cSHAKE128', + outputLength: 256, + customization: new Uint8Array([1, 2, 3]), + }; + const expected = new Uint8Array(await subtle.digest(algorithm, data)); + const plain = new Uint8Array( + await subtle.digest({ name: 'cSHAKE128', outputLength: 256 }, data)); + assert.notDeepStrictEqual(expected, plain); + await withPoisoned(poisonTypedArrayByteLength(0), + common.mustCall(async () => { + assert.deepStrictEqual( + new Uint8Array(await subtle.digest(algorithm, data)), + expected); + })); + } +} + +// AeadParams: AES-OCB caps the iv at 15 bytes. +if (supports('encrypt', 'AES-OCB')) { + const key = await subtle.importKey( + 'raw-secret', new Uint8Array(16), 'AES-OCB', false, ['encrypt']); + await withPoisoned(poisonTypedArrayByteLength(12), common.mustCall(() => + assert.rejects( + subtle.encrypt({ name: 'AES-OCB', iv: new Uint8Array(20) }, key, data), + { + name: 'OperationError', + message: /algorithm\.iv must be no more than 15 bytes/, + }))); +} + +// Argon2Params: the nonce has an 8 byte minimum. +if (supports('deriveBits', 'Argon2id')) { + const key = await subtle.importKey( + 'raw-secret', new Uint8Array(32), 'Argon2id', false, ['deriveBits']); + await withPoisoned(poisonTypedArrayByteLength(16), common.mustCall(() => + assert.rejects( + subtle.deriveBits({ + name: 'Argon2id', + nonce: new Uint8Array(4), + memory: 32, + passes: 1, + parallelism: 1, + }, key, 256), + { + name: 'OperationError', + message: /nonce must be at least 8 bytes/, + }))); +} + +// bigIntArrayToUnsignedInt(): TypedArray `length` is a prototype accessor. +await withPoisoned( + [{ target: TypedArrayPrototype, key: 'length', get: () => 0 }], + common.mustCall(async () => { + const { publicKey } = await subtle.generateKey({ + name: 'RSA-OAEP', + modulusLength, + publicExponent: new Uint8Array([1, 0, 1]), + hash: 'SHA-256', + }, true, ['encrypt', 'decrypt']); + assert.strictEqual(publicKey.algorithm.modulusLength, modulusLength); + assert.deepStrictEqual( + publicKey.algorithm.publicExponent, new Uint8Array([1, 0, 1])); + })); + +// ecdhDeriveBits() bounds the request by the native job's ArrayBuffer. +{ + const { privateKey, publicKey } = await subtle.generateKey( + { name: 'ECDH', namedCurve: 'P-256' }, false, ['deriveBits']); + await withPoisoned( + [{ target: ArrayBuffer.prototype, key: 'byteLength', get: () => 1e9 }], + common.mustCall(() => assert.rejects( + subtle.deriveBits({ name: 'ECDH', public: publicKey }, privateKey, 8192), + { name: 'OperationError' }))); +} + +// simpleAlgorithmDictionaries relies on a miss returning undefined. +{ + const { privateKey, publicKey } = await subtle.generateKey( + { name: 'ECDH', namedCurve: 'P-256' }, false, ['deriveBits']); + await withPoisoned( + inherited('EcdhKeyDeriveParams', + { keys: ['public'], types: { public: 'BufferSource' } }), + common.mustCall(async () => { + const bits = await subtle.deriveBits( + { name: 'ECDH', public: publicKey }, privateKey, 128); + assert.strictEqual(bits.byteLength, 16); + })); + + await withPoisoned( + inherited('AesKeyGenParams', + { keys: ['name'], types: { name: 'AlgorithmIdentifier' } }), + common.mustCall(async () => { + const key = await subtle.generateKey( + { name: 'AES-GCM', length: 128 }, false, ['encrypt']); + assert.strictEqual(key.algorithm.length, 128); + })); +} + +// createDictionaryConverter() reads optional member descriptor keys. +{ + const key = await subtle.generateKey( + { name: 'AES-GCM', length: 128 }, false, ['encrypt']); + const encrypt = () => subtle.encrypt( + { name: 'AES-GCM', iv: new Uint8Array(12) }, key, data); + + for (const poison of [ + inherited('required', true), + inherited('defaultValue', () => 9999), + inherited('validator', common.mustNotCall('Object.prototype.validator')), + ]) { + await withPoisoned(poison, common.mustCall(async () => { + assert.strictEqual((await encrypt()).byteLength, data.byteLength + 16); + })); + } +} + +// Conversion options are read by key by the Web IDL converters. +{ + const key = await subtle.importKey( + 'raw-secret', new Uint8Array(32), 'HKDF', false, ['deriveBits']); + const hkdf = (length) => subtle.deriveBits({ + name: 'HKDF', + hash: 'SHA-256', + salt: new Uint8Array(0), + info: new Uint8Array(0), + }, key, length); + + // deriveBits length is [EnforceRange], so 2 ** 32 must throw even when + // conversion option properties are inherited from Object.prototype. + for (const attribute of ['enforceRange', 'clamp']) { + await withPoisoned( + inherited(attribute, true), + common.mustCall(() => assert.rejects(hkdf(2 ** 32), { + code: 'ERR_OUT_OF_RANGE', + name: 'TypeError', + }))); + } + + // [AllowResizable] is not set for BufferSource. + await withPoisoned(inherited('allowResizable', true), common.mustCall(() => + subtle.digest('SHA-256', new ArrayBuffer(8, { maxByteLength: 1024 })) + )); + + // makeException() falls back to ERR_INVALID_ARG_TYPE. + await withPoisoned(inherited('code', 'ERR_POLLUTED'), common.mustCall(() => + assert.rejects(subtle.digest('SHA-256', 'not a BufferSource'), + { code: 'ERR_INVALID_ARG_TYPE' }))); +} + +// enforceRangeOptions(): [EnforceRange] uses IntegerPart, not round-half-even. +{ + const key = await subtle.importKey( + 'raw-secret', new Uint8Array(4), 'PBKDF2', false, ['deriveBits']); + const pbkdf2 = (iterations) => subtle.deriveBits({ + name: 'PBKDF2', + hash: 'SHA-256', + salt: new Uint8Array(16), + iterations, + }, key, 8); + + const expected = new Uint8Array(await pbkdf2(1)); + await withPoisoned(inherited('clamp', true), common.mustCall(async () => { + assert.deepStrictEqual(new Uint8Array(await pbkdf2(1.5)), expected); + })); +} + +// keyDetail() is filled in by C++ with an ordinary [[Set]]. +{ + const { publicKey } = await subtle.generateKey({ + name: 'RSA-PSS', + modulusLength, + publicExponent: new Uint8Array([1, 0, 1]), + hash: 'SHA-256', + }, true, ['sign', 'verify']); + const spki = await subtle.exportKey('spki', publicKey); + + await withPoisoned([ + { + target: Object.prototype, key: 'modulusLength', + get: () => 8192, set() {}, + }, + { + target: Object.prototype, key: 'publicExponent', + get: () => new Uint8Array([9, 9, 9]), set() {}, + }, + ], common.mustCall(async () => { + const imported = await subtle.importKey( + 'spki', spki, { name: 'RSA-PSS', hash: 'SHA-256' }, true, ['verify']); + assert.strictEqual(imported.algorithm.modulusLength, modulusLength); + assert.deepStrictEqual( + imported.algorithm.publicExponent, new Uint8Array([1, 0, 1])); + })); +} + +{ + const { publicKey } = await subtle.generateKey( + { name: 'ECDSA', namedCurve: 'P-384' }, true, ['sign', 'verify']); + const spki = await subtle.exportKey('spki', publicKey); + + await withPoisoned( + [{ + target: Object.prototype, key: 'namedCurve', + get: () => 'prime256v1', set() {}, + }], + common.mustCall(() => assert.rejects( + subtle.importKey( + 'spki', spki, { name: 'ECDSA', namedCurve: 'P-256' }, true, ['verify']), + { name: 'DataError', message: /Named curve mismatch/ }))); +} + +// Key usages under a poisoned array iterator. Callers pass a Set so the +// spec-mandated sequence conversion still yields the requested usage; only +// WebCrypto's own re-iteration of that array sees the poison. +{ + // Every Set has to be built before the poison is installed, otherwise the + // Set constructor itself iterates its array argument and comes out empty. + const signOnly = new Set(['sign']); + const encryptOnly = new Set(['encrypt']); + const decryptOnly = new Set(['decrypt']); + const decapsulateKeyOnly = new Set(['decapsulateKey']); + + // Secret keys reject empty usages anyway, so match the message: the usage + // has to be rejected as unsupported, not as missing. + const cases = [ + { + name: 'AES-GCM', + message: /Unsupported key usage for AES-GCM key/, + importKey: () => subtle.importKey( + 'raw-secret', new Uint8Array(32), 'AES-GCM', false, signOnly), + }, + { + name: 'HKDF', + message: /Unsupported key usage for a HKDF key/, + importKey: () => subtle.importKey( + 'raw-secret', new Uint8Array(32), 'HKDF', false, encryptOnly), + }, + ]; + + const addPublicKeyCase = async (name, algorithm, usages, disallowed) => { + if (!supports('importKey', name)) return; + const { publicKey } = await subtle.generateKey(algorithm, true, usages); + const spki = await subtle.exportKey('spki', publicKey); + cases.push({ + name, + importKey: () => subtle.importKey( + 'spki', spki, algorithm, true, disallowed), + }); + }; + + await addPublicKeyCase('ECDSA', { name: 'ECDSA', namedCurve: 'P-256' }, + ['sign', 'verify'], signOnly); + await addPublicKeyCase('Ed25519', { name: 'Ed25519' }, + ['sign', 'verify'], signOnly); + await addPublicKeyCase('RSA-OAEP', { + name: 'RSA-OAEP', + modulusLength, + publicExponent: new Uint8Array([1, 0, 1]), + hash: 'SHA-256', + }, ['encrypt', 'decrypt'], decryptOnly); + await addPublicKeyCase('ML-DSA-44', { name: 'ML-DSA-44' }, + ['sign', 'verify'], signOnly); + await addPublicKeyCase('ML-KEM-512', { name: 'ML-KEM-512' }, + ['encapsulateKey', 'decapsulateKey'], + decapsulateKeyOnly); + + for (const { name, message, importKey } of cases) { + const outcome = await settleUnderPoison(poisonArrayIterator, importKey); + assert.strictEqual(outcome.value, undefined, name); + assert.strictEqual(outcome.error?.name, 'SyntaxError', name); + if (message !== undefined) assert.match(outcome.error.message, message); + } +} + +// The registry, the Web IDL converters and the hash name aliases are built at +// module load, so poisoning those needs a fresh process. The child bodies are +// written as real functions and stringified into -e so that they stay linted. +async function runInFreshProcess(fn, args, expected) { + const { code, stdout, stderr } = await common.spawnPromisified( + process.execPath, ['-e', `(${fn})(${args})`]); + assert.strictEqual(code, 0, stderr); + assert.strictEqual(stdout.trim(), expected, stderr); +} + +// Only the load happens under the poison: a sequence argument would +// legitimately come out empty while the caller's iterator is broken. +async function pollutedArrayIteratorChild(kmac) { + const real = Array.prototype[Symbol.iterator]; + Array.prototype[Symbol.iterator] = () => ({ next: () => ({ done: true }) }); + const { subtle } = globalThis.crypto; + const out = []; + try { + out.push((await subtle.digest('SHA-256', new Uint8Array(4))).byteLength); + } finally { + Array.prototype[Symbol.iterator] = real; + } + const hmac = await subtle.generateKey( + { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']); + out.push((await subtle.sign('HMAC', hmac, new Uint8Array(4))).byteLength); + const aes = await subtle.generateKey( + { name: 'AES-GCM', length: 128 }, false, ['encrypt']); + out.push((await subtle.encrypt( + { name: 'AES-GCM', iv: new Uint8Array(12) }, aes, new Uint8Array(4), + )).byteLength); + if (kmac) { + const key = await subtle.generateKey( + { name: 'KMAC128', length: 128 }, false, ['sign']); + out.push((await subtle.sign( + { name: 'KMAC128', outputLength: 256 }, key, new Uint8Array(4), + )).byteLength); + } + console.log(out.join(',')); +} + +// kHashNames indexes its aliases at load time. +async function pollutedHashNameChild() { + Object.prototype['SHA-256'] = { 1: 'md5', 2: 'POLLUTED' }; + const { subtle } = globalThis.crypto; + const key = await subtle.generateKey( + { name: 'HMAC', hash: 'SHA-256' }, true, ['sign']); + const signature = await subtle.sign('HMAC', key, new Uint8Array(4)); + const { alg } = await subtle.exportKey('jwk', key); + console.log(`${signature.byteLength},${alg}`); +} + +{ + const kmac = supports('generateKey', 'KMAC128'); + await runInFreshProcess(pollutedArrayIteratorChild, kmac, + kmac ? '32,32,20,32' : '32,32,20'); + await runInFreshProcess(pollutedHashNameChild, '', '32,HS256'); +} diff --git a/test/parallel/test-webcrypto-webidl.js b/test/parallel/test-webcrypto-webidl.js index 493d0093996b..d91099aed2bf 100644 --- a/test/parallel/test-webcrypto-webidl.js +++ b/test/parallel/test-webcrypto-webidl.js @@ -119,6 +119,104 @@ function assertJsonWebKey(actual, expected) { } } +// [EnforceRange] integer dictionary members +{ + const kOctetMax = 2 ** 8 - 1; + const kUnsignedShortMax = 2 ** 16 - 1; + const kUnsignedLongMax = 2 ** 32 - 1; + const empty = Buffer.alloc(0); + const rsaKeyGen = { + name: 'RSA-PSS', + modulusLength: 2048, + publicExponent: new Uint8Array([1, 0, 1]), + }; + const aesKeyParams = { name: 'AES-GCM', length: 128 }; + const hmacKeyParams = { + name: 'HMAC', + hash: 'SHA-256', + length: 128, + }; + const kmacKeyParams = { name: 'KMAC128', length: 128 }; + const cases = [ + ['RsaKeyGenParams', rsaKeyGen, + { modulusLength: kUnsignedLongMax }], + ['RsaHashedKeyGenParams', { ...rsaKeyGen, hash: 'SHA-256' }, + { modulusLength: kUnsignedLongMax }], + ['AesKeyGenParams', aesKeyParams, + { length: kUnsignedShortMax }], + ['RsaPssParams', { name: 'RSA-PSS', saltLength: 20 }, + { saltLength: kUnsignedLongMax }], + ['HmacKeyGenParams', hmacKeyParams, + { length: kUnsignedLongMax }], + ['HmacImportParams', hmacKeyParams, + { length: kUnsignedLongMax }], + ['CShakeParams', { name: 'cSHAKE128', outputLength: 256 }, + { outputLength: kUnsignedLongMax }], + ['Pbkdf2Params', { + name: 'PBKDF2', + salt: empty, + iterations: 1, + hash: 'SHA-256', + }, { iterations: kUnsignedLongMax }], + ['AesDerivedKeyParams', aesKeyParams, + { length: kUnsignedShortMax }], + ['AeadParams', { + name: 'AES-GCM', + iv: Buffer.alloc(12), + tagLength: 128, + }, { tagLength: kOctetMax }], + ['AesCtrParams', { + name: 'AES-CTR', + counter: Buffer.alloc(16), + length: 128, + }, { length: kOctetMax }], + ['Argon2Params', { + name: 'Argon2id', + nonce: Buffer.alloc(8), + parallelism: 1, + memory: 8, + passes: 1, + version: 0x13, + }, { + parallelism: kUnsignedLongMax, + memory: kUnsignedLongMax, + passes: kUnsignedLongMax, + version: kOctetMax, + }], + ['KmacKeyGenParams', kmacKeyParams, + { length: kUnsignedLongMax }], + ['KmacImportParams', kmacKeyParams, + { length: kUnsignedLongMax }], + ['KmacParams', { name: 'KMAC128', outputLength: 256 }, + { outputLength: kUnsignedLongMax }], + ['KangarooTwelveParams', { name: 'KT128', outputLength: 256 }, + { outputLength: kUnsignedLongMax }], + ['TurboShakeParams', { + name: 'TurboSHAKE128', + outputLength: 256, + domainSeparation: 0x1f, + }, { + outputLength: kUnsignedLongMax, + domainSeparation: kOctetMax, + }], + ]; + + for (const [dictionary, base, members] of cases) { + const converter = converters[dictionary]; + assertIdlDictionary(converter(base, opts), base); + + for (const [member, max] of Object.entries(members)) { + assert.throws( + () => converter({ ...base, [member]: -1 }, opts), { + name: 'TypeError', + code: 'ERR_OUT_OF_RANGE', + message: `${prefix}: ${member} in ${context} is outside ` + + `the expected range of 0 to ${max}.`, + }); + } + } +} + // DOMString { assert.strictEqual(converters.DOMString(1), '1'); diff --git a/test/parallel/test-whatwg-headers.js b/test/parallel/test-whatwg-headers.js new file mode 100644 index 000000000000..94610128ce11 --- /dev/null +++ b/test/parallel/test-whatwg-headers.js @@ -0,0 +1,245 @@ +'use strict'; + +// Tests below are not from WPT. + +require('../common'); +const assert = require('assert'); +const util = require('util'); + +{ + const headers = new Headers(); + assert.strictEqual(headers.get('content-type'), null); + assert.strictEqual(headers.has('content-type'), false); + assert.deepStrictEqual([...headers], []); + assert.deepStrictEqual(headers.getSetCookie(), []); +} + +{ + const headers = new Headers({ + 'Content-Type': 'text/plain', + 'Accept': 'application/json', + 'X-Custom': '1', + }); + assert.strictEqual(headers.get('content-type'), 'text/plain'); + assert.strictEqual(headers.get('Content-Type'), 'text/plain'); + assert.strictEqual(headers.get('ACCEPT'), 'application/json'); + assert.ok(headers.has('accept')); + assert.deepStrictEqual([...headers], [ + ['accept', 'application/json'], + ['content-type', 'text/plain'], + ['x-custom', '1'], + ]); +} + +{ + const headers = new Headers([ + ['X-A', '1'], + ['x-b', '2'], + ['X-A', '3'], + ]); + assert.strictEqual(headers.get('x-a'), '1, 3'); + assert.deepStrictEqual([...headers], [ + ['x-a', '1, 3'], + ['x-b', '2'], + ]); +} + +{ + const source = new Headers({ 'Content-Type': 'text/html' }); + source.append('Set-Cookie', 'a=b'); + source.append('Set-Cookie', 'c=d'); + const copy = new Headers(source); + assert.strictEqual(copy.get('content-type'), 'text/html'); + assert.deepStrictEqual(copy.getSetCookie(), ['a=b', 'c=d']); + assert.deepStrictEqual([...copy], [...source]); + copy.append('X-Copy', 'yes'); + assert.strictEqual(source.has('x-copy'), false); + source.append('Set-Cookie', 'e=f'); + assert.deepStrictEqual(copy.getSetCookie(), ['a=b', 'c=d']); +} + +{ + const headers = new Headers(); + headers.append('Accept', 'text/html'); + headers.append('accept', 'application/json'); + assert.strictEqual(headers.get('ACCEPT'), 'text/html, application/json'); + headers.set('ACCEPT', 'image/png'); + assert.strictEqual(headers.get('accept'), 'image/png'); + headers.delete('Accept'); + assert.strictEqual(headers.has('accept'), false); +} + +{ + const headers = new Headers(); + headers.append('Cookie', 'a=1'); + headers.append('cookie', 'b=2'); + assert.strictEqual(headers.get('cookie'), 'a=1; b=2'); +} + +{ + const headers = new Headers(); + headers.append('set-cookie', 'a=b'); + headers.append('Set-Cookie', 'c=d'); + assert.deepStrictEqual(headers.getSetCookie(), ['a=b', 'c=d']); + const cloned = headers.getSetCookie(); + cloned.push('e=f'); + assert.deepStrictEqual(headers.getSetCookie(), ['a=b', 'c=d']); + headers.set('set-cookie', 'only=one'); + assert.deepStrictEqual(headers.getSetCookie(), ['only=one']); + headers.delete('SET-COOKIE'); + assert.deepStrictEqual(headers.getSetCookie(), []); +} + +{ + const headers = new Headers(); + headers.set('a', ' value '); + assert.strictEqual(headers.get('a'), 'value'); + headers.set('b', '\r\n\t trimmed\t\n'); + assert.strictEqual(headers.get('b'), 'trimmed'); + headers.set('c', '\r'); + assert.strictEqual(headers.get('c'), ''); + headers.set('d', '\n'); + assert.strictEqual(headers.get('d'), ''); +} + +{ + const headers = new Headers(); + headers.set('a', ['b', 'c']); + assert.strictEqual(headers.get('a'), 'b,c'); + headers.set('b', null); + assert.strictEqual(headers.get('b'), 'null'); + headers.set('c', 1); + assert.strictEqual(headers.get('c'), '1'); +} + +{ + const headers = new Headers({ + c: '5', + b: ['3', '4'], + a: ['1', '2'], + }); + assert.deepStrictEqual([...headers.entries()], [ + ['a', '1,2'], + ['b', '3,4'], + ['c', '5'], + ]); +} + +{ + const init = [ + ['foo', '123'], + ['bar', '456'], + ]; + const headers = new Headers(init); + for (const [key, val] of headers) { + headers.delete(key); + headers.set(`x-${key}`, val); + } + assert.deepStrictEqual([...headers], [ + ['foo', '123'], + ['x-x-bar', '456'], + ]); +} + +{ + const headers = new Headers([ + ['b', '2'], + ['c', '3'], + ['e', '5'], + ]); + headers.append('d', '4'); + headers.append('a', '1'); + headers.append('f', '6'); + headers.append('c', '7'); + headers.append('abc', '8'); + assert.deepStrictEqual([...headers], [ + ['a', '1'], + ['abc', '8'], + ['b', '2'], + ['c', '3, 7'], + ['d', '4'], + ['e', '5'], + ['f', '6'], + ]); +} + +{ + const headers = new Headers({ 'Content-Type': 'application/json' }); + headers.set('Authorization', 'Bearer token'); + assert.strictEqual( + util.inspect(headers, { depth: 1 }), + "Headers { 'Content-Type': 'application/json', Authorization: 'Bearer token' }", + ); +} + +{ + const headers = new Headers(); + assert.throws(() => headers.get(), TypeError); + assert.throws(() => headers.has(), TypeError); + assert.throws(() => headers.delete(), TypeError); + assert.throws(() => headers.append('a'), TypeError); + assert.throws(() => headers.set('a'), TypeError); + assert.throws(() => headers.append('invalid @ name', 'x'), TypeError); + assert.throws(() => headers.set('a', 'a\nb'), TypeError); + assert.throws(() => headers.set('a', 'a\rb'), TypeError); + assert.throws(() => headers.set('a', 'a\0b'), TypeError); + assert.throws(() => headers.set(Symbol('x'), 'y'), TypeError); + assert.throws(() => headers.set('a', Symbol('y')), TypeError); + assert.throws(() => headers.set('', 'x'), TypeError); + assert.throws(() => headers.set('a', 'héllo\u0100'), TypeError); + assert.throws(() => new Headers(1), TypeError); + assert.throws(() => new Headers('1'), TypeError); + assert.throws(() => new Headers([['undici', 'fetch'], ['fetch']]), TypeError); +} + +{ + assert.throws(() => Headers.prototype.get.call(null, 'a'), { + name: 'TypeError', + code: 'ERR_INVALID_THIS', + }); + assert.throws(() => Headers.prototype.append.call({}, 'a', 'b'), { + name: 'TypeError', + code: 'ERR_INVALID_THIS', + }); +} + +{ + assert.strictEqual(Headers.prototype.append.length, 2); + assert.strictEqual(Headers.prototype.constructor.length, 0); + assert.strictEqual(Headers.prototype.delete.length, 1); + assert.strictEqual(Headers.prototype.get.length, 1); + assert.strictEqual(Headers.prototype.has.length, 1); + assert.strictEqual(Headers.prototype.set.length, 2); + assert.strictEqual(Headers.prototype.entries, Headers.prototype[Symbol.iterator]); + assert.strictEqual(Headers.prototype[Symbol.toStringTag], 'Headers'); + assert.strictEqual(Object.prototype.toString.call(Headers.prototype), '[object Headers]'); +} + +{ + const headers = new Headers(); + headers.set('content-type', 'text/plain'); + assert.strictEqual(headers.delete('content-type'), undefined); + assert.strictEqual(headers.delete('missing'), undefined); + assert.strictEqual(headers.set('a', 'b'), undefined); +} + +{ + const headers = new Headers(); + for (const name of [ + 'content-type', + 'accept', + 'user-agent', + 'cache-control', + 'set-cookie', + ]) { + headers.set(name, 'value'); + assert.strictEqual(headers.get(name), 'value'); + assert.ok(headers.has(name)); + } +} + +{ + const headers = new Headers(); + headers.append('fhqwhgads', `a${'\t'.repeat(1000)}a`); + assert.strictEqual(headers.get('fhqwhgads'), `a${'\t'.repeat(1000)}a`); +} diff --git a/test/parallel/test-whatwg-readablestream-byob-read-min.js b/test/parallel/test-whatwg-readablestream-byob-read-min.js new file mode 100644 index 000000000000..c428caa83478 --- /dev/null +++ b/test/parallel/test-whatwg-readablestream-byob-read-min.js @@ -0,0 +1,41 @@ +'use strict'; +const common = require('../common'); +const assert = require('node:assert'); + +const { + ReadableStream, +} = require('node:stream/web'); + +// Validation of the options.min argument of ReadableStreamBYOBReader.read() +// must reject with the same errors regardless of how the checks are implemented internally. + +const reader = new ReadableStream({ type: 'bytes' }) + .getReader({ mode: 'byob' }); + +(async () => { + // A null min is not covered here: `options?.min ?? 1` turns it into + // the default before validation, so it never reaches the type check. + for (const min of ['1', true, {}, [], 1n]) { + await assert.rejects( + reader.read(new Uint8Array(8), { min }), + { code: 'ERR_INVALID_ARG_TYPE' }, + ); + } + + for (const min of [NaN, 1.5, 0, -1]) { + await assert.rejects( + reader.read(new Uint8Array(8), { min }), + { code: 'ERR_INVALID_ARG_VALUE' }, + ); + } + + await assert.rejects( + reader.read(new Uint8Array(8), { min: 9 }), + { code: 'ERR_OUT_OF_RANGE' }, + ); + + await assert.rejects( + reader.read(new DataView(new ArrayBuffer(8)), { min: 9 }), + { code: 'ERR_OUT_OF_RANGE' }, + ); +})().then(common.mustCall()); diff --git a/test/parallel/test-whatwg-url-custom-setters.js b/test/parallel/test-whatwg-url-custom-setters.js index b98bf5d8d3b3..061ccf6f4480 100644 --- a/test/parallel/test-whatwg-url-custom-setters.js +++ b/test/parallel/test-whatwg-url-custom-setters.js @@ -39,6 +39,32 @@ const additionalTestCases = } } +// The parser can produce a serialization it rejects when parsing it back: a +// Unicode host encodes to an `xn--xn--` label that the punycode decoder turns +// down. Setters reparse `href`, so the failure must not take the process down. +// Implementations backed by ICU accept that label, and ada does too as of +// https://github.com/ada-url/idna/pull/72, so this URL round-trips once that +// lands here and the setters below apply as usual. +test(function() { + const url = new URL('http:\u{1F600}xn-'); + const setters = { + hostname: 'example.com', + host: 'example.com:8080', + protocol: 'https:', + pathname: '/path', + search: '?search', + hash: '#hash', + port: '8080', + username: 'username', + password: 'password', + }; + + for (const [property, value] of Object.entries(setters)) { + url[property] = value; + assert_equals(typeof url.href, 'string', `Setting ${property} does not crash`); + } +}, 'URL: setting properties with an unparsable serialized URL'); + { const url = new URL('http://example.com/'); const obj = { diff --git a/test/parallel/test-whatwg-url-parse-fast-path.js b/test/parallel/test-whatwg-url-parse-fast-path.js new file mode 100644 index 000000000000..e6c295f039a3 --- /dev/null +++ b/test/parallel/test-whatwg-url-parse-fast-path.js @@ -0,0 +1,88 @@ +'use strict'; + +// Covers the URL constructor parse paths that avoid a UTF-8 copy and/or +// reuse the input string when it is already a serialized ASCII href. + +const { hasIntl } = require('../common'); +const assert = require('assert'); + +const alreadySerialized = [ + 'https://nodejs.org/en/blog/', + 'http://nodejs.org:89/docs/latest/api/foo/bar/qua/13949281/0f28b/' + + '/5d49/b3020/url.html#test?payload1=true&payload2=false&test=1' + + '&benchmark=3&foo=38.38.011.293&bar=1234834910480&test=19299&3992&' + + 'key=f5c65e1e98fe07e648249ad41e1cfdb0', + 'https://user:pass@example.com/path?search=1', + 'file:///foo/bar/test/node.js', + 'ws://localhost:9229/f46db715-70df-43ad-a359-7f9949f39868', +]; + +for (const href of alreadySerialized) { + const url = new URL(href); + assert.strictEqual(url.href, href); + assert.strictEqual(URL.parse(href).href, href); + assert.strictEqual(URL.canParse(href), true); +} + +// Special-scheme URLs with an empty path gain a trailing slash. +{ + const url = new URL('https://example.com'); + assert.strictEqual(url.href, 'https://example.com/'); + assert.strictEqual(url.pathname, '/'); +} + +// Dot-segment normalization must still rewrite the path. +{ + const url = new URL('https://example.org/./a/../b/./c'); + assert.strictEqual(url.href, 'https://example.org/b/c'); + assert.strictEqual(url.pathname, '/b/c'); +} + +// Relative resolution against a base URL. +{ + const url = new URL('/path?x=1#h', 'https://example.com:8443/base'); + assert.strictEqual(url.href, 'https://example.com:8443/path?x=1#h'); + assert.strictEqual(url.host, 'example.com:8443'); +} + +// Non-string input is still stringified. +{ + const url = new URL({ toString: () => 'https://example.com/from-object' }); + assert.strictEqual(url.href, 'https://example.com/from-object'); +} + +// Invalid input still throws from the constructor and is null from parse(). +{ + assert.throws(() => new URL('not a url'), { + code: 'ERR_INVALID_URL', + name: 'TypeError', + }); + assert.strictEqual(URL.parse('not a url'), null); + assert.strictEqual(URL.canParse('not a url'), false); +} + +// Unpaired surrogates must not be returned as-is from href. +{ + const input = 'https://example.com/\uD800'; + const url = new URL(input); + assert.notStrictEqual(url.href, input); + assert.ok(url.href.startsWith('https://example.com/')); +} + +if (hasIntl) { + const url = new URL('http://你好你好.在线'); + assert.ok(url.hostname.startsWith('xn--')); + assert.ok(url.href.startsWith('http://xn--')); +} + +// Setters re-parse the existing href; keep component updates correct. +{ + const url = new URL('https://example.com/old'); + url.pathname = '/new'; + url.search = 'q=1'; + url.hash = 'frag'; + assert.strictEqual(url.href, 'https://example.com/new?q=1#frag'); + assert.strictEqual(url.pathname, '/new'); + assert.strictEqual(url.search, '?q=1'); + assert.strictEqual(url.hash, '#frag'); +} diff --git a/test/parallel/test-whatwg-url-searchparams-fast-path.js b/test/parallel/test-whatwg-url-searchparams-fast-path.js new file mode 100644 index 000000000000..2dbb38f88aa5 --- /dev/null +++ b/test/parallel/test-whatwg-url-searchparams-fast-path.js @@ -0,0 +1,116 @@ +'use strict'; + +// Tests for the URLSearchParams parse / serialize / toUSVString fast paths. + +require('../common'); +const assert = require('assert'); + +{ + const params = new URLSearchParams('?a=b'); + assert.strictEqual(params.toString(), 'a=b'); + assert.strictEqual(params.get('a'), 'b'); +} + +{ + const params = new URLSearchParams('a=b&c'); + assert.deepStrictEqual([...params], [['a', 'b'], ['c', '']]); +} + +{ + const params = new URLSearchParams('&a&&& &&&&&a+b=& c&m%c3%b8%c3%b8'); + assert.ok(params.has('a')); + assert.ok(params.has('a b')); + assert.ok(params.has(' ')); + assert.ok(params.has(' c')); + assert.ok(params.has('møø')); + assert.strictEqual(params.get('a+b'), null); +} + +{ + const params = new URLSearchParams('id=0&value=%'); + assert.strictEqual(params.get('id'), '0'); + assert.strictEqual(params.get('value'), '%'); +} + +{ + const params = new URLSearchParams('b=%2sf%2a'); + assert.strictEqual(params.get('b'), '%2sf*'); +} + +{ + const params = new URLSearchParams('a=b=c&d='); + assert.strictEqual(params.get('a'), 'b=c'); + assert.strictEqual(params.get('d'), ''); +} + +{ + const params = new URLSearchParams('foo=bar&baz=quux'); + assert.strictEqual(params.toString(), 'foo=bar&baz=quux'); + assert.strictEqual(params.toString(), 'foo=bar&baz=quux'); + params.append('xyzzy', 'thud'); + assert.strictEqual(params.toString(), 'foo=bar&baz=quux&xyzzy=thud'); + params.set('baz', 'updated'); + assert.strictEqual(params.toString(), 'foo=bar&baz=updated&xyzzy=thud'); + params.delete('foo'); + assert.strictEqual(params.toString(), 'baz=updated&xyzzy=thud'); + params.sort(); + assert.strictEqual(params.toString(), 'baz=updated&xyzzy=thud'); +} + +{ + const original = new URLSearchParams('a=1&b=2'); + assert.strictEqual(original.toString(), 'a=1&b=2'); + const copy = new URLSearchParams(original); + assert.strictEqual(copy.toString(), 'a=1&b=2'); + original.append('c', '3'); + assert.strictEqual(original.toString(), 'a=1&b=2&c=3'); + assert.strictEqual(copy.toString(), 'a=1&b=2'); +} + +{ + const params = new URLSearchParams({ foo: 'bar', baz: 1, xyzzy: false }); + assert.strictEqual(params.get('foo'), 'bar'); + assert.strictEqual(params.get('baz'), '1'); + assert.strictEqual(params.get('xyzzy'), 'false'); + assert.strictEqual(params.toString(), 'foo=bar&baz=1&xyzzy=false'); +} + +{ + const params = new URLSearchParams([['foo', 'bar'], ['baz', 'quux']]); + assert.strictEqual(params.toString(), 'foo=bar&baz=quux'); + assert.ok(params.has('foo', 'bar')); + assert.deepStrictEqual(params.getAll('foo'), ['bar']); +} + +{ + const params = new URLSearchParams('\uD83D'); + assert.strictEqual(params.keys().next().value, '\uFFFD'); + assert.strictEqual(params.toString(), '%EF%BF%BD='); +} + +{ + const params = new URLSearchParams('a=b+c&d=%20'); + assert.strictEqual(params.get('a'), 'b c'); + assert.strictEqual(params.get('d'), ' '); + assert.strictEqual(params.toString(), 'a=b+c&d=+'); +} + +{ + // Fake percent-encoding must not be UTF-8-decoded into U+FFFD. + const params = new URLSearchParams('foo=%©ar&baz=%A©uux&xyzzy=%©ud'); + assert.deepStrictEqual([...params], [ + ['foo', '%©ar'], + ['baz', '%A©uux'], + ['xyzzy', '%©ud'], + ]); + assert.strictEqual(params.toString(), 'foo=%25%C2%A9ar&baz=%25A%C2%A9uux&xyzzy=%25%C2%A9ud'); +} + +{ + const url = new URL('https://example.org/?foo=bar'); + const params = url.searchParams; + assert.strictEqual(params.toString(), 'foo=bar'); + params.append('baz', 'quux'); + assert.strictEqual(url.search, '?foo=bar&baz=quux'); + assert.strictEqual(params.toString(), 'foo=bar&baz=quux'); +} diff --git a/test/parallel/test-zlib-zstd-pledged-src-size.js b/test/parallel/test-zlib-zstd-pledged-src-size.js index 4a5f27394c66..a0b1babd3f73 100644 --- a/test/parallel/test-zlib-zstd-pledged-src-size.js +++ b/test/parallel/test-zlib-zstd-pledged-src-size.js @@ -3,6 +3,11 @@ const common = require('../common'); const assert = require('assert'); const zlib = require('zlib'); +const pledgedSrcSizeError = { + code: 'ZSTD_error_srcSize_wrong', + errno: zlib.constants.ZSTD_error_srcSize_wrong, +}; + function compressWithPledgedSrcSize({ pledgedSrcSize, actualSrcSize }) { return new Promise((resolve, reject) => { const compressor = zlib.createZstdCompress({ pledgedSrcSize }); @@ -18,23 +23,59 @@ function compressWithPledgedSrcSize({ pledgedSrcSize, actualSrcSize }) { // Compression should only succeed if sizes match assert.strictEqual(pledgedSrcSize, actualSrcSize); }, (error) => { - assert.strictEqual(error.code, 'ZSTD_error_srcSize_wrong'); + assert.strictEqual(error.code, pledgedSrcSizeError.code); + assert.strictEqual(error.errno, pledgedSrcSizeError.errno); // Size error should only happen when sizes do not match assert.notStrictEqual(pledgedSrcSize, actualSrcSize); }).then(common.mustCall()); } -compressWithPledgedSrcSize({ pledgedSrcSize: 0, actualSrcSize: 0 }); +function compressSyncWithPledgedSrcSize({ pledgedSrcSize, actualSrcSize }) { + const compress = () => zlib.zstdCompressSync( + 'x'.repeat(actualSrcSize), + { pledgedSrcSize }, + ); + + if (pledgedSrcSize === actualSrcSize) { + compress(); + } else { + assert.throws(compress, pledgedSrcSizeError); + } +} -compressWithPledgedSrcSize({ pledgedSrcSize: 0, actualSrcSize: 42 }); +const testCases = [ + { pledgedSrcSize: 0, actualSrcSize: 0 }, + { pledgedSrcSize: 0, actualSrcSize: 42 }, + { pledgedSrcSize: 1, actualSrcSize: 42 }, + { pledgedSrcSize: 13, actualSrcSize: 42 }, + { pledgedSrcSize: 42, actualSrcSize: 0 }, + { pledgedSrcSize: 42, actualSrcSize: 13 }, + { pledgedSrcSize: 42, actualSrcSize: 42 }, +]; -compressWithPledgedSrcSize({ pledgedSrcSize: 13, actualSrcSize: 42 }); +for (const testCase of testCases) { + compressWithPledgedSrcSize(testCase); + compressSyncWithPledgedSrcSize(testCase); +} -compressWithPledgedSrcSize({ pledgedSrcSize: 42, actualSrcSize: 0 }); +const retryInput = Buffer.allocUnsafe(256 * 1024); +let randomState = 0x12345678; +for (let i = 0; i < retryInput.length; i++) { + randomState = (Math.imul(randomState, 1664525) + 1013904223) | 0; + retryInput[i] = randomState >>> 24; +} -compressWithPledgedSrcSize({ pledgedSrcSize: 42, actualSrcSize: 13 }); +const compressed = zlib.zstdCompressSync(retryInput, { + pledgedSrcSize: retryInput.length, + chunkSize: 64, +}); +assert.ok(compressed.length > 64); +assert.deepStrictEqual(zlib.zstdDecompressSync(compressed), retryInput); -compressWithPledgedSrcSize({ pledgedSrcSize: 42, actualSrcSize: 42 }); +assert.throws(() => zlib.zstdCompressSync(retryInput, { + pledgedSrcSize: retryInput.length - 1, + chunkSize: 64, +}), pledgedSrcSizeError); function assertInvalidPledgedSrcSize(pledgedSrcSize, expected) { assert.throws( diff --git a/test/pseudo-tty/test-set-raw-mode-modes.js b/test/pseudo-tty/test-set-raw-mode-modes.js new file mode 100644 index 000000000000..8280aacb0a85 --- /dev/null +++ b/test/pseudo-tty/test-set-raw-mode-modes.js @@ -0,0 +1,43 @@ +'use strict'; +require('../common'); +const assert = require('assert'); +const { spawnSync } = require('child_process'); + +function isOnlcrEnabled() { + const { stdout, stderr, status } = spawnSync('stty', ['-a'], { + encoding: 'utf8', + stdio: ['inherit', 'pipe', 'pipe'], + }); + + assert.strictEqual(status, 0, stderr); + return /(?:^|[\s;])onlcr(?:[\s;]|$)/.test(stdout); +} + +process.stdin.setRawMode(true); +console.log(`raw=${isOnlcrEnabled()}`); +assert.strictEqual(process.stdin.isRaw, true); +assert.strictEqual(process.stdin.rawMode, 'raw'); + +process.stdin.setRawMode(false); +console.log(`normal=${process.stdin.isRaw}`); +assert.strictEqual(process.stdin.rawMode, false); +assert.throws( + () => process.stdin.setRawMode('raw-vt'), + { + code: 'ERR_INVALID_ARG_VALUE', + name: 'TypeError', + }); +assert.strictEqual(process.stdin.rawMode, false); + +process.stdin.setRawMode('raw'); +console.log(`raw-string=${isOnlcrEnabled()}`); +assert.strictEqual(process.stdin.isRaw, true); +assert.strictEqual(process.stdin.rawMode, 'raw'); + +process.stdin.setRawMode(false); +process.stdin.setRawMode('io'); +console.log(`io=${isOnlcrEnabled()}`); +assert.strictEqual(process.stdin.isRaw, true); +assert.strictEqual(process.stdin.rawMode, 'io'); + +process.stdin.setRawMode(false); diff --git a/test/pseudo-tty/test-set-raw-mode-modes.out b/test/pseudo-tty/test-set-raw-mode-modes.out new file mode 100644 index 000000000000..e449081d60cb --- /dev/null +++ b/test/pseudo-tty/test-set-raw-mode-modes.out @@ -0,0 +1,4 @@ +raw=true +normal=false +raw-string=true +io=false diff --git a/test/pummel/test-heapdump-fs-promise.js b/test/pummel/test-heapdump-fs-promise.js index 429359e1a6be..5b259ea2dd32 100644 --- a/test/pummel/test-heapdump-fs-promise.js +++ b/test/pummel/test-heapdump-fs-promise.js @@ -20,7 +20,7 @@ fs.stat(__filename); validateByRetainingPathFromNodes(nodes, 'Node / FSReqPromise', [ { node_name: 'FSReqPromise', edge_name: 'native_to_javascript' }, ]); - validateByRetainingPathFromNodes(nodes, 'Node / FSReqPromise', [ - { node_name: 'Node / AliasedFloat64Array', edge_name: 'stats_field_array' }, - ]); + // The stats field array is allocated lazily when the request resolves + // with stats, so it is not retained by a request that is still pending + // and cannot be observed in a heap snapshot. } diff --git a/test/sea/test-single-executable-application-exec-argv-extension-cli.js b/test/sea/test-single-executable-application-exec-argv-extension-cli.js index 738a2bc98b6c..6457579034c9 100644 --- a/test/sea/test-single-executable-application-exec-argv-extension-cli.js +++ b/test/sea/test-single-executable-application-exec-argv-extension-cli.js @@ -23,7 +23,11 @@ const outputFile = generateSEA(fixtures.path('sea', 'exec-argv-extension-cli')); // Test that --node-options works with execArgvExtension: "cli" spawnSyncAndAssert( outputFile, - ['--node-options=--max-old-space-size=1024', 'user-arg1', 'user-arg2'], + [ + '--node-options=--no-warnings --max-old-space-size=1024', + 'user-arg1', + 'user-arg2', + ], { env: { ...process.env, diff --git a/test/sea/test-single-executable-blob-config-errors.js b/test/sea/test-single-executable-blob-config-errors.js index 322f430aad81..9562faad6b79 100644 --- a/test/sea/test-single-executable-blob-config-errors.js +++ b/test/sea/test-single-executable-blob-config-errors.js @@ -47,6 +47,24 @@ const { spawnSyncAndAssert } = require('../common/child_process'); }); } +{ + tmpdir.refresh(); + const config = tmpdir.resolve('trailing-content.json'); + writeFileSync( + config, + '{"main":"bundle.js","output":"sea.blob"}{}', + 'utf8', + ); + spawnSyncAndAssert( + process.execPath, + ['--experimental-sea-config', config], { + cwd: tmpdir.path, + }, { + status: 1, + stderr: /TRAILING_CONTENT/, + }); +} + { tmpdir.refresh(); const config = tmpdir.resolve('empty.json'); diff --git a/test/sequential/test-cli-syntax-bad.js b/test/sequential/test-cli-syntax-bad.js index e967ff36ac28..0cf9d020b30f 100644 --- a/test/sequential/test-cli-syntax-bad.js +++ b/test/sequential/test-cli-syntax-bad.js @@ -21,6 +21,9 @@ const syntaxErrorRE = /^SyntaxError: \b/m; 'syntax/bad_syntax', 'syntax/bad_syntax_shebang.js', 'syntax/bad_syntax_shebang', + // A `.js` file with no `"type"` in the nearest package.json, whose module + // syntax makes it load as ESM. Refs: https://github.com/nodejs/node/issues/65202 + 'syntax/bad_syntax_esm_ambiguous.js', ].forEach((file) => { const path = fixtures.path(file); diff --git a/test/parallel/test-net-listen-ipv6only.js b/test/sequential/test-net-listen-ipv6only.js similarity index 68% rename from test/parallel/test-net-listen-ipv6only.js rename to test/sequential/test-net-listen-ipv6only.js index a329011bcc8a..c85f813bc08b 100644 --- a/test/parallel/test-net-listen-ipv6only.js +++ b/test/sequential/test-net-listen-ipv6only.js @@ -11,9 +11,13 @@ const net = require('net'); const host = '::'; const server = net.createServer(); +// Use a fixed port and run this test sequentially. The assertion below relies +// on nothing else listening on the IPv4 side of the chosen port; with an +// ephemeral port under parallel execution another test can occupy that IPv4 +// port, making the connection succeed instead of being refused. server.listen({ host, - port: 0, + port: common.PORT, ipv6Only: true, }, common.mustCall(() => { const { port } = server.address(); diff --git a/test/sequential/test-performance-eventloopdelay.js b/test/sequential/test-performance-eventloopdelay.js index ddd33372ec5e..ede729514937 100644 --- a/test/sequential/test-performance-eventloopdelay.js +++ b/test/sequential/test-performance-eventloopdelay.js @@ -9,6 +9,18 @@ const { } = require('perf_hooks'); const { sleep } = require('internal/util'); +function runEventLoopIterations(iterations, callback) { + let remaining = iterations; + function tick() { + if (--remaining > 0) { + setImmediate(tick); + } else { + callback(); + } + } + setImmediate(tick); +} + { const histogram = monitorEventLoopDelay(); assert(histogram); @@ -125,12 +137,16 @@ const { sleep } = require('internal/util'); } { + const iterations = 10; const histogram = monitorEventLoopDelay({ samplePerIteration: true }); histogram.enable(); - setTimeout(common.mustCall(() => { + runEventLoopIterations(iterations, common.mustCall(() => { histogram.disable(); - assert(histogram.count > 0, - `Expected samples to be recorded, got count=${histogram.count}`); + assert( + histogram.count >= iterations - 1, + `Expected at least ${iterations - 1} samples for ${iterations} iterations, ` + + `got ${histogram.count}` + ); assert(histogram.min > 0); assert(histogram.max > 0); assert(histogram.mean > 0); @@ -146,7 +162,7 @@ const { sleep } = require('internal/util'); assert(Number.isNaN(histogram.mean)); assert(Number.isNaN(histogram.stddev)); assert.strictEqual(histogram.percentiles.size, 1); - }), common.platformTimeout(20)); + })); } { @@ -158,65 +174,40 @@ const { sleep } = require('internal/util'); assert.strictEqual(histogram.disable(), false); // Already disabled, no-op // Re-enabling after disable should work assert.strictEqual(histogram.enable(), true); - setTimeout(common.mustCall(() => { + runEventLoopIterations(10, common.mustCall(() => { histogram.disable(); assert(histogram.count > 0, `Expected samples after re-enable, got count=${histogram.count}`); - }), common.platformTimeout(20)); + })); } { // Verify that samplePerIteration records exactly one sample per event loop iteration. - const N = 10; + // It should do so independently of the timer resolution used by the legacy + // monitorEventLoopDelay path. + const iterations = 10; const histogram = monitorEventLoopDelay({ samplePerIteration: true }); - histogram.enable(); - - let iterations = 0; - const verify = common.mustCall(() => { - histogram.disable(); - assert( - histogram.count >= N - 1, - `Expected at least ${N - 1} samples for ${N} iterations, got ${histogram.count}` - ); - }); - - function tick() { - if (++iterations < N) { - setImmediate(tick); - } else { - verify(); - } - } - setImmediate(tick); -} - -{ - // samplePerIteration should sample per event loop iteration, independent of - // the timer resolution used by the legacy monitorEventLoopDelay path. - const N = 10; - const histogram = monitorEventLoopDelay({ + const largeResolutionHistogram = monitorEventLoopDelay({ samplePerIteration: true, resolution: 60 * 1000, }); histogram.enable(); + largeResolutionHistogram.enable(); - let iterations = 0; - const verify = common.mustCall(() => { + runEventLoopIterations(iterations, common.mustCall(() => { histogram.disable(); + largeResolutionHistogram.disable(); assert( - histogram.count >= N - 1, - `Expected samples despite large resolution, got count=${histogram.count}` + histogram.count >= iterations - 1, + `Expected at least ${iterations - 1} samples for ${iterations} iterations, ` + + `got ${histogram.count}` ); - }); - - function tick() { - if (++iterations < N) { - setImmediate(tick); - } else { - verify(); - } - } - setImmediate(tick); + assert( + largeResolutionHistogram.count >= iterations - 1, + `Expected samples despite large resolution, ` + + `got count=${largeResolutionHistogram.count}` + ); + })); } // Make sure that the histogram instances can be garbage-collected without diff --git a/test/test-runner/test-output-dot-reporter-coverage-threshold.mjs b/test/test-runner/test-output-dot-reporter-coverage-threshold.mjs new file mode 100644 index 000000000000..e764863a6b0b --- /dev/null +++ b/test/test-runner/test-output-dot-reporter-coverage-threshold.mjs @@ -0,0 +1,15 @@ +// Test that the output of test-runner/output/dot_reporter_coverage_threshold.js matches +// test-runner/output/dot_reporter_coverage_threshold.snapshot +import * as common from '../common/index.mjs'; +import * as fixtures from '../common/fixtures.mjs'; +import { spawnAndAssert, specTransform, ensureCwdIsProjectRoot } from '../common/assertSnapshot.js'; + +if (!process.features.inspector) { + common.skip('inspector support required'); +} + +ensureCwdIsProjectRoot(); +await spawnAndAssert( + fixtures.path('test-runner/output/dot_reporter_coverage_threshold.js'), + specTransform, +); diff --git a/test/test-runner/test-output-junit-classname-hierarchy.mjs b/test/test-runner/test-output-junit-classname-hierarchy.mjs new file mode 100644 index 000000000000..737cefd89eca --- /dev/null +++ b/test/test-runner/test-output-junit-classname-hierarchy.mjs @@ -0,0 +1,12 @@ +// Test that the output of test-runner/output/junit_classname_hierarchy.js matches +// test-runner/output/junit_classname_hierarchy.snapshot +import '../common/index.mjs'; +import * as fixtures from '../common/fixtures.mjs'; +import { spawnAndAssert, junitTransform, ensureCwdIsProjectRoot } from '../common/assertSnapshot.js'; + +ensureCwdIsProjectRoot(); +await spawnAndAssert( + fixtures.path('test-runner/output/junit_classname_hierarchy.js'), + junitTransform, + { flags: ['--test-reporter=junit'] }, +); diff --git a/test/test-runner/test-output-junit-empty-diagnostic.mjs b/test/test-runner/test-output-junit-empty-diagnostic.mjs new file mode 100644 index 000000000000..5c1cf4a2b382 --- /dev/null +++ b/test/test-runner/test-output-junit-empty-diagnostic.mjs @@ -0,0 +1,11 @@ +// Test that the output of test-runner/output/junit_empty_diagnostic.js matches +// test-runner/output/junit_empty_diagnostic.snapshot +import '../common/index.mjs'; +import * as fixtures from '../common/fixtures.mjs'; +import { spawnAndAssert, junitTransform, ensureCwdIsProjectRoot } from '../common/assertSnapshot.js'; + +ensureCwdIsProjectRoot(); +await spawnAndAssert( + fixtures.path('test-runner/output/junit_empty_diagnostic.js'), + junitTransform, +); diff --git a/test/wpt/status/streams.json b/test/wpt/status/streams.json index 2268ffcc87ac..968b33597651 100644 --- a/test/wpt/status/streams.json +++ b/test/wpt/status/streams.json @@ -43,13 +43,5 @@ }, "transform-streams/invalid-realm.tentative.window.js": { "skip": "Browser-specific test" - }, - "writable-streams/aborting.any.js": { - "fail": { - "note": "Recursive abort() call from within an abort algorithm triggers ERR_INTERNAL_ASSERTION", - "expected": [ - "recursive abort() call from abort() aborting signal" - ] - } } } diff --git a/tools/actions/commit-queue.sh b/tools/actions/commit-queue.sh index 2ee7694aedd2..9fb74ed9cad8 100755 --- a/tools/actions/commit-queue.sh +++ b/tools/actions/commit-queue.sh @@ -2,52 +2,82 @@ set -xe -OWNER=$1 -REPOSITORY=$2 -shift 2 - UPSTREAM=origin DEFAULT_BRANCH=main COMMIT_QUEUE_LABEL="commit-queue" COMMIT_QUEUE_FAILED_LABEL="commit-queue-failed" +cqurl="${GITHUB_SERVER_URL:?}/${GITHUB_REPOSITORY:?}/actions/runs/${GITHUB_RUN_ID:?}" + +escape_code_block_or_line() { + case $1 in + *" +"*|'') fence='```' sep=' +' ;; + *[![:space:]]*) fence='`' sep=' ' ;; + *) fence='`' sep='' ;; + esac + while case $1 in *"$fence"*) ;; *) false ;; esac; do + fence=$fence'`' + done + printf '%s%s%s%s%s\n' "$fence" "$sep" "$1" "$sep" "$fence" +} + commit_queue_failed() { pr=$1 + reported_failure=${2:-} + + gh -R "$GITHUB_REPOSITORY" pr edit "$pr" --add-label "${COMMIT_QUEUE_FAILED_LABEL}" --remove-label "${COMMIT_QUEUE_LABEL}" + + last_output_line=$(awk 'NF { line = $0 } END { sub(/^[[:space:]]*/, "", line); print line }' output) + # shellcheck disable=SC2016 + missing_policy_message='ℹ Add `commit-queue-squash` label to land the PR as one commit, or `commit-queue-rebase` to land as separate commits.' + if [ "$last_output_line" = "$missing_policy_message" ]; then + failure_body='This pull request has multiple commits, but no landing policy was selected. + +Add https://github.com/nodejs/node/labels/commit-queue-squash to land it as one commit, or https://github.com/nodejs/node/labels/commit-queue-rebase to land the commits separately.' + else + if [ -z "$reported_failure" ]; then + reported_failure=$(grep -e '✘' -e '⚠' output | tail -n 10) + fi + if [ -z "$reported_failure" ]; then + reported_failure=$(tail -n 10 output) + fi + if [ -z "$reported_failure" ]; then + reported_failure='No failure reason was reported.' + fi + failure_body=$(escape_code_block_or_line "$reported_failure") + fi + + raw_output=$(cat output) + + body="### Commit Queue failed + +$failure_body - gh pr edit "$pr" --add-label "${COMMIT_QUEUE_FAILED_LABEL}" +The pull request was removed from the Commit Queue and labeled https://github.com/nodejs/node/labels/commit-queue-failed. After resolving the failure, remove that label and add https://github.com/nodejs/node/labels/commit-queue to retry. - # shellcheck disable=SC2154 - cqurl="${GITHUB_SERVER_URL}/${OWNER}/${REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" - body="
Commit Queue failed
$(sed -e 's/&/\&/g' -e 's//\>/g' output)
$cqurl
" +
+Full Commit Queue output + +$(escape_code_block_or_line "$raw_output") + +
+ +[View workflow run]($cqurl)" echo "$body" - gh pr comment "$pr" --body "$body" + gh -R "$GITHUB_REPOSITORY" pr comment "$pr" --body "$body" rm output } -# TODO(mmarchini): should this be set with whoever added the label for each PR? -git config --local user.email "github-bot@iojs.org" -git config --local user.name "Node.js GitHub Bot" +SHOULD_ABORT= for pr in "$@"; do - gh pr view "$pr" --json labels --jq ".labels" > labels.json - # Skip PR if CI was requested - if jq -e 'map(.name) | index("request-ci")' < labels.json; then - echo "pr ${pr} skipped, waiting for CI to start" - continue - fi - - # Skip PR if CI is still running - if gh pr checks "$pr" | grep -q "\spending\s"; then - echo "pr ${pr} skipped, CI still running" - continue - fi - - # Delete the commit queue label - gh pr edit "$pr" --remove-label "$COMMIT_QUEUE_LABEL" - + gh -R "$GITHUB_REPOSITORY" pr view "$pr" --json labels --jq ".labels" > labels.json + if jq -e 'map(.name) | index("commit-queue-squash")' < labels.json; then MULTIPLE_COMMIT_POLICY="--fixupAll" elif jq -e 'map(.name) | index("commit-queue-rebase")' < labels.json; then @@ -56,6 +86,14 @@ for pr in "$@"; do MULTIPLE_COMMIT_POLICY="--oneCommitMax" fi + if [ -n "$SHOULD_ABORT" ]; then + # If `git node land --abort` fails, we're in unknown state. Better to stop + # the script here, current PR was removed from the queue so it shouldn't + # interfere again in the future. + git node land --abort --yes + SHOULD_ABORT= + fi + git node land --autorebase --yes $MULTIPLE_COMMIT_POLICY "$pr" >output 2>&1 || echo "Failed to land #${pr}" # cat here otherwise we'll be suppressing the output of git node land cat output @@ -64,10 +102,8 @@ for pr in "$@"; do # if the "Landed in..." message was not on the output we assume land failed if ! grep -q '. Post "Landed in .*/pull/'"${pr}" output; then commit_queue_failed "$pr" - # If `git node land --abort` fails, we're in unknown state. Better to stop - # the script here, current PR was removed from the queue so it shouldn't - # interfere again in the future. - git node land --abort --yes + # Using a variable as there's no point in aborting if there are no PRs left in the queue. + SHOULD_ABORT=1 continue fi @@ -77,7 +113,8 @@ for pr in "$@"; do commits="${start_sha}...${end_sha}" if ! git push $UPSTREAM $DEFAULT_BRANCH >> output 2>&1; then - commit_queue_failed "$pr" + commit_queue_failed "$pr" \ + "Failed to push the landed commits to ${UPSTREAM}/${DEFAULT_BRANCH}." continue fi else @@ -93,19 +130,23 @@ for pr in "$@"; do --arg body "${commit_body}" \ --arg head "${commit_head}" \ '{merge_method:"squash",commit_title:$title,commit_message:$body,sha:$head}' |\ - gh api -X PUT "repos/${OWNER}/${REPOSITORY}/pulls/${pr}/merge" --input -\ - --jq 'if .merged then .sha else halt_error end' + gh api -X PUT "repos/${GITHUB_REPOSITORY}/pulls/${pr}/merge" --input -\ + --jq 'if .merged then .sha else halt_error end' 2>> output )"; then - commit_queue_failed "$pr" + commit_queue_failed "$pr" \ + 'GitHub failed to squash and merge this pull request.' continue fi fi rm output - gh pr comment "$pr" --body "Landed in $commits" + gh -R "$GITHUB_REPOSITORY" pr comment "$pr" --body "Landed in $commits" + + [ -z "$MULTIPLE_COMMIT_POLICY" ] && gh -R "$GITHUB_REPOSITORY" pr close "$pr" - [ -z "$MULTIPLE_COMMIT_POLICY" ] && gh pr close "$pr" + # Delete the commit queue label (but ignore errors, it's no big deal if a closed PR still has the label) + gh -R "$GITHUB_REPOSITORY" pr edit "$pr" --remove-label "$COMMIT_QUEUE_LABEL" || true done rm -f labels.json diff --git a/tools/actions/create-release-proposal.sh b/tools/actions/create-release-proposal.sh index f4878f1cc940..9240fa2ad7f7 100755 --- a/tools/actions/create-release-proposal.sh +++ b/tools/actions/create-release-proposal.sh @@ -35,9 +35,14 @@ HEAD_SHA="$(git rev-parse HEAD^)" TITLE="$(git log -1 --format=%s)" -TEMP_BODY="$(awk -v MAX_BODY_LENGTH="65536" \ - "/^## ${RELEASE_DATE}/,/^ MAX_BODY_LENGTH) {exit 1;} print }" \ - "doc/changelogs/CHANGELOG_V${RELEASE_LINE}.md" || echo "…")" +# GH rest API has an undocumented limit of 65536 char for the body, setting it +# to 65534 to account for the ellipsis and the final EOL. +TEMP_BODY="$(awk -v MAX_BODY_LENGTH="65534" \ + "/^## ${RELEASE_DATE}/,/^ MAX_BODY_LENGTH) {exit 1;} + print + }" "doc/changelogs/CHANGELOG_V${RELEASE_LINE}.md" || echo "…")" # Create the proposal branch gh api \ diff --git a/tools/actions/start-ci.sh b/tools/actions/start-ci.sh index 4d4fadf958a9..d4d19b92082d 100755 --- a/tools/actions/start-ci.sh +++ b/tools/actions/start-ci.sh @@ -4,9 +4,10 @@ set -xe REQUEST_CI_LABEL="request-ci" REQUEST_CI_FAILED_LABEL="request-ci-failed" +cqurl="${GITHUB_SERVER_URL:?}/${GITHUB_REPOSITORY:?}/actions/runs/${GITHUB_RUN_ID:?}" for pr in "$@"; do - gh pr edit "$pr" --remove-label "$REQUEST_CI_LABEL" + gh -R "$GITHUB_REPOSITORY" pr edit "$pr" --remove-label "$REQUEST_CI_LABEL" ci_started=yes rm -f output; @@ -15,14 +16,12 @@ for pr in "$@"; do if [ "$ci_started" = "no" ]; then # Do we need to reset? - gh pr edit "$pr" --add-label "$REQUEST_CI_FAILED_LABEL" + gh -R "$GITHUB_REPOSITORY" pr edit "$pr" --add-label "$REQUEST_CI_FAILED_LABEL" - # shellcheck disable=SC2154 - cqurl="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" body="
Failed to start CI
$(cat output)
$cqurl
" echo "$body" - gh pr comment "$pr" --body "$body" + gh -R "$GITHUB_REPOSITORY" pr comment "$pr" --body "$body" rm output fi diff --git a/tools/certdata.txt b/tools/certdata.txt index fafc33ddeea5..f2f8edc685ad 100644 --- a/tools/certdata.txt +++ b/tools/certdata.txt @@ -2453,181 +2453,6 @@ CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE -# -# Certificate "ePKI Root Certification Authority" -# -# Issuer: OU=ePKI Root Certification Authority,O="Chunghwa Telecom Co., Ltd.",C=TW -# Serial Number:15:c8:bd:65:47:5c:af:b8:97:00:5e:e4:06:d2:bc:9d -# Subject: OU=ePKI Root Certification Authority,O="Chunghwa Telecom Co., Ltd.",C=TW -# Not Valid Before: Mon Dec 20 02:31:27 2004 -# Not Valid After : Wed Dec 20 02:31:27 2034 -# Fingerprint (SHA-256): C0:A6:F4:DC:63:A2:4B:FD:CF:54:EF:2A:6A:08:2A:0A:72:DE:35:80:3E:2F:F5:FF:52:7A:E5:D8:72:06:DF:D5 -# Fingerprint (SHA1): 67:65:0D:F1:7E:8E:7E:5B:82:40:A4:F4:56:4B:CF:E2:3D:69:C6:F0 -CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE -CKA_TOKEN CK_BBOOL CK_TRUE -CKA_PRIVATE CK_BBOOL CK_FALSE -CKA_MODIFIABLE CK_BBOOL CK_FALSE -CKA_LABEL UTF8 "ePKI Root Certification Authority" -CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509 -CKA_SUBJECT MULTILINE_OCTAL -\060\136\061\013\060\011\006\003\125\004\006\023\002\124\127\061 -\043\060\041\006\003\125\004\012\014\032\103\150\165\156\147\150 -\167\141\040\124\145\154\145\143\157\155\040\103\157\056\054\040 -\114\164\144\056\061\052\060\050\006\003\125\004\013\014\041\145 -\120\113\111\040\122\157\157\164\040\103\145\162\164\151\146\151 -\143\141\164\151\157\156\040\101\165\164\150\157\162\151\164\171 -END -CKA_ID UTF8 "0" -CKA_ISSUER MULTILINE_OCTAL -\060\136\061\013\060\011\006\003\125\004\006\023\002\124\127\061 -\043\060\041\006\003\125\004\012\014\032\103\150\165\156\147\150 -\167\141\040\124\145\154\145\143\157\155\040\103\157\056\054\040 -\114\164\144\056\061\052\060\050\006\003\125\004\013\014\041\145 -\120\113\111\040\122\157\157\164\040\103\145\162\164\151\146\151 -\143\141\164\151\157\156\040\101\165\164\150\157\162\151\164\171 -END -CKA_SERIAL_NUMBER MULTILINE_OCTAL -\002\020\025\310\275\145\107\134\257\270\227\000\136\344\006\322 -\274\235 -END -CKA_VALUE MULTILINE_OCTAL -\060\202\005\260\060\202\003\230\240\003\002\001\002\002\020\025 -\310\275\145\107\134\257\270\227\000\136\344\006\322\274\235\060 -\015\006\011\052\206\110\206\367\015\001\001\005\005\000\060\136 -\061\013\060\011\006\003\125\004\006\023\002\124\127\061\043\060 -\041\006\003\125\004\012\014\032\103\150\165\156\147\150\167\141 -\040\124\145\154\145\143\157\155\040\103\157\056\054\040\114\164 -\144\056\061\052\060\050\006\003\125\004\013\014\041\145\120\113 -\111\040\122\157\157\164\040\103\145\162\164\151\146\151\143\141 -\164\151\157\156\040\101\165\164\150\157\162\151\164\171\060\036 -\027\015\060\064\061\062\062\060\060\062\063\061\062\067\132\027 -\015\063\064\061\062\062\060\060\062\063\061\062\067\132\060\136 -\061\013\060\011\006\003\125\004\006\023\002\124\127\061\043\060 -\041\006\003\125\004\012\014\032\103\150\165\156\147\150\167\141 -\040\124\145\154\145\143\157\155\040\103\157\056\054\040\114\164 -\144\056\061\052\060\050\006\003\125\004\013\014\041\145\120\113 -\111\040\122\157\157\164\040\103\145\162\164\151\146\151\143\141 -\164\151\157\156\040\101\165\164\150\157\162\151\164\171\060\202 -\002\042\060\015\006\011\052\206\110\206\367\015\001\001\001\005 -\000\003\202\002\017\000\060\202\002\012\002\202\002\001\000\341 -\045\017\356\215\333\210\063\165\147\315\255\037\175\072\116\155 -\235\323\057\024\363\143\164\313\001\041\152\067\352\204\120\007 -\113\046\133\011\103\154\041\236\152\310\325\003\365\140\151\217 -\314\360\042\344\037\347\367\152\042\061\267\054\025\362\340\376 -\000\152\103\377\207\145\306\265\032\301\247\114\155\042\160\041 -\212\061\362\227\164\211\011\022\046\034\236\312\331\022\242\225 -\074\332\351\147\277\010\240\144\343\326\102\267\105\357\227\364 -\366\365\327\265\112\025\002\130\175\230\130\113\140\274\315\327 -\015\232\023\063\123\321\141\371\172\325\327\170\263\232\063\367 -\000\206\316\035\115\224\070\257\250\354\170\121\160\212\134\020 -\203\121\041\367\021\075\064\206\136\345\110\315\227\201\202\065 -\114\031\354\145\366\153\305\005\241\356\107\023\326\263\041\047 -\224\020\012\331\044\073\272\276\104\023\106\060\077\227\074\330 -\327\327\152\356\073\070\343\053\324\227\016\271\033\347\007\111 -\177\067\052\371\167\170\317\124\355\133\106\235\243\200\016\221 -\103\301\326\133\137\024\272\237\246\215\044\107\100\131\277\162 -\070\262\066\154\067\377\231\321\135\016\131\012\253\151\367\300 -\262\004\105\172\124\000\256\276\123\366\265\347\341\370\074\243 -\061\322\251\376\041\122\144\305\246\147\360\165\007\006\224\024 -\201\125\306\047\344\001\217\027\301\152\161\327\276\113\373\224 -\130\175\176\021\063\261\102\367\142\154\030\326\317\011\150\076 -\177\154\366\036\217\142\255\245\143\333\011\247\037\042\102\101 -\036\157\231\212\076\327\371\077\100\172\171\260\245\001\222\322 -\235\075\010\025\245\020\001\055\263\062\166\250\225\015\263\172 -\232\373\007\020\170\021\157\341\217\307\272\017\045\032\164\052 -\345\034\230\101\231\337\041\207\350\225\006\152\012\263\152\107 -\166\145\366\072\317\217\142\027\031\173\012\050\315\032\322\203 -\036\041\307\054\277\276\377\141\150\267\147\033\273\170\115\215 -\316\147\345\344\301\216\267\043\146\342\235\220\165\064\230\251 -\066\053\212\232\224\271\235\354\314\212\261\370\045\211\134\132 -\266\057\214\037\155\171\044\247\122\150\303\204\065\342\146\215 -\143\016\045\115\325\031\262\346\171\067\247\042\235\124\061\002 -\003\001\000\001\243\152\060\150\060\035\006\003\125\035\016\004 -\026\004\024\036\014\367\266\147\362\341\222\046\011\105\300\125 -\071\056\167\077\102\112\242\060\014\006\003\125\035\023\004\005 -\060\003\001\001\377\060\071\006\004\147\052\007\000\004\061\060 -\057\060\055\002\001\000\060\011\006\005\053\016\003\002\032\005 -\000\060\007\006\005\147\052\003\000\000\004\024\105\260\302\307 -\012\126\174\356\133\170\014\225\371\030\123\301\246\034\330\020 -\060\015\006\011\052\206\110\206\367\015\001\001\005\005\000\003 -\202\002\001\000\011\263\203\123\131\001\076\225\111\271\361\201 -\272\371\166\040\043\265\047\140\164\324\152\231\064\136\154\000 -\123\331\237\362\246\261\044\007\104\152\052\306\245\216\170\022 -\350\107\331\130\033\023\052\136\171\233\237\012\052\147\246\045 -\077\006\151\126\163\303\212\146\110\373\051\201\127\164\006\312 -\234\352\050\350\070\147\046\053\361\325\265\077\145\223\370\066 -\135\216\215\215\100\040\207\031\352\357\047\300\075\264\071\017 -\045\173\150\120\164\125\234\014\131\175\132\075\101\224\045\122 -\010\340\107\054\025\061\031\325\277\007\125\306\273\022\265\227 -\364\137\203\205\272\161\301\331\154\201\021\166\012\012\260\277 -\202\227\367\352\075\372\372\354\055\251\050\224\073\126\335\322 -\121\056\256\300\275\010\025\214\167\122\064\226\326\233\254\323 -\035\216\141\017\065\173\233\256\071\151\013\142\140\100\040\066 -\217\257\373\066\356\055\010\112\035\270\277\233\134\370\352\245 -\033\240\163\246\330\370\156\340\063\004\137\150\252\047\207\355 -\331\301\220\234\355\275\343\152\065\257\143\337\253\030\331\272 -\346\351\112\352\120\212\017\141\223\036\342\055\031\342\060\224 -\065\222\135\016\266\007\257\031\200\217\107\220\121\113\056\115 -\335\205\342\322\012\122\012\027\232\374\032\260\120\002\345\001 -\243\143\067\041\114\104\304\233\121\231\021\016\163\234\006\217 -\124\056\247\050\136\104\071\207\126\055\067\275\205\104\224\341 -\014\113\054\234\303\222\205\064\141\313\017\270\233\112\103\122 -\376\064\072\175\270\351\051\334\166\251\310\060\370\024\161\200 -\306\036\066\110\164\042\101\134\207\202\350\030\161\213\101\211 -\104\347\176\130\133\250\270\215\023\351\247\154\303\107\355\263 -\032\235\142\256\215\202\352\224\236\335\131\020\303\255\335\342 -\115\343\061\325\307\354\350\362\260\376\222\036\026\012\032\374 -\331\363\370\047\266\311\276\035\264\154\144\220\177\364\344\304 -\133\327\067\256\102\016\335\244\032\157\174\210\124\305\026\156 -\341\172\150\056\370\072\277\015\244\074\211\073\170\247\116\143 -\203\004\041\010\147\215\362\202\111\320\133\375\261\315\017\203 -\204\324\076\040\205\367\112\075\053\234\375\052\012\011\115\352 -\201\370\021\234 -END -CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE -# For Server Distrust After: Tue Apr 15 23:59:59 2025 -CKA_NSS_SERVER_DISTRUST_AFTER MULTILINE_OCTAL -\062\065\060\064\061\065\062\063\065\071\065\071\132 -END -CKA_NSS_EMAIL_DISTRUST_AFTER CK_BBOOL CK_FALSE - -# Trust for "ePKI Root Certification Authority" -# Issuer: OU=ePKI Root Certification Authority,O="Chunghwa Telecom Co., Ltd.",C=TW -# Serial Number:15:c8:bd:65:47:5c:af:b8:97:00:5e:e4:06:d2:bc:9d -# Subject: OU=ePKI Root Certification Authority,O="Chunghwa Telecom Co., Ltd.",C=TW -# Not Valid Before: Mon Dec 20 02:31:27 2004 -# Not Valid After : Wed Dec 20 02:31:27 2034 -# Fingerprint (SHA-256): C0:A6:F4:DC:63:A2:4B:FD:CF:54:EF:2A:6A:08:2A:0A:72:DE:35:80:3E:2F:F5:FF:52:7A:E5:D8:72:06:DF:D5 -# Fingerprint (SHA1): 67:65:0D:F1:7E:8E:7E:5B:82:40:A4:F4:56:4B:CF:E2:3D:69:C6:F0 -CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST -CKA_TOKEN CK_BBOOL CK_TRUE -CKA_PRIVATE CK_BBOOL CK_FALSE -CKA_MODIFIABLE CK_BBOOL CK_FALSE -CKA_LABEL UTF8 "ePKI Root Certification Authority" -CKA_CERT_SHA1_HASH MULTILINE_OCTAL -\147\145\015\361\176\216\176\133\202\100\244\364\126\113\317\342 -\075\151\306\360 -END -CKA_CERT_MD5_HASH MULTILINE_OCTAL -\033\056\000\312\046\006\220\075\255\376\157\025\150\323\153\263 -END -CKA_ISSUER MULTILINE_OCTAL -\060\136\061\013\060\011\006\003\125\004\006\023\002\124\127\061 -\043\060\041\006\003\125\004\012\014\032\103\150\165\156\147\150 -\167\141\040\124\145\154\145\143\157\155\040\103\157\056\054\040 -\114\164\144\056\061\052\060\050\006\003\125\004\013\014\041\145 -\120\113\111\040\122\157\157\164\040\103\145\162\164\151\146\151 -\143\141\164\151\157\156\040\101\165\164\150\157\162\151\164\171 -END -CKA_SERIAL_NUMBER MULTILINE_OCTAL -\002\020\025\310\275\145\107\134\257\270\227\000\136\344\006\322 -\274\235 -END -CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR -CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR -CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST -CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE - # # Certificate "NetLock Arany (Class Gold) Főtanúsítvány" # @@ -5846,7 +5671,7 @@ END CKA_SERIAL_NUMBER MULTILINE_OCTAL \002\010\134\063\313\142\054\137\263\062 END -CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR +CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_MUST_VERIFY_TRUST CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE @@ -24763,3 +24588,1013 @@ CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_MUST_VERIFY_TRUST CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE + +# +# Certificate "SECOM TLS RSA Root CA 2024" +# +# Issuer: CN=SECOM TLS RSA Root CA 2024,O="SECOM Trust Systems Co., Ltd.",C=JP +# Serial Number:00:ee:89:34:d0:cb:80:e0:b2 +# Subject: CN=SECOM TLS RSA Root CA 2024,O="SECOM Trust Systems Co., Ltd.",C=JP +# Not Valid Before: Wed Jan 31 05:11:55 2024 +# Not Valid After : Thu Jan 14 05:11:55 2049 +# Fingerprint (SHA-256): 14:35:F2:25:C5:D2:52:D7:A2:19:48:CC:3C:E6:2A:EC:FA:88:00:1E:3D:D7:2D:1C:C3:55:51:00:EB:37:2F:93 +# Fingerprint (SHA1): FB:97:96:7C:EF:8D:98:63:06:C0:3B:B6:11:F8:E0:13:97:A2:98:D3 +CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE +CKA_TOKEN CK_BBOOL CK_TRUE +CKA_PRIVATE CK_BBOOL CK_FALSE +CKA_MODIFIABLE CK_BBOOL CK_FALSE +CKA_LABEL UTF8 "SECOM TLS RSA Root CA 2024" +CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509 +CKA_SUBJECT MULTILINE_OCTAL +\060\132\061\013\060\011\006\003\125\004\006\023\002\112\120\061 +\046\060\044\006\003\125\004\012\023\035\123\105\103\117\115\040 +\124\162\165\163\164\040\123\171\163\164\145\155\163\040\103\157 +\056\054\040\114\164\144\056\061\043\060\041\006\003\125\004\003 +\023\032\123\105\103\117\115\040\124\114\123\040\122\123\101\040 +\122\157\157\164\040\103\101\040\062\060\062\064 +END +CKA_ID UTF8 "0" +CKA_ISSUER MULTILINE_OCTAL +\060\132\061\013\060\011\006\003\125\004\006\023\002\112\120\061 +\046\060\044\006\003\125\004\012\023\035\123\105\103\117\115\040 +\124\162\165\163\164\040\123\171\163\164\145\155\163\040\103\157 +\056\054\040\114\164\144\056\061\043\060\041\006\003\125\004\003 +\023\032\123\105\103\117\115\040\124\114\123\040\122\123\101\040 +\122\157\157\164\040\103\101\040\062\060\062\064 +END +CKA_SERIAL_NUMBER MULTILINE_OCTAL +\002\011\000\356\211\064\320\313\200\340\262 +END +CKA_VALUE MULTILINE_OCTAL +\060\202\005\232\060\202\003\202\240\003\002\001\002\002\011\000 +\356\211\064\320\313\200\340\262\060\015\006\011\052\206\110\206 +\367\015\001\001\014\005\000\060\132\061\013\060\011\006\003\125 +\004\006\023\002\112\120\061\046\060\044\006\003\125\004\012\023 +\035\123\105\103\117\115\040\124\162\165\163\164\040\123\171\163 +\164\145\155\163\040\103\157\056\054\040\114\164\144\056\061\043 +\060\041\006\003\125\004\003\023\032\123\105\103\117\115\040\124 +\114\123\040\122\123\101\040\122\157\157\164\040\103\101\040\062 +\060\062\064\060\036\027\015\062\064\060\061\063\061\060\065\061 +\061\065\065\132\027\015\064\071\060\061\061\064\060\065\061\061 +\065\065\132\060\132\061\013\060\011\006\003\125\004\006\023\002 +\112\120\061\046\060\044\006\003\125\004\012\023\035\123\105\103 +\117\115\040\124\162\165\163\164\040\123\171\163\164\145\155\163 +\040\103\157\056\054\040\114\164\144\056\061\043\060\041\006\003 +\125\004\003\023\032\123\105\103\117\115\040\124\114\123\040\122 +\123\101\040\122\157\157\164\040\103\101\040\062\060\062\064\060 +\202\002\042\060\015\006\011\052\206\110\206\367\015\001\001\001 +\005\000\003\202\002\017\000\060\202\002\012\002\202\002\001\000 +\341\070\342\315\114\063\305\262\047\253\304\361\327\130\032\025 +\203\144\345\363\276\337\214\273\117\043\070\235\350\164\122\002 +\371\044\206\133\044\322\323\317\154\177\374\277\301\357\137\271 +\233\245\372\234\142\053\355\336\045\024\220\106\266\063\272\357 +\270\127\073\077\167\316\107\026\151\104\346\335\126\316\002\060 +\145\267\206\026\306\127\034\160\021\327\271\236\350\335\017\270 +\107\352\053\232\260\135\035\342\165\011\065\004\033\313\155\101 +\262\210\227\161\273\071\226\033\234\177\077\244\377\034\214\373 +\233\377\111\003\124\333\214\316\236\361\261\124\121\070\350\254 +\102\336\167\174\312\011\056\126\040\241\346\333\270\312\141\072 +\243\002\266\071\011\355\036\236\174\103\037\056\237\024\001\130 +\275\145\242\321\237\276\204\117\360\211\222\117\166\346\167\156 +\272\347\302\340\026\255\113\211\247\134\131\261\067\113\324\135 +\275\042\217\320\174\073\360\374\202\054\120\022\305\122\017\201 +\212\360\125\221\076\035\333\125\337\372\157\067\144\034\142\143 +\313\155\127\043\114\236\215\132\046\145\106\321\254\347\315\273 +\075\033\240\361\225\326\233\165\361\361\102\337\322\007\100\113 +\141\334\341\152\157\223\103\073\162\376\003\326\315\251\070\000 +\311\110\021\230\211\370\271\310\003\163\364\142\374\251\267\127 +\235\156\171\230\362\327\374\244\322\254\011\125\247\100\125\132 +\302\267\236\242\065\345\316\310\113\363\044\000\306\200\064\074 +\023\123\335\152\247\055\360\054\247\317\376\073\105\344\014\353 +\153\305\140\355\074\301\304\044\256\071\227\376\327\254\212\112 +\065\127\134\262\151\376\204\174\374\324\027\071\232\033\057\161 +\276\100\260\165\271\265\344\107\123\242\123\243\023\101\366\125 +\276\177\000\360\316\310\041\104\242\110\230\032\145\323\055\320 +\024\227\114\012\147\202\062\216\101\306\317\055\043\206\226\227 +\021\161\077\030\227\004\274\216\225\314\107\041\215\240\113\323 +\161\011\322\037\151\033\203\252\170\203\262\160\253\300\243\160 +\076\115\267\255\311\373\053\201\214\207\315\115\032\357\372\224 +\214\146\255\324\000\052\326\165\145\214\312\112\252\230\247\075 +\073\037\375\337\107\337\321\123\121\342\113\355\072\163\316\065 +\002\003\001\000\001\243\143\060\141\060\035\006\003\125\035\016 +\004\026\004\024\054\353\162\022\216\130\167\144\065\025\126\065 +\001\127\007\251\175\015\066\346\060\037\006\003\125\035\043\004 +\030\060\026\200\024\054\353\162\022\216\130\167\144\065\025\126 +\065\001\127\007\251\175\015\066\346\060\016\006\003\125\035\017 +\001\001\377\004\004\003\002\001\006\060\017\006\003\125\035\023 +\001\001\377\004\005\060\003\001\001\377\060\015\006\011\052\206 +\110\206\367\015\001\001\014\005\000\003\202\002\001\000\025\302 +\313\345\271\046\237\151\354\371\264\123\321\376\024\123\007\064 +\161\023\043\014\100\135\327\045\160\225\213\174\236\201\234\212 +\241\347\073\206\141\072\217\035\231\063\302\240\063\131\047\333 +\042\121\300\125\307\137\314\324\133\331\301\054\100\326\163\214 +\056\023\302\353\225\232\241\031\223\075\244\224\027\032\141\263 +\105\353\003\045\136\211\201\020\147\153\350\370\260\015\114\357 +\042\035\226\362\364\260\007\305\134\120\223\105\245\223\017\201 +\065\127\337\121\056\261\163\131\364\334\013\347\265\363\110\103 +\270\323\051\250\341\050\343\257\245\061\345\277\132\370\173\211 +\363\220\263\351\042\053\103\266\200\174\120\014\334\154\225\046 +\257\234\053\070\127\271\174\035\020\311\330\266\265\322\216\364 +\006\216\325\057\067\365\133\303\001\276\375\025\116\174\101\370 +\330\323\346\244\300\156\021\205\207\321\257\247\200\132\046\231 +\235\121\375\002\344\041\017\351\326\320\225\370\061\131\374\330 +\257\257\162\125\076\235\075\000\176\030\121\032\143\115\310\061 +\217\200\160\020\254\372\211\265\174\334\153\101\173\175\316\212 +\037\060\023\105\154\270\157\244\321\377\046\305\326\164\145\063 +\174\326\316\327\153\254\301\066\271\301\250\174\054\035\174\025 +\064\015\333\374\317\035\211\257\004\112\013\273\045\040\147\117 +\125\064\262\150\345\200\064\221\162\055\125\211\013\214\307\266 +\112\054\163\053\213\034\120\173\374\324\202\275\364\217\165\015 +\154\173\027\003\025\053\015\261\200\132\176\144\266\001\331\331 +\351\101\012\352\302\125\272\342\011\107\121\302\266\067\320\103 +\262\170\313\113\027\231\371\103\304\012\037\121\304\176\026\001 +\302\242\145\157\234\251\242\214\232\023\366\130\027\321\340\207 +\021\354\323\213\337\151\245\327\127\154\363\270\141\127\120\231 +\131\141\102\044\007\002\211\326\031\317\240\231\153\307\261\314 +\172\043\077\324\201\345\021\364\376\375\112\164\160\042\262\250 +\122\216\322\145\375\102\000\034\204\070\361\351\116\237\314\053 +\115\321\132\247\206\033\345\241\340\226\143\036\067\037\237\000 +\210\103\226\345\225\177\024\316\354\176\035\114\365\076\110\125 +\121\060\260\041\373\014\012\145\372\233\367\211\314\171 +END +CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE +CKA_NSS_SERVER_DISTRUST_AFTER CK_BBOOL CK_FALSE +CKA_NSS_EMAIL_DISTRUST_AFTER CK_BBOOL CK_FALSE + +# Trust for "SECOM TLS RSA Root CA 2024" +# Issuer: CN=SECOM TLS RSA Root CA 2024,O="SECOM Trust Systems Co., Ltd.",C=JP +# Serial Number:00:ee:89:34:d0:cb:80:e0:b2 +# Subject: CN=SECOM TLS RSA Root CA 2024,O="SECOM Trust Systems Co., Ltd.",C=JP +# Not Valid Before: Wed Jan 31 05:11:55 2024 +# Not Valid After : Thu Jan 14 05:11:55 2049 +# Fingerprint (SHA-256): 14:35:F2:25:C5:D2:52:D7:A2:19:48:CC:3C:E6:2A:EC:FA:88:00:1E:3D:D7:2D:1C:C3:55:51:00:EB:37:2F:93 +# Fingerprint (SHA1): FB:97:96:7C:EF:8D:98:63:06:C0:3B:B6:11:F8:E0:13:97:A2:98:D3 +CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST +CKA_TOKEN CK_BBOOL CK_TRUE +CKA_PRIVATE CK_BBOOL CK_FALSE +CKA_MODIFIABLE CK_BBOOL CK_FALSE +CKA_LABEL UTF8 "SECOM TLS RSA Root CA 2024" +CKA_CERT_SHA1_HASH MULTILINE_OCTAL +\373\227\226\174\357\215\230\143\006\300\073\266\021\370\340\023 +\227\242\230\323 +END +CKA_CERT_MD5_HASH MULTILINE_OCTAL +\320\244\333\062\353\104\230\322\142\013\076\274\115\174\134\351 +END +CKA_ISSUER MULTILINE_OCTAL +\060\132\061\013\060\011\006\003\125\004\006\023\002\112\120\061 +\046\060\044\006\003\125\004\012\023\035\123\105\103\117\115\040 +\124\162\165\163\164\040\123\171\163\164\145\155\163\040\103\157 +\056\054\040\114\164\144\056\061\043\060\041\006\003\125\004\003 +\023\032\123\105\103\117\115\040\124\114\123\040\122\123\101\040 +\122\157\157\164\040\103\101\040\062\060\062\064 +END +CKA_SERIAL_NUMBER MULTILINE_OCTAL +\002\011\000\356\211\064\320\313\200\340\262 +END +CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR +CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_MUST_VERIFY_TRUST +CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST +CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE + +# +# Certificate "SECOM TLS ECC Root CA 2024" +# +# Issuer: CN=SECOM TLS ECC Root CA 2024,O="SECOM Trust Systems Co., Ltd.",C=JP +# Serial Number:00:81:7a:2c:ef:8f:23:7a:44 +# Subject: CN=SECOM TLS ECC Root CA 2024,O="SECOM Trust Systems Co., Ltd.",C=JP +# Not Valid Before: Wed Jan 31 05:52:34 2024 +# Not Valid After : Thu Jan 14 05:52:34 2049 +# Fingerprint (SHA-256): 6A:B2:AB:75:F5:1C:B4:F4:F0:15:62:03:FB:F6:F6:46:23:2F:51:4B:E0:59:F6:28:33:30:8B:82:B4:D7:2D:B1 +# Fingerprint (SHA1): 7A:1F:22:2D:72:B2:C3:19:87:44:DB:61:69:E8:A6:4B:D7:0D:44:0E +CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE +CKA_TOKEN CK_BBOOL CK_TRUE +CKA_PRIVATE CK_BBOOL CK_FALSE +CKA_MODIFIABLE CK_BBOOL CK_FALSE +CKA_LABEL UTF8 "SECOM TLS ECC Root CA 2024" +CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509 +CKA_SUBJECT MULTILINE_OCTAL +\060\132\061\013\060\011\006\003\125\004\006\023\002\112\120\061 +\046\060\044\006\003\125\004\012\023\035\123\105\103\117\115\040 +\124\162\165\163\164\040\123\171\163\164\145\155\163\040\103\157 +\056\054\040\114\164\144\056\061\043\060\041\006\003\125\004\003 +\023\032\123\105\103\117\115\040\124\114\123\040\105\103\103\040 +\122\157\157\164\040\103\101\040\062\060\062\064 +END +CKA_ID UTF8 "0" +CKA_ISSUER MULTILINE_OCTAL +\060\132\061\013\060\011\006\003\125\004\006\023\002\112\120\061 +\046\060\044\006\003\125\004\012\023\035\123\105\103\117\115\040 +\124\162\165\163\164\040\123\171\163\164\145\155\163\040\103\157 +\056\054\040\114\164\144\056\061\043\060\041\006\003\125\004\003 +\023\032\123\105\103\117\115\040\124\114\123\040\105\103\103\040 +\122\157\157\164\040\103\101\040\062\060\062\064 +END +CKA_SERIAL_NUMBER MULTILINE_OCTAL +\002\011\000\201\172\054\357\217\043\172\104 +END +CKA_VALUE MULTILINE_OCTAL +\060\202\002\114\060\202\001\321\240\003\002\001\002\002\011\000 +\201\172\054\357\217\043\172\104\060\012\006\010\052\206\110\316 +\075\004\003\003\060\132\061\013\060\011\006\003\125\004\006\023 +\002\112\120\061\046\060\044\006\003\125\004\012\023\035\123\105 +\103\117\115\040\124\162\165\163\164\040\123\171\163\164\145\155 +\163\040\103\157\056\054\040\114\164\144\056\061\043\060\041\006 +\003\125\004\003\023\032\123\105\103\117\115\040\124\114\123\040 +\105\103\103\040\122\157\157\164\040\103\101\040\062\060\062\064 +\060\036\027\015\062\064\060\061\063\061\060\065\065\062\063\064 +\132\027\015\064\071\060\061\061\064\060\065\065\062\063\064\132 +\060\132\061\013\060\011\006\003\125\004\006\023\002\112\120\061 +\046\060\044\006\003\125\004\012\023\035\123\105\103\117\115\040 +\124\162\165\163\164\040\123\171\163\164\145\155\163\040\103\157 +\056\054\040\114\164\144\056\061\043\060\041\006\003\125\004\003 +\023\032\123\105\103\117\115\040\124\114\123\040\105\103\103\040 +\122\157\157\164\040\103\101\040\062\060\062\064\060\166\060\020 +\006\007\052\206\110\316\075\002\001\006\005\053\201\004\000\042 +\003\142\000\004\354\334\305\062\333\275\167\064\027\110\320\265 +\331\366\233\223\117\206\224\056\137\212\160\167\107\265\332\146 +\211\321\121\335\264\150\130\226\071\273\156\064\020\213\121\224 +\237\223\244\027\000\116\171\006\061\027\261\164\077\064\157\062 +\122\250\234\136\073\056\366\113\003\053\162\131\006\000\260\054 +\345\141\353\351\360\045\164\357\262\217\335\022\077\306\121\201 +\371\230\027\150\243\143\060\141\060\035\006\003\125\035\016\004 +\026\004\024\073\166\021\173\051\164\342\116\006\114\126\202\100 +\320\041\057\172\263\311\325\060\037\006\003\125\035\043\004\030 +\060\026\200\024\073\166\021\173\051\164\342\116\006\114\126\202 +\100\320\041\057\172\263\311\325\060\016\006\003\125\035\017\001 +\001\377\004\004\003\002\001\006\060\017\006\003\125\035\023\001 +\001\377\004\005\060\003\001\001\377\060\012\006\010\052\206\110 +\316\075\004\003\003\003\151\000\060\146\002\061\000\335\342\157 +\307\342\326\223\030\264\003\343\062\051\101\345\356\177\037\353 +\171\010\275\061\074\277\234\147\232\023\115\233\222\012\072\100 +\237\133\373\027\365\100\257\306\305\305\005\300\243\002\061\000 +\253\001\124\355\100\010\132\173\262\114\063\076\367\157\324\105 +\030\345\257\075\355\141\213\117\211\133\371\270\361\024\005\262 +\227\314\003\161\222\135\300\146\177\244\001\361\267\120\011\326 +END +CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE +CKA_NSS_SERVER_DISTRUST_AFTER CK_BBOOL CK_FALSE +CKA_NSS_EMAIL_DISTRUST_AFTER CK_BBOOL CK_FALSE + +# Trust for "SECOM TLS ECC Root CA 2024" +# Issuer: CN=SECOM TLS ECC Root CA 2024,O="SECOM Trust Systems Co., Ltd.",C=JP +# Serial Number:00:81:7a:2c:ef:8f:23:7a:44 +# Subject: CN=SECOM TLS ECC Root CA 2024,O="SECOM Trust Systems Co., Ltd.",C=JP +# Not Valid Before: Wed Jan 31 05:52:34 2024 +# Not Valid After : Thu Jan 14 05:52:34 2049 +# Fingerprint (SHA-256): 6A:B2:AB:75:F5:1C:B4:F4:F0:15:62:03:FB:F6:F6:46:23:2F:51:4B:E0:59:F6:28:33:30:8B:82:B4:D7:2D:B1 +# Fingerprint (SHA1): 7A:1F:22:2D:72:B2:C3:19:87:44:DB:61:69:E8:A6:4B:D7:0D:44:0E +CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST +CKA_TOKEN CK_BBOOL CK_TRUE +CKA_PRIVATE CK_BBOOL CK_FALSE +CKA_MODIFIABLE CK_BBOOL CK_FALSE +CKA_LABEL UTF8 "SECOM TLS ECC Root CA 2024" +CKA_CERT_SHA1_HASH MULTILINE_OCTAL +\172\037\042\055\162\262\303\031\207\104\333\141\151\350\246\113 +\327\015\104\016 +END +CKA_CERT_MD5_HASH MULTILINE_OCTAL +\231\323\235\344\322\261\055\360\052\004\147\205\363\337\106\326 +END +CKA_ISSUER MULTILINE_OCTAL +\060\132\061\013\060\011\006\003\125\004\006\023\002\112\120\061 +\046\060\044\006\003\125\004\012\023\035\123\105\103\117\115\040 +\124\162\165\163\164\040\123\171\163\164\145\155\163\040\103\157 +\056\054\040\114\164\144\056\061\043\060\041\006\003\125\004\003 +\023\032\123\105\103\117\115\040\124\114\123\040\105\103\103\040 +\122\157\157\164\040\103\101\040\062\060\062\064 +END +CKA_SERIAL_NUMBER MULTILINE_OCTAL +\002\011\000\201\172\054\357\217\043\172\104 +END +CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR +CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_MUST_VERIFY_TRUST +CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST +CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE + +# +# Certificate "SECOM SMIME RSA Root CA 2024" +# +# Issuer: CN=SECOM SMIME RSA Root CA 2024,O="SECOM Trust Systems Co., Ltd.",C=JP +# Serial Number:00:dd:a9:db:9e:7e:bc:d4:6d +# Subject: CN=SECOM SMIME RSA Root CA 2024,O="SECOM Trust Systems Co., Ltd.",C=JP +# Not Valid Before: Wed Jan 31 06:23:06 2024 +# Not Valid After : Thu Jan 14 06:23:06 2049 +# Fingerprint (SHA-256): 36:29:E7:18:8E:00:A7:CB:32:32:C4:42:6B:C8:49:12:F1:21:8B:1A:9A:E6:76:C0:B0:AB:E1:DB:FE:21:82:B5 +# Fingerprint (SHA1): 90:A5:E1:BD:C5:3F:69:08:C2:E3:73:9F:E7:55:E3:7F:75:F3:84:47 +CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE +CKA_TOKEN CK_BBOOL CK_TRUE +CKA_PRIVATE CK_BBOOL CK_FALSE +CKA_MODIFIABLE CK_BBOOL CK_FALSE +CKA_LABEL UTF8 "SECOM SMIME RSA Root CA 2024" +CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509 +CKA_SUBJECT MULTILINE_OCTAL +\060\134\061\013\060\011\006\003\125\004\006\023\002\112\120\061 +\046\060\044\006\003\125\004\012\023\035\123\105\103\117\115\040 +\124\162\165\163\164\040\123\171\163\164\145\155\163\040\103\157 +\056\054\040\114\164\144\056\061\045\060\043\006\003\125\004\003 +\023\034\123\105\103\117\115\040\123\115\111\115\105\040\122\123 +\101\040\122\157\157\164\040\103\101\040\062\060\062\064 +END +CKA_ID UTF8 "0" +CKA_ISSUER MULTILINE_OCTAL +\060\134\061\013\060\011\006\003\125\004\006\023\002\112\120\061 +\046\060\044\006\003\125\004\012\023\035\123\105\103\117\115\040 +\124\162\165\163\164\040\123\171\163\164\145\155\163\040\103\157 +\056\054\040\114\164\144\056\061\045\060\043\006\003\125\004\003 +\023\034\123\105\103\117\115\040\123\115\111\115\105\040\122\123 +\101\040\122\157\157\164\040\103\101\040\062\060\062\064 +END +CKA_SERIAL_NUMBER MULTILINE_OCTAL +\002\011\000\335\251\333\236\176\274\324\155 +END +CKA_VALUE MULTILINE_OCTAL +\060\202\005\236\060\202\003\206\240\003\002\001\002\002\011\000 +\335\251\333\236\176\274\324\155\060\015\006\011\052\206\110\206 +\367\015\001\001\014\005\000\060\134\061\013\060\011\006\003\125 +\004\006\023\002\112\120\061\046\060\044\006\003\125\004\012\023 +\035\123\105\103\117\115\040\124\162\165\163\164\040\123\171\163 +\164\145\155\163\040\103\157\056\054\040\114\164\144\056\061\045 +\060\043\006\003\125\004\003\023\034\123\105\103\117\115\040\123 +\115\111\115\105\040\122\123\101\040\122\157\157\164\040\103\101 +\040\062\060\062\064\060\036\027\015\062\064\060\061\063\061\060 +\066\062\063\060\066\132\027\015\064\071\060\061\061\064\060\066 +\062\063\060\066\132\060\134\061\013\060\011\006\003\125\004\006 +\023\002\112\120\061\046\060\044\006\003\125\004\012\023\035\123 +\105\103\117\115\040\124\162\165\163\164\040\123\171\163\164\145 +\155\163\040\103\157\056\054\040\114\164\144\056\061\045\060\043 +\006\003\125\004\003\023\034\123\105\103\117\115\040\123\115\111 +\115\105\040\122\123\101\040\122\157\157\164\040\103\101\040\062 +\060\062\064\060\202\002\042\060\015\006\011\052\206\110\206\367 +\015\001\001\001\005\000\003\202\002\017\000\060\202\002\012\002 +\202\002\001\000\301\312\336\306\344\326\154\327\326\170\031\114 +\105\145\246\144\314\126\243\202\175\214\212\325\211\332\015\345 +\357\140\077\143\221\372\360\007\033\147\266\077\301\300\356\202 +\031\226\121\311\053\102\156\376\123\107\212\242\346\206\027\325 +\312\247\266\077\111\010\320\310\375\175\052\072\056\305\013\152 +\226\204\104\114\213\335\010\124\033\263\002\247\103\024\104\135 +\157\062\074\061\202\121\304\342\301\206\375\334\170\172\270\345 +\070\160\233\324\116\037\024\262\057\352\013\032\166\144\050\211 +\047\253\162\171\310\341\135\017\274\026\255\126\312\243\232\040 +\122\120\252\037\062\270\124\133\171\350\374\165\070\240\300\357 +\106\362\313\007\203\121\057\271\172\105\273\221\345\367\034\074 +\302\315\174\307\005\150\324\322\210\306\310\226\231\055\014\005 +\163\314\060\007\220\166\341\003\060\025\165\001\136\320\163\150 +\172\251\020\213\322\106\353\176\057\112\126\145\003\050\213\117 +\031\360\211\175\131\371\370\034\155\177\331\341\331\231\212\304 +\104\226\274\043\044\103\311\161\373\115\151\232\101\045\250\362 +\142\264\235\356\274\020\063\070\067\277\043\013\164\314\276\063 +\060\207\054\032\263\054\200\277\236\264\104\375\316\351\040\130 +\233\031\204\347\150\270\161\177\131\242\322\012\017\252\007\310 +\143\026\334\300\363\014\216\223\321\124\355\201\006\056\115\203 +\015\104\254\115\061\105\356\165\273\114\106\056\255\245\305\037 +\211\242\044\142\223\333\206\072\262\164\242\330\072\103\354\146 +\344\024\221\030\274\014\063\017\214\107\225\011\006\371\320\376 +\227\156\066\062\013\342\140\361\306\163\135\040\367\206\251\033 +\150\361\165\045\131\242\253\276\147\060\247\262\263\303\156\370 +\242\110\163\207\161\216\015\312\134\043\265\221\165\353\257\013 +\263\114\170\360\227\164\351\124\056\336\100\227\252\246\343\173 +\130\366\244\355\016\120\240\371\176\240\056\064\014\127\001\370 +\376\302\370\301\267\254\301\343\363\254\151\305\144\126\262\255 +\320\100\271\333\233\165\046\061\050\367\152\160\123\270\165\022 +\275\025\142\160\036\337\020\107\242\165\147\140\325\137\162\154 +\201\315\344\111\275\156\365\020\013\301\301\135\220\317\323\023 +\155\342\312\103\002\003\001\000\001\243\143\060\141\060\035\006 +\003\125\035\016\004\026\004\024\173\341\234\250\066\034\107\244 +\004\373\001\202\157\272\161\101\065\034\060\260\060\037\006\003 +\125\035\043\004\030\060\026\200\024\173\341\234\250\066\034\107 +\244\004\373\001\202\157\272\161\101\065\034\060\260\060\016\006 +\003\125\035\017\001\001\377\004\004\003\002\001\006\060\017\006 +\003\125\035\023\001\001\377\004\005\060\003\001\001\377\060\015 +\006\011\052\206\110\206\367\015\001\001\014\005\000\003\202\002 +\001\000\264\266\325\373\106\055\356\273\274\174\332\064\357\344 +\260\131\050\312\106\144\274\042\345\010\226\341\032\033\366\044 +\316\331\131\140\142\315\033\252\132\014\174\270\174\164\133\342 +\204\074\044\270\147\167\230\034\156\150\341\152\244\265\265\063 +\222\230\005\171\036\011\272\130\321\352\202\127\124\165\034\144 +\313\101\240\216\241\174\002\104\173\271\250\147\072\172\122\116 +\072\273\201\177\305\145\364\323\032\145\357\120\375\200\237\115 +\011\222\132\001\133\251\247\060\120\200\152\226\177\122\114\034 +\077\146\345\044\224\302\031\252\004\050\237\303\026\060\316\364 +\163\327\264\316\076\317\027\033\072\141\240\166\040\076\012\113 +\063\335\271\330\101\173\224\243\174\266\014\121\244\122\206\233 +\131\116\173\340\332\366\121\304\042\376\045\271\071\152\275\146 +\323\125\236\122\246\141\175\113\054\314\037\256\061\152\364\075 +\230\017\100\003\073\254\146\141\067\337\373\041\223\201\332\324 +\041\027\035\227\021\373\250\216\262\175\202\174\136\326\173\102 +\241\251\033\223\355\042\072\355\224\220\173\367\136\131\073\376 +\165\034\126\205\367\210\113\100\155\251\070\126\041\256\345\025 +\033\102\131\237\377\314\006\073\066\233\121\067\177\130\062\303 +\136\153\230\001\035\301\273\114\022\164\017\152\100\015\117\102 +\062\212\356\072\175\223\250\344\370\041\106\254\140\161\361\115 +\151\046\072\175\365\342\070\102\207\113\372\273\202\124\336\353 +\116\170\310\246\153\332\236\241\254\200\233\111\375\046\276\302 +\027\270\115\250\010\150\031\102\372\305\101\017\030\343\356\010 +\330\037\043\207\020\316\325\361\010\071\103\247\367\353\143\010 +\067\141\077\173\336\203\045\265\134\162\125\357\333\060\072\023 +\325\231\113\107\261\200\276\317\177\200\331\024\014\273\340\234 +\372\011\213\015\001\042\071\154\354\135\304\226\260\055\044\065 +\021\340\005\175\102\151\167\052\101\036\241\305\154\371\275\321 +\046\240\360\255\103\170\213\326\240\134\322\226\001\345\335\354 +\356\310\117\346\140\124\113\014\020\207\207\345\313\167\147\132 +\002\326\221\126\213\356\032\235\346\034\016\366\344\033\000\101 +\240\124\034\056\217\336\322\247\166\147\341\343\237\350\157\007 +\044\244 +END +CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE +CKA_NSS_SERVER_DISTRUST_AFTER CK_BBOOL CK_FALSE +CKA_NSS_EMAIL_DISTRUST_AFTER CK_BBOOL CK_FALSE + +# Trust for "SECOM SMIME RSA Root CA 2024" +# Issuer: CN=SECOM SMIME RSA Root CA 2024,O="SECOM Trust Systems Co., Ltd.",C=JP +# Serial Number:00:dd:a9:db:9e:7e:bc:d4:6d +# Subject: CN=SECOM SMIME RSA Root CA 2024,O="SECOM Trust Systems Co., Ltd.",C=JP +# Not Valid Before: Wed Jan 31 06:23:06 2024 +# Not Valid After : Thu Jan 14 06:23:06 2049 +# Fingerprint (SHA-256): 36:29:E7:18:8E:00:A7:CB:32:32:C4:42:6B:C8:49:12:F1:21:8B:1A:9A:E6:76:C0:B0:AB:E1:DB:FE:21:82:B5 +# Fingerprint (SHA1): 90:A5:E1:BD:C5:3F:69:08:C2:E3:73:9F:E7:55:E3:7F:75:F3:84:47 +CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST +CKA_TOKEN CK_BBOOL CK_TRUE +CKA_PRIVATE CK_BBOOL CK_FALSE +CKA_MODIFIABLE CK_BBOOL CK_FALSE +CKA_LABEL UTF8 "SECOM SMIME RSA Root CA 2024" +CKA_CERT_SHA1_HASH MULTILINE_OCTAL +\220\245\341\275\305\077\151\010\302\343\163\237\347\125\343\177 +\165\363\204\107 +END +CKA_CERT_MD5_HASH MULTILINE_OCTAL +\241\313\205\021\231\325\204\012\342\151\245\257\066\061\142\220 +END +CKA_ISSUER MULTILINE_OCTAL +\060\134\061\013\060\011\006\003\125\004\006\023\002\112\120\061 +\046\060\044\006\003\125\004\012\023\035\123\105\103\117\115\040 +\124\162\165\163\164\040\123\171\163\164\145\155\163\040\103\157 +\056\054\040\114\164\144\056\061\045\060\043\006\003\125\004\003 +\023\034\123\105\103\117\115\040\123\115\111\115\105\040\122\123 +\101\040\122\157\157\164\040\103\101\040\062\060\062\064 +END +CKA_SERIAL_NUMBER MULTILINE_OCTAL +\002\011\000\335\251\333\236\176\274\324\155 +END +CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_MUST_VERIFY_TRUST +CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR +CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST +CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE + +# +# Certificate "Telia EC Email Root CA v3" +# +# Issuer: CN=Telia EC Email Root CA v3,O=Telia Company AB,C=SE +# Serial Number:01:8b:d2:e1:0c:1e:d8:0d:94:03:87:05:11:00:a6 +# Subject: CN=Telia EC Email Root CA v3,O=Telia Company AB,C=SE +# Not Valid Before: Wed Nov 15 12:14:14 2023 +# Not Valid After : Sat May 23 11:00:00 2048 +# Fingerprint (SHA-256): 36:82:22:8D:7D:67:8B:57:14:40:CF:1C:B3:4E:69:FB:41:35:FD:6C:2A:1B:E3:8E:14:16:3B:71:1E:02:AE:01 +# Fingerprint (SHA1): 33:EA:1C:7E:79:CF:31:66:FD:B9:FA:32:47:73:FB:B7:89:01:00:4F +CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE +CKA_TOKEN CK_BBOOL CK_TRUE +CKA_PRIVATE CK_BBOOL CK_FALSE +CKA_MODIFIABLE CK_BBOOL CK_FALSE +CKA_LABEL UTF8 "Telia EC Email Root CA v3" +CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509 +CKA_SUBJECT MULTILINE_OCTAL +\060\114\061\013\060\011\006\003\125\004\006\023\002\123\105\061 +\031\060\027\006\003\125\004\012\014\020\124\145\154\151\141\040 +\103\157\155\160\141\156\171\040\101\102\061\042\060\040\006\003 +\125\004\003\014\031\124\145\154\151\141\040\105\103\040\105\155 +\141\151\154\040\122\157\157\164\040\103\101\040\166\063 +END +CKA_ID UTF8 "0" +CKA_ISSUER MULTILINE_OCTAL +\060\114\061\013\060\011\006\003\125\004\006\023\002\123\105\061 +\031\060\027\006\003\125\004\012\014\020\124\145\154\151\141\040 +\103\157\155\160\141\156\171\040\101\102\061\042\060\040\006\003 +\125\004\003\014\031\124\145\154\151\141\040\105\103\040\105\155 +\141\151\154\040\122\157\157\164\040\103\101\040\166\063 +END +CKA_SERIAL_NUMBER MULTILINE_OCTAL +\002\017\001\213\322\341\014\036\330\015\224\003\207\005\021\000 +\246 +END +CKA_VALUE MULTILINE_OCTAL +\060\202\002\065\060\202\001\273\240\003\002\001\002\002\017\001 +\213\322\341\014\036\330\015\224\003\207\005\021\000\246\060\012 +\006\010\052\206\110\316\075\004\003\003\060\114\061\013\060\011 +\006\003\125\004\006\023\002\123\105\061\031\060\027\006\003\125 +\004\012\014\020\124\145\154\151\141\040\103\157\155\160\141\156 +\171\040\101\102\061\042\060\040\006\003\125\004\003\014\031\124 +\145\154\151\141\040\105\103\040\105\155\141\151\154\040\122\157 +\157\164\040\103\101\040\166\063\060\036\027\015\062\063\061\061 +\061\065\061\062\061\064\061\064\132\027\015\064\070\060\065\062 +\063\061\061\060\060\060\060\132\060\114\061\013\060\011\006\003 +\125\004\006\023\002\123\105\061\031\060\027\006\003\125\004\012 +\014\020\124\145\154\151\141\040\103\157\155\160\141\156\171\040 +\101\102\061\042\060\040\006\003\125\004\003\014\031\124\145\154 +\151\141\040\105\103\040\105\155\141\151\154\040\122\157\157\164 +\040\103\101\040\166\063\060\166\060\020\006\007\052\206\110\316 +\075\002\001\006\005\053\201\004\000\042\003\142\000\004\224\000 +\346\143\237\026\057\244\370\272\105\045\315\107\053\127\234\131 +\056\207\302\136\363\043\105\231\305\224\256\133\152\302\066\063 +\336\154\267\322\310\274\020\202\351\106\247\016\253\144\015\114 +\056\245\005\347\315\273\064\142\130\251\307\272\334\101\140\052 +\107\031\266\257\036\373\221\221\260\265\234\345\232\127\174\030 +\230\037\222\153\110\262\262\014\011\137\235\341\201\030\243\143 +\060\141\060\037\006\003\125\035\043\004\030\060\026\200\024\056 +\321\321\037\117\251\046\255\246\255\041\230\105\373\023\034\123 +\002\257\346\060\035\006\003\125\035\016\004\026\004\024\056\321 +\321\037\117\251\046\255\246\255\041\230\105\373\023\034\123\002 +\257\346\060\016\006\003\125\035\017\001\001\377\004\004\003\002 +\001\006\060\017\006\003\125\035\023\001\001\377\004\005\060\003 +\001\001\377\060\012\006\010\052\206\110\316\075\004\003\003\003 +\150\000\060\145\002\061\000\353\252\152\365\014\257\201\003\016 +\252\222\077\357\053\033\013\263\264\324\230\330\367\225\244\035 +\252\274\266\277\346\122\230\013\170\134\017\017\243\306\243\151 +\302\275\120\326\157\172\177\002\060\074\035\354\172\365\211\203 +\077\041\351\260\325\170\372\333\120\363\164\007\314\171\247\045 +\362\366\214\070\207\331\266\154\102\364\162\111\114\326\273\135 +\114\256\036\366\372\221\132\052\113 +END +CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE +CKA_NSS_SERVER_DISTRUST_AFTER CK_BBOOL CK_FALSE +CKA_NSS_EMAIL_DISTRUST_AFTER CK_BBOOL CK_FALSE + +# Trust for "Telia EC Email Root CA v3" +# Issuer: CN=Telia EC Email Root CA v3,O=Telia Company AB,C=SE +# Serial Number:01:8b:d2:e1:0c:1e:d8:0d:94:03:87:05:11:00:a6 +# Subject: CN=Telia EC Email Root CA v3,O=Telia Company AB,C=SE +# Not Valid Before: Wed Nov 15 12:14:14 2023 +# Not Valid After : Sat May 23 11:00:00 2048 +# Fingerprint (SHA-256): 36:82:22:8D:7D:67:8B:57:14:40:CF:1C:B3:4E:69:FB:41:35:FD:6C:2A:1B:E3:8E:14:16:3B:71:1E:02:AE:01 +# Fingerprint (SHA1): 33:EA:1C:7E:79:CF:31:66:FD:B9:FA:32:47:73:FB:B7:89:01:00:4F +CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST +CKA_TOKEN CK_BBOOL CK_TRUE +CKA_PRIVATE CK_BBOOL CK_FALSE +CKA_MODIFIABLE CK_BBOOL CK_FALSE +CKA_LABEL UTF8 "Telia EC Email Root CA v3" +CKA_CERT_SHA1_HASH MULTILINE_OCTAL +\063\352\034\176\171\317\061\146\375\271\372\062\107\163\373\267 +\211\001\000\117 +END +CKA_CERT_MD5_HASH MULTILINE_OCTAL +\327\203\306\202\162\144\010\353\243\270\127\205\010\236\106\231 +END +CKA_ISSUER MULTILINE_OCTAL +\060\114\061\013\060\011\006\003\125\004\006\023\002\123\105\061 +\031\060\027\006\003\125\004\012\014\020\124\145\154\151\141\040 +\103\157\155\160\141\156\171\040\101\102\061\042\060\040\006\003 +\125\004\003\014\031\124\145\154\151\141\040\105\103\040\105\155 +\141\151\154\040\122\157\157\164\040\103\101\040\166\063 +END +CKA_SERIAL_NUMBER MULTILINE_OCTAL +\002\017\001\213\322\341\014\036\330\015\224\003\207\005\021\000 +\246 +END +CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_MUST_VERIFY_TRUST +CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR +CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST +CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE + +# +# Certificate "Telia EC TLS Root CA v3" +# +# Issuer: CN=Telia EC TLS Root CA v3,O=Telia Company AB,C=SE +# Serial Number:01:8b:d2:22:54:63:4d:04:8b:6c:e5:47:1f:d2:b5 +# Subject: CN=Telia EC TLS Root CA v3,O=Telia Company AB,C=SE +# Not Valid Before: Wed Nov 15 08:55:26 2023 +# Not Valid After : Sat May 23 11:00:00 2048 +# Fingerprint (SHA-256): 09:8E:08:A9:1D:BB:F7:74:78:B9:6C:CE:B8:9B:14:13:A5:DA:37:B7:C8:62:60:6A:95:5D:EB:07:17:9F:43:26 +# Fingerprint (SHA1): B4:D6:07:C2:A5:95:BC:5B:F4:67:4D:C9:DC:6F:6F:0A:00:7A:A5:35 +CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE +CKA_TOKEN CK_BBOOL CK_TRUE +CKA_PRIVATE CK_BBOOL CK_FALSE +CKA_MODIFIABLE CK_BBOOL CK_FALSE +CKA_LABEL UTF8 "Telia EC TLS Root CA v3" +CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509 +CKA_SUBJECT MULTILINE_OCTAL +\060\112\061\013\060\011\006\003\125\004\006\023\002\123\105\061 +\031\060\027\006\003\125\004\012\014\020\124\145\154\151\141\040 +\103\157\155\160\141\156\171\040\101\102\061\040\060\036\006\003 +\125\004\003\014\027\124\145\154\151\141\040\105\103\040\124\114 +\123\040\122\157\157\164\040\103\101\040\166\063 +END +CKA_ID UTF8 "0" +CKA_ISSUER MULTILINE_OCTAL +\060\112\061\013\060\011\006\003\125\004\006\023\002\123\105\061 +\031\060\027\006\003\125\004\012\014\020\124\145\154\151\141\040 +\103\157\155\160\141\156\171\040\101\102\061\040\060\036\006\003 +\125\004\003\014\027\124\145\154\151\141\040\105\103\040\124\114 +\123\040\122\157\157\164\040\103\101\040\166\063 +END +CKA_SERIAL_NUMBER MULTILINE_OCTAL +\002\017\001\213\322\042\124\143\115\004\213\154\345\107\037\322 +\265 +END +CKA_VALUE MULTILINE_OCTAL +\060\202\002\062\060\202\001\267\240\003\002\001\002\002\017\001 +\213\322\042\124\143\115\004\213\154\345\107\037\322\265\060\012 +\006\010\052\206\110\316\075\004\003\003\060\112\061\013\060\011 +\006\003\125\004\006\023\002\123\105\061\031\060\027\006\003\125 +\004\012\014\020\124\145\154\151\141\040\103\157\155\160\141\156 +\171\040\101\102\061\040\060\036\006\003\125\004\003\014\027\124 +\145\154\151\141\040\105\103\040\124\114\123\040\122\157\157\164 +\040\103\101\040\166\063\060\036\027\015\062\063\061\061\061\065 +\060\070\065\065\062\066\132\027\015\064\070\060\065\062\063\061 +\061\060\060\060\060\132\060\112\061\013\060\011\006\003\125\004 +\006\023\002\123\105\061\031\060\027\006\003\125\004\012\014\020 +\124\145\154\151\141\040\103\157\155\160\141\156\171\040\101\102 +\061\040\060\036\006\003\125\004\003\014\027\124\145\154\151\141 +\040\105\103\040\124\114\123\040\122\157\157\164\040\103\101\040 +\166\063\060\166\060\020\006\007\052\206\110\316\075\002\001\006 +\005\053\201\004\000\042\003\142\000\004\301\310\226\025\103\055 +\271\205\051\112\126\322\042\270\166\232\362\117\247\246\140\347 +\222\337\122\117\301\151\326\076\151\026\106\260\044\115\263\327 +\343\113\020\174\162\075\232\224\173\105\271\055\273\171\340\203 +\245\276\004\024\227\111\347\041\264\300\247\006\145\227\217\361 +\032\126\131\225\345\306\065\214\075\207\241\067\341\005\015\300 +\151\312\102\064\302\311\053\203\151\145\243\143\060\141\060\037 +\006\003\125\035\043\004\030\060\026\200\024\324\144\350\103\210 +\072\163\057\320\032\161\202\066\013\136\205\336\307\336\103\060 +\035\006\003\125\035\016\004\026\004\024\324\144\350\103\210\072 +\163\057\320\032\161\202\066\013\136\205\336\307\336\103\060\016 +\006\003\125\035\017\001\001\377\004\004\003\002\001\006\060\017 +\006\003\125\035\023\001\001\377\004\005\060\003\001\001\377\060 +\012\006\010\052\206\110\316\075\004\003\003\003\151\000\060\146 +\002\061\000\227\001\107\122\377\326\333\047\300\065\045\206\206 +\177\366\326\267\373\073\115\255\050\267\225\045\236\217\016\215 +\043\130\105\144\010\225\056\055\125\151\135\275\060\025\003\270 +\136\070\130\002\061\000\257\052\277\076\147\144\147\370\340\153 +\345\101\363\226\000\116\156\226\235\324\273\260\065\064\134\164 +\330\024\047\022\026\151\327\044\213\345\001\054\110\265\374\005 +\021\051\136\146\167\143 +END +CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE +CKA_NSS_SERVER_DISTRUST_AFTER CK_BBOOL CK_FALSE +CKA_NSS_EMAIL_DISTRUST_AFTER CK_BBOOL CK_FALSE + +# Trust for "Telia EC TLS Root CA v3" +# Issuer: CN=Telia EC TLS Root CA v3,O=Telia Company AB,C=SE +# Serial Number:01:8b:d2:22:54:63:4d:04:8b:6c:e5:47:1f:d2:b5 +# Subject: CN=Telia EC TLS Root CA v3,O=Telia Company AB,C=SE +# Not Valid Before: Wed Nov 15 08:55:26 2023 +# Not Valid After : Sat May 23 11:00:00 2048 +# Fingerprint (SHA-256): 09:8E:08:A9:1D:BB:F7:74:78:B9:6C:CE:B8:9B:14:13:A5:DA:37:B7:C8:62:60:6A:95:5D:EB:07:17:9F:43:26 +# Fingerprint (SHA1): B4:D6:07:C2:A5:95:BC:5B:F4:67:4D:C9:DC:6F:6F:0A:00:7A:A5:35 +CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST +CKA_TOKEN CK_BBOOL CK_TRUE +CKA_PRIVATE CK_BBOOL CK_FALSE +CKA_MODIFIABLE CK_BBOOL CK_FALSE +CKA_LABEL UTF8 "Telia EC TLS Root CA v3" +CKA_CERT_SHA1_HASH MULTILINE_OCTAL +\264\326\007\302\245\225\274\133\364\147\115\311\334\157\157\012 +\000\172\245\065 +END +CKA_CERT_MD5_HASH MULTILINE_OCTAL +\266\372\152\134\102\373\305\147\162\300\340\057\162\373\132\104 +END +CKA_ISSUER MULTILINE_OCTAL +\060\112\061\013\060\011\006\003\125\004\006\023\002\123\105\061 +\031\060\027\006\003\125\004\012\014\020\124\145\154\151\141\040 +\103\157\155\160\141\156\171\040\101\102\061\040\060\036\006\003 +\125\004\003\014\027\124\145\154\151\141\040\105\103\040\124\114 +\123\040\122\157\157\164\040\103\101\040\166\063 +END +CKA_SERIAL_NUMBER MULTILINE_OCTAL +\002\017\001\213\322\042\124\143\115\004\213\154\345\107\037\322 +\265 +END +CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR +CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_MUST_VERIFY_TRUST +CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST +CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE + +# +# Certificate "Telia RSA Email Root CA v3" +# +# Issuer: CN=Telia RSA Email Root CA v3,O=Telia Company AB,C=SE +# Serial Number:01:8b:d2:ce:f4:c1:15:78:29:62:4d:79:b2:75:5b +# Subject: CN=Telia RSA Email Root CA v3,O=Telia Company AB,C=SE +# Not Valid Before: Wed Nov 15 11:55:02 2023 +# Not Valid After : Sat May 23 11:00:00 2048 +# Fingerprint (SHA-256): 5B:0C:50:2A:7D:96:3B:A5:52:17:39:6F:DA:9B:3D:C7:81:71:00:0A:EE:FF:42:CE:CC:3A:20:A7:93:81:63:E8 +# Fingerprint (SHA1): AA:6C:3C:AF:F0:96:C6:4D:C3:27:84:BE:9D:8A:3E:3A:7B:B4:4E:C2 +CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE +CKA_TOKEN CK_BBOOL CK_TRUE +CKA_PRIVATE CK_BBOOL CK_FALSE +CKA_MODIFIABLE CK_BBOOL CK_FALSE +CKA_LABEL UTF8 "Telia RSA Email Root CA v3" +CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509 +CKA_SUBJECT MULTILINE_OCTAL +\060\115\061\013\060\011\006\003\125\004\006\023\002\123\105\061 +\031\060\027\006\003\125\004\012\014\020\124\145\154\151\141\040 +\103\157\155\160\141\156\171\040\101\102\061\043\060\041\006\003 +\125\004\003\014\032\124\145\154\151\141\040\122\123\101\040\105 +\155\141\151\154\040\122\157\157\164\040\103\101\040\166\063 +END +CKA_ID UTF8 "0" +CKA_ISSUER MULTILINE_OCTAL +\060\115\061\013\060\011\006\003\125\004\006\023\002\123\105\061 +\031\060\027\006\003\125\004\012\014\020\124\145\154\151\141\040 +\103\157\155\160\141\156\171\040\101\102\061\043\060\041\006\003 +\125\004\003\014\032\124\145\154\151\141\040\122\123\101\040\105 +\155\141\151\154\040\122\157\157\164\040\103\101\040\166\063 +END +CKA_SERIAL_NUMBER MULTILINE_OCTAL +\002\017\001\213\322\316\364\301\025\170\051\142\115\171\262\165 +\133 +END +CKA_VALUE MULTILINE_OCTAL +\060\202\005\206\060\202\003\156\240\003\002\001\002\002\017\001 +\213\322\316\364\301\025\170\051\142\115\171\262\165\133\060\015 +\006\011\052\206\110\206\367\015\001\001\014\005\000\060\115\061 +\013\060\011\006\003\125\004\006\023\002\123\105\061\031\060\027 +\006\003\125\004\012\014\020\124\145\154\151\141\040\103\157\155 +\160\141\156\171\040\101\102\061\043\060\041\006\003\125\004\003 +\014\032\124\145\154\151\141\040\122\123\101\040\105\155\141\151 +\154\040\122\157\157\164\040\103\101\040\166\063\060\036\027\015 +\062\063\061\061\061\065\061\061\065\065\060\062\132\027\015\064 +\070\060\065\062\063\061\061\060\060\060\060\132\060\115\061\013 +\060\011\006\003\125\004\006\023\002\123\105\061\031\060\027\006 +\003\125\004\012\014\020\124\145\154\151\141\040\103\157\155\160 +\141\156\171\040\101\102\061\043\060\041\006\003\125\004\003\014 +\032\124\145\154\151\141\040\122\123\101\040\105\155\141\151\154 +\040\122\157\157\164\040\103\101\040\166\063\060\202\002\042\060 +\015\006\011\052\206\110\206\367\015\001\001\001\005\000\003\202 +\002\017\000\060\202\002\012\002\202\002\001\000\271\111\073\057 +\133\122\030\311\317\144\254\250\333\366\172\236\076\255\327\201 +\243\354\272\352\201\056\365\275\257\225\321\113\136\210\356\224 +\142\012\313\206\047\011\250\047\321\303\062\243\012\352\356\027 +\145\014\074\023\026\372\337\004\323\153\317\140\212\066\133\367 +\047\226\061\334\333\367\307\156\025\021\272\143\051\273\320\211 +\160\154\343\110\242\064\231\310\372\112\222\217\260\176\222\056 +\354\246\164\371\321\052\234\163\302\162\053\124\217\011\170\173 +\357\046\014\076\362\174\072\021\135\041\007\325\317\276\136\043 +\210\240\053\005\302\214\277\051\277\130\105\074\361\152\310\253 +\364\376\071\376\262\156\025\132\017\247\113\076\151\304\273\073 +\321\222\240\330\137\050\201\302\275\112\226\245\241\106\161\370 +\015\261\021\143\152\246\001\137\305\163\172\330\111\112\056\301 +\064\276\077\145\336\302\152\306\217\040\330\276\046\002\272\307 +\162\042\026\230\231\227\346\144\155\111\070\220\312\324\161\006 +\264\204\042\264\236\063\064\126\312\035\166\251\232\110\335\314 +\365\217\056\211\111\306\172\006\003\217\257\216\354\200\162\025 +\361\331\011\200\130\122\251\302\034\255\076\137\067\061\146\227 +\020\241\330\163\264\335\056\302\063\245\176\247\130\233\201\021 +\153\210\325\374\113\265\055\272\176\374\121\255\347\076\115\256 +\363\316\121\236\345\123\213\257\036\250\102\344\145\271\362\346 +\052\103\347\117\074\365\333\321\334\273\240\337\027\330\341\276 +\122\131\147\076\041\024\072\203\131\176\157\203\331\225\153\061 +\171\143\216\311\135\324\064\215\370\344\332\056\256\331\010\353 +\333\263\034\351\335\225\030\256\142\233\065\200\105\357\322\224 +\240\326\013\340\242\311\040\100\063\265\113\173\230\066\144\064 +\227\324\213\003\267\172\212\233\147\052\225\223\143\263\362\362 +\037\024\054\021\250\321\146\014\332\106\346\014\336\125\272\107 +\043\306\352\017\262\103\135\216\376\017\127\324\257\347\312\070 +\313\326\333\231\273\112\130\266\150\241\324\212\045\162\252\233 +\015\100\072\246\241\243\036\267\132\055\241\347\240\071\217\306 +\104\324\240\166\137\210\074\377\345\045\120\214\356\074\176\022 +\066\075\262\136\045\107\066\151\231\024\041\137\002\003\001\000 +\001\243\143\060\141\060\037\006\003\125\035\043\004\030\060\026 +\200\024\207\271\006\077\106\305\051\024\315\024\136\305\236\043 +\220\266\044\256\146\231\060\035\006\003\125\035\016\004\026\004 +\024\207\271\006\077\106\305\051\024\315\024\136\305\236\043\220 +\266\044\256\146\231\060\016\006\003\125\035\017\001\001\377\004 +\004\003\002\001\006\060\017\006\003\125\035\023\001\001\377\004 +\005\060\003\001\001\377\060\015\006\011\052\206\110\206\367\015 +\001\001\014\005\000\003\202\002\001\000\215\123\131\331\377\073 +\062\217\327\061\076\355\166\235\015\206\215\342\060\120\160\270 +\235\331\237\022\071\313\235\257\265\256\303\207\341\153\304\355 +\203\020\274\105\172\266\231\360\264\171\174\155\065\243\223\220 +\054\060\206\261\377\205\327\214\145\127\130\222\007\110\354\107 +\230\267\347\166\306\167\140\377\107\354\167\100\255\034\055\352 +\337\122\314\222\176\245\333\053\107\365\033\247\107\100\135\161 +\163\110\304\323\375\247\260\043\100\261\043\273\353\332\201\100 +\305\062\007\331\051\311\023\006\266\030\226\127\131\213\140\001 +\257\357\014\230\112\113\246\026\242\241\043\103\254\125\151\114 +\061\137\373\141\274\053\263\305\002\061\265\124\077\165\031\253 +\135\074\076\144\305\343\353\360\177\262\212\272\057\004\062\073 +\362\003\336\052\273\302\011\342\243\045\363\115\056\206\170\126 +\330\074\107\055\144\255\372\001\171\260\330\210\116\353\262\301 +\132\345\113\272\066\304\031\102\353\233\056\014\015\244\370\273 +\332\044\036\000\234\356\112\043\321\241\264\242\317\135\047\252 +\102\123\203\042\204\024\227\050\134\227\171\246\140\274\207\066 +\231\370\303\027\150\342\272\145\363\016\312\066\327\323\044\074 +\301\011\211\356\373\023\271\103\250\051\024\305\273\101\107\264 +\366\112\275\333\107\042\317\367\243\332\060\126\306\175\230\145 +\045\151\120\140\152\365\372\265\277\214\170\033\167\255\271\135 +\316\327\227\151\156\356\011\346\337\226\167\273\006\223\252\123 +\241\234\331\053\273\336\073\231\042\004\251\274\024\366\075\003 +\242\363\065\224\074\116\037\142\276\360\262\347\130\271\323\027 +\051\305\253\016\325\113\145\106\031\133\044\072\142\111\044\005 +\212\300\170\367\024\224\321\257\013\037\067\154\064\005\316\147 +\361\166\300\367\254\144\110\326\127\232\050\363\027\117\232\367 +\003\264\040\021\142\237\377\032\252\151\063\141\050\176\075\366 +\304\150\027\314\063\071\303\316\122\341\366\262\273\125\134\146 +\155\237\341\074\256\246\016\025\115\106\361\326\004\015\205\226 +\263\137\050\024\117\316\326\233\341\372\015\163\154\157\247\375 +\271\351\052\244\267\100\114\160\016\070\117\033\254\307\165\050 +\170\251\167\066\232\150\164\240\327\267 +END +CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE +CKA_NSS_SERVER_DISTRUST_AFTER CK_BBOOL CK_FALSE +CKA_NSS_EMAIL_DISTRUST_AFTER CK_BBOOL CK_FALSE + +# Trust for "Telia RSA Email Root CA v3" +# Issuer: CN=Telia RSA Email Root CA v3,O=Telia Company AB,C=SE +# Serial Number:01:8b:d2:ce:f4:c1:15:78:29:62:4d:79:b2:75:5b +# Subject: CN=Telia RSA Email Root CA v3,O=Telia Company AB,C=SE +# Not Valid Before: Wed Nov 15 11:55:02 2023 +# Not Valid After : Sat May 23 11:00:00 2048 +# Fingerprint (SHA-256): 5B:0C:50:2A:7D:96:3B:A5:52:17:39:6F:DA:9B:3D:C7:81:71:00:0A:EE:FF:42:CE:CC:3A:20:A7:93:81:63:E8 +# Fingerprint (SHA1): AA:6C:3C:AF:F0:96:C6:4D:C3:27:84:BE:9D:8A:3E:3A:7B:B4:4E:C2 +CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST +CKA_TOKEN CK_BBOOL CK_TRUE +CKA_PRIVATE CK_BBOOL CK_FALSE +CKA_MODIFIABLE CK_BBOOL CK_FALSE +CKA_LABEL UTF8 "Telia RSA Email Root CA v3" +CKA_CERT_SHA1_HASH MULTILINE_OCTAL +\252\154\074\257\360\226\306\115\303\047\204\276\235\212\076\072 +\173\264\116\302 +END +CKA_CERT_MD5_HASH MULTILINE_OCTAL +\173\170\307\204\252\212\256\263\377\237\272\146\072\007\164\361 +END +CKA_ISSUER MULTILINE_OCTAL +\060\115\061\013\060\011\006\003\125\004\006\023\002\123\105\061 +\031\060\027\006\003\125\004\012\014\020\124\145\154\151\141\040 +\103\157\155\160\141\156\171\040\101\102\061\043\060\041\006\003 +\125\004\003\014\032\124\145\154\151\141\040\122\123\101\040\105 +\155\141\151\154\040\122\157\157\164\040\103\101\040\166\063 +END +CKA_SERIAL_NUMBER MULTILINE_OCTAL +\002\017\001\213\322\316\364\301\025\170\051\142\115\171\262\165 +\133 +END +CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_MUST_VERIFY_TRUST +CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR +CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST +CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE + +# +# Certificate "Telia RSA TLS Root CA v3" +# +# Issuer: CN=Telia RSA TLS Root CA v3,O=Telia Company AB,C=SE +# Serial Number:01:8b:d2:50:ab:42:55:2c:47:5a:bd:a1:dc:1a:c5 +# Subject: CN=Telia RSA TLS Root CA v3,O=Telia Company AB,C=SE +# Not Valid Before: Wed Nov 15 09:47:42 2023 +# Not Valid After : Sat May 23 11:00:00 2048 +# Fingerprint (SHA-256): D1:3D:B1:29:4C:45:EB:C6:FC:86:C6:BB:F6:9F:A2:9B:DF:E6:92:DF:F7:C7:13:C2:43:C7:A9:56:C6:A2:28:4C +# Fingerprint (SHA1): B5:2E:88:4E:40:C1:11:FB:50:C7:E2:4F:AC:18:2B:BD:68:15:D2:34 +CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE +CKA_TOKEN CK_BBOOL CK_TRUE +CKA_PRIVATE CK_BBOOL CK_FALSE +CKA_MODIFIABLE CK_BBOOL CK_FALSE +CKA_LABEL UTF8 "Telia RSA TLS Root CA v3" +CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509 +CKA_SUBJECT MULTILINE_OCTAL +\060\113\061\013\060\011\006\003\125\004\006\023\002\123\105\061 +\031\060\027\006\003\125\004\012\014\020\124\145\154\151\141\040 +\103\157\155\160\141\156\171\040\101\102\061\041\060\037\006\003 +\125\004\003\014\030\124\145\154\151\141\040\122\123\101\040\124 +\114\123\040\122\157\157\164\040\103\101\040\166\063 +END +CKA_ID UTF8 "0" +CKA_ISSUER MULTILINE_OCTAL +\060\113\061\013\060\011\006\003\125\004\006\023\002\123\105\061 +\031\060\027\006\003\125\004\012\014\020\124\145\154\151\141\040 +\103\157\155\160\141\156\171\040\101\102\061\041\060\037\006\003 +\125\004\003\014\030\124\145\154\151\141\040\122\123\101\040\124 +\114\123\040\122\157\157\164\040\103\101\040\166\063 +END +CKA_SERIAL_NUMBER MULTILINE_OCTAL +\002\017\001\213\322\120\253\102\125\054\107\132\275\241\334\032 +\305 +END +CKA_VALUE MULTILINE_OCTAL +\060\202\005\202\060\202\003\152\240\003\002\001\002\002\017\001 +\213\322\120\253\102\125\054\107\132\275\241\334\032\305\060\015 +\006\011\052\206\110\206\367\015\001\001\014\005\000\060\113\061 +\013\060\011\006\003\125\004\006\023\002\123\105\061\031\060\027 +\006\003\125\004\012\014\020\124\145\154\151\141\040\103\157\155 +\160\141\156\171\040\101\102\061\041\060\037\006\003\125\004\003 +\014\030\124\145\154\151\141\040\122\123\101\040\124\114\123\040 +\122\157\157\164\040\103\101\040\166\063\060\036\027\015\062\063 +\061\061\061\065\060\071\064\067\064\062\132\027\015\064\070\060 +\065\062\063\061\061\060\060\060\060\132\060\113\061\013\060\011 +\006\003\125\004\006\023\002\123\105\061\031\060\027\006\003\125 +\004\012\014\020\124\145\154\151\141\040\103\157\155\160\141\156 +\171\040\101\102\061\041\060\037\006\003\125\004\003\014\030\124 +\145\154\151\141\040\122\123\101\040\124\114\123\040\122\157\157 +\164\040\103\101\040\166\063\060\202\002\042\060\015\006\011\052 +\206\110\206\367\015\001\001\001\005\000\003\202\002\017\000\060 +\202\002\012\002\202\002\001\000\261\137\075\050\155\175\204\047 +\370\113\121\157\223\300\367\117\040\304\106\031\234\277\037\005 +\354\251\233\341\140\023\307\170\243\173\130\235\334\241\361\104 +\115\023\052\147\015\011\260\020\347\266\357\034\121\030\153\210 +\121\332\135\264\126\065\132\164\114\152\071\157\266\225\337\175 +\061\261\042\073\350\321\124\354\376\005\274\113\304\231\346\033 +\000\252\043\340\137\271\070\343\125\027\203\306\314\143\102\370 +\340\006\300\245\150\357\354\233\230\273\322\171\131\161\141\221 +\264\211\057\130\062\267\064\331\023\345\033\160\135\317\316\360 +\324\305\126\226\324\251\076\234\106\062\043\336\211\100\156\124 +\176\225\027\370\025\374\271\243\344\075\175\246\343\142\177\131 +\365\056\042\266\273\204\225\301\005\177\322\343\223\267\360\165 +\074\234\117\372\357\045\157\160\374\035\306\331\255\353\321\377 +\363\134\323\225\256\342\001\162\241\072\246\104\250\262\220\002 +\123\146\306\343\147\330\052\266\314\374\145\247\247\273\276\247 +\321\153\317\210\332\067\012\133\341\201\356\021\344\274\006\266 +\255\065\303\374\137\255\243\134\213\357\050\174\145\260\300\311 +\012\166\370\123\302\163\024\342\354\123\251\250\205\126\071\360 +\027\131\256\370\264\032\117\124\072\352\246\202\201\272\166\311 +\007\242\113\043\145\071\112\353\120\377\042\174\346\022\200\065 +\310\006\011\024\065\162\262\064\161\015\103\256\365\300\060\000 +\326\352\232\256\373\130\201\113\350\032\147\146\005\152\076\323 +\037\033\254\015\360\032\323\051\326\251\276\051\125\261\204\171 +\364\021\140\042\300\025\004\314\153\032\037\226\371\007\057\230 +\226\237\122\220\022\276\120\053\052\365\106\330\122\070\213\243 +\342\056\064\201\117\117\272\027\241\020\056\266\052\171\363\220 +\027\367\301\064\105\333\372\170\324\103\104\224\126\260\052\264 +\176\030\370\350\302\043\366\270\374\222\120\246\234\136\172\146 +\134\103\104\224\112\030\042\043\220\014\347\021\316\346\054\232 +\122\264\343\140\176\063\305\114\375\217\355\105\021\260\307\377 +\032\154\266\275\140\134\034\244\262\233\251\372\024\123\150\227 +\033\003\345\033\244\232\255\131\231\335\000\367\135\046\153\172 +\140\224\076\165\115\351\016\357\002\003\001\000\001\243\143\060 +\141\060\037\006\003\125\035\043\004\030\060\026\200\024\260\307 +\251\322\335\262\050\126\163\004\224\214\024\134\110\157\067\122 +\222\250\060\035\006\003\125\035\016\004\026\004\024\260\307\251 +\322\335\262\050\126\163\004\224\214\024\134\110\157\067\122\222 +\250\060\016\006\003\125\035\017\001\001\377\004\004\003\002\001 +\006\060\017\006\003\125\035\023\001\001\377\004\005\060\003\001 +\001\377\060\015\006\011\052\206\110\206\367\015\001\001\014\005 +\000\003\202\002\001\000\135\143\061\154\064\140\321\223\266\321 +\374\010\021\052\257\271\353\176\330\270\345\276\303\253\241\246 +\204\264\126\162\214\122\234\207\013\011\056\363\250\104\276\250 +\257\152\103\355\176\151\146\341\261\160\267\357\254\157\377\016 +\136\305\201\252\327\333\134\306\201\064\064\331\227\305\321\060 +\233\213\130\345\266\046\266\312\221\034\340\033\107\201\121\313 +\354\151\321\265\256\270\133\231\232\230\274\125\332\001\223\273 +\243\204\335\071\234\361\204\020\171\030\340\026\131\160\167\041 +\352\332\064\376\011\353\174\362\243\331\374\032\254\067\260\220 +\106\343\207\246\346\032\030\214\027\337\077\351\351\211\274\254 +\226\173\045\106\056\013\353\021\354\011\210\377\075\246\376\072 +\132\233\060\040\172\277\353\023\010\267\204\042\351\021\127\072 +\021\365\244\070\346\221\012\355\235\120\006\164\254\154\002\220 +\266\313\064\044\240\375\167\371\227\327\215\307\327\027\217\214 +\370\123\136\133\371\044\051\041\255\310\376\111\050\163\320\377 +\176\020\172\026\173\251\275\227\045\004\070\205\147\322\272\176 +\311\122\126\065\271\262\016\375\325\223\001\161\034\055\100\245 +\044\054\201\050\246\214\144\070\302\332\372\161\051\250\255\326 +\061\221\137\221\243\311\116\040\210\121\222\305\317\310\071\066 +\356\005\272\042\065\027\012\106\112\247\021\143\220\275\343\210 +\024\234\361\051\061\237\000\226\265\170\074\307\003\160\164\125 +\115\004\142\302\012\342\147\262\167\230\136\062\115\253\064\152 +\121\312\006\303\073\057\027\164\042\375\231\307\120\333\310\111 +\327\257\226\002\000\134\276\026\276\274\132\252\372\032\323\134 +\001\370\140\237\263\236\321\114\141\070\116\360\006\204\243\112 +\272\317\012\336\024\123\324\024\251\212\014\314\041\034\322\306 +\320\016\256\243\315\352\077\377\101\051\226\365\377\011\162\167 +\053\213\210\366\212\024\251\126\261\124\320\327\115\220\310\131 +\170\002\242\165\061\117\263\020\225\026\345\270\002\170\263\356 +\072\242\303\233\026\266\066\320\256\125\264\337\230\263\040\105 +\070\261\214\020\240\055\115\307\104\257\313\351\214\115\026\242 +\347\102\352\025\017\200\327\361\352\353\021\307\014\334\173\010 +\217\067\167\155\304\257 +END +CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE +CKA_NSS_SERVER_DISTRUST_AFTER CK_BBOOL CK_FALSE +CKA_NSS_EMAIL_DISTRUST_AFTER CK_BBOOL CK_FALSE + +# Trust for "Telia RSA TLS Root CA v3" +# Issuer: CN=Telia RSA TLS Root CA v3,O=Telia Company AB,C=SE +# Serial Number:01:8b:d2:50:ab:42:55:2c:47:5a:bd:a1:dc:1a:c5 +# Subject: CN=Telia RSA TLS Root CA v3,O=Telia Company AB,C=SE +# Not Valid Before: Wed Nov 15 09:47:42 2023 +# Not Valid After : Sat May 23 11:00:00 2048 +# Fingerprint (SHA-256): D1:3D:B1:29:4C:45:EB:C6:FC:86:C6:BB:F6:9F:A2:9B:DF:E6:92:DF:F7:C7:13:C2:43:C7:A9:56:C6:A2:28:4C +# Fingerprint (SHA1): B5:2E:88:4E:40:C1:11:FB:50:C7:E2:4F:AC:18:2B:BD:68:15:D2:34 +CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST +CKA_TOKEN CK_BBOOL CK_TRUE +CKA_PRIVATE CK_BBOOL CK_FALSE +CKA_MODIFIABLE CK_BBOOL CK_FALSE +CKA_LABEL UTF8 "Telia RSA TLS Root CA v3" +CKA_CERT_SHA1_HASH MULTILINE_OCTAL +\265\056\210\116\100\301\021\373\120\307\342\117\254\030\053\275 +\150\025\322\064 +END +CKA_CERT_MD5_HASH MULTILINE_OCTAL +\364\213\234\363\370\143\317\334\045\217\264\273\242\351\235\342 +END +CKA_ISSUER MULTILINE_OCTAL +\060\113\061\013\060\011\006\003\125\004\006\023\002\123\105\061 +\031\060\027\006\003\125\004\012\014\020\124\145\154\151\141\040 +\103\157\155\160\141\156\171\040\101\102\061\041\060\037\006\003 +\125\004\003\014\030\124\145\154\151\141\040\122\123\101\040\124 +\114\123\040\122\157\157\164\040\103\101\040\166\063 +END +CKA_SERIAL_NUMBER MULTILINE_OCTAL +\002\017\001\213\322\120\253\102\125\054\107\132\275\241\334\032 +\305 +END +CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR +CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_MUST_VERIFY_TRUST +CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST +CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE diff --git a/tools/clang-format/package-lock.json b/tools/clang-format/package-lock.json index 5d03eb31fde1..10ee47a76269 100644 --- a/tools/clang-format/package-lock.json +++ b/tools/clang-format/package-lock.json @@ -23,9 +23,9 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/brace-expansion": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", - "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -193,9 +193,9 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "brace-expansion": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", - "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" diff --git a/tools/doc/type-parser.mjs b/tools/doc/type-parser.mjs index af7c97cf0fae..babf0464bb66 100644 --- a/tools/doc/type-parser.mjs +++ b/tools/doc/type-parser.mjs @@ -270,6 +270,7 @@ const customTypesMap = { 'URLSearchParams': 'url.html#class-urlsearchparams', 'MIMEParams': 'util.html#class-utilmimeparams', + 'MIMEType': 'util.html#class-utilmimetype', 'vm.Module': 'vm.html#class-vmmodule', 'vm.Script': 'vm.html#class-vmscript', diff --git a/tools/eslint/package-lock.json b/tools/eslint/package-lock.json index 82bdd3efb8c2..fc7840daff98 100644 --- a/tools/eslint/package-lock.json +++ b/tools/eslint/package-lock.json @@ -1408,9 +1408,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", - "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", "funding": [ { "type": "github", diff --git a/tools/icu/icu-generic.gyp b/tools/icu/icu-generic.gyp index f49b4ddba74a..c4e8c6fbb9f8 100644 --- a/tools/icu/icu-generic.gyp +++ b/tools/icu/icu-generic.gyp @@ -208,6 +208,7 @@ 'outputs': [ '<(SHARED_INTERMEDIATE_DIR)/icudt<(icu_ver_major)<(icu_endianness)_dat.<(icu_asm_ext)' ], 'action': [ '<(PRODUCT_DIR)/genccode<(EXECUTABLE_SUFFIX)', '<@(icu_asm_opts)', # -o + '-c', '<(target_arch)', '-d', '<(SHARED_INTERMEDIATE_DIR)/', '-n', 'icudata', '-e', 'icusmdt<(icu_ver_major)', diff --git a/tools/icu/patches/78/source/i18n/dtfmtsym.cpp b/tools/icu/patches/78/source/i18n/dtfmtsym.cpp new file mode 100644 index 000000000000..6c2a417eccde --- /dev/null +++ b/tools/icu/patches/78/source/i18n/dtfmtsym.cpp @@ -0,0 +1,2653 @@ +// © 2016 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html +/* +******************************************************************************* +* Copyright (C) 1997-2016, International Business Machines Corporation and * +* others. All Rights Reserved. * +******************************************************************************* +* +* File DTFMTSYM.CPP +* +* Modification History: +* +* Date Name Description +* 02/19/97 aliu Converted from java. +* 07/21/98 stephen Added getZoneIndex +* Changed weekdays/short weekdays to be one-based +* 06/14/99 stephen Removed SimpleDateFormat::fgTimeZoneDataSuffix +* 11/16/99 weiv Added 'Y' and 'e' to fgPatternChars +* 03/27/00 weiv Keeping resource bundle around! +* 06/30/05 emmons Added eraNames, narrow month/day, standalone context +* 10/12/05 emmons Added setters for eraNames, month/day by width/context +******************************************************************************* +*/ + +#include + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#include "unicode/ustring.h" +#include "unicode/localpointer.h" +#include "unicode/dtfmtsym.h" +#include "unicode/errorcode.h" +#include "unicode/smpdtfmt.h" +#include "unicode/msgfmt.h" +#include "unicode/numsys.h" +#include "unicode/tznames.h" +#include "cpputils.h" +#include "umutex.h" +#include "cmemory.h" +#include "cstring.h" +#include "charstr.h" +#include "erarules.h" +#include "dt_impl.h" +#include "locbased.h" +#include "gregoimp.h" +#include "hash.h" +#include "uassert.h" +#include "uresimp.h" +#include "ureslocs.h" +#include "uvector.h" +#include "shareddateformatsymbols.h" +#include "unicode/calendar.h" +#include "unifiedcache.h" + +// ***************************************************************************** +// class DateFormatSymbols +// ***************************************************************************** + +/** + * These are static arrays we use only in the case where we have no + * resource data. + */ + +#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR +#define PATTERN_CHARS_LEN 38 +#else +#define PATTERN_CHARS_LEN 37 +#endif + +/** + * Unlocalized date-time pattern characters. For example: 'y', 'd', etc. All + * locales use the same these unlocalized pattern characters. + */ +static const char16_t gPatternChars[] = { + // if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR: + // GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB: + // else: + // GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB + + 0x47, 0x79, 0x4D, 0x64, 0x6B, 0x48, 0x6D, 0x73, 0x53, 0x45, + 0x44, 0x46, 0x77, 0x57, 0x61, 0x68, 0x4B, 0x7A, 0x59, 0x65, + 0x75, 0x67, 0x41, 0x5A, 0x76, 0x63, 0x4c, 0x51, 0x71, 0x56, + 0x55, 0x4F, 0x58, 0x78, 0x72, 0x62, 0x42, +#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR + 0x3a, +#endif + 0 +}; + +/** + * Map of each ASCII character to its corresponding index in the table above if + * it is a pattern character and -1 otherwise. + */ +static const int8_t gLookupPatternChars[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + // + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + // ! " # $ % & ' ( ) * + , - . / + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR + // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 37, -1, -1, -1, -1, -1, +#else + // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +#endif + // @ A B C D E F G H I J K L M N O + -1, 22, 36, -1, 10, 9, 11, 0, 5, -1, -1, 16, 26, 2, -1, 31, + // P Q R S T U V W X Y Z [ \ ] ^ _ + -1, 27, -1, 8, -1, 30, 29, 13, 32, 18, 23, -1, -1, -1, -1, -1, + // ` a b c d e f g h i j k l m n o + -1, 14, 35, 25, 3, 19, -1, 21, 15, -1, -1, 4, -1, 6, -1, -1, + // p q r s t u v w x y z { | } ~ + -1, 28, 34, 7, -1, 20, 24, 12, 33, 1, 17, -1, -1, -1, -1, -1 +}; + +//------------------------------------------------------ +// Strings of last resort. These are only used if we have no resource +// files. They aren't designed for actual use, just for backup. + +// These are the month names and abbreviations of last resort. +static const char16_t gLastResortMonthNames[13][3] = +{ + {0x0030, 0x0031, 0x0000}, /* "01" */ + {0x0030, 0x0032, 0x0000}, /* "02" */ + {0x0030, 0x0033, 0x0000}, /* "03" */ + {0x0030, 0x0034, 0x0000}, /* "04" */ + {0x0030, 0x0035, 0x0000}, /* "05" */ + {0x0030, 0x0036, 0x0000}, /* "06" */ + {0x0030, 0x0037, 0x0000}, /* "07" */ + {0x0030, 0x0038, 0x0000}, /* "08" */ + {0x0030, 0x0039, 0x0000}, /* "09" */ + {0x0031, 0x0030, 0x0000}, /* "10" */ + {0x0031, 0x0031, 0x0000}, /* "11" */ + {0x0031, 0x0032, 0x0000}, /* "12" */ + {0x0031, 0x0033, 0x0000} /* "13" */ +}; + +// These are the weekday names and abbreviations of last resort. +static const char16_t gLastResortDayNames[8][2] = +{ + {0x0030, 0x0000}, /* "0" */ + {0x0031, 0x0000}, /* "1" */ + {0x0032, 0x0000}, /* "2" */ + {0x0033, 0x0000}, /* "3" */ + {0x0034, 0x0000}, /* "4" */ + {0x0035, 0x0000}, /* "5" */ + {0x0036, 0x0000}, /* "6" */ + {0x0037, 0x0000} /* "7" */ +}; + +// These are the quarter names and abbreviations of last resort. +static const char16_t gLastResortQuarters[4][2] = +{ + {0x0031, 0x0000}, /* "1" */ + {0x0032, 0x0000}, /* "2" */ + {0x0033, 0x0000}, /* "3" */ + {0x0034, 0x0000}, /* "4" */ +}; + +// These are the am/pm and BC/AD markers of last resort. +static const char16_t gLastResortAmPmMarkers[2][3] = +{ + {0x0041, 0x004D, 0x0000}, /* "AM" */ + {0x0050, 0x004D, 0x0000} /* "PM" */ +}; + +static const char16_t gLastResortEras[2][3] = +{ + {0x0042, 0x0043, 0x0000}, /* "BC" */ + {0x0041, 0x0044, 0x0000} /* "AD" */ +}; + +/* Sizes for the last resort string arrays */ +typedef enum LastResortSize { + kMonthNum = 13, + kMonthLen = 3, + + kDayNum = 8, + kDayLen = 2, + + kAmPmNum = 2, + kAmPmLen = 3, + + kQuarterNum = 4, + kQuarterLen = 2, + + kEraNum = 2, + kEraLen = 3, + + kZoneNum = 5, + kZoneLen = 4, + + kGmtHourNum = 4, + kGmtHourLen = 10 +} LastResortSize; + +U_NAMESPACE_BEGIN + +SharedDateFormatSymbols::~SharedDateFormatSymbols() { +} + +template<> U_I18N_API +const SharedDateFormatSymbols * + LocaleCacheKey::createObject( + const void * /*unusedContext*/, UErrorCode &status) const { + char type[256]; + Calendar::getCalendarTypeFromLocale(fLoc, type, UPRV_LENGTHOF(type), status); + if (U_FAILURE(status)) { + return nullptr; + } + SharedDateFormatSymbols *shared + = new SharedDateFormatSymbols(fLoc, type, status); + if (shared == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } + if (U_FAILURE(status)) { + delete shared; + return nullptr; + } + shared->addRef(); + return shared; +} + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateFormatSymbols) + +#define kSUPPLEMENTAL "supplementalData" + +/** + * These are the tags we expect to see in normal resource bundle files associated + * with a locale and calendar + */ +static const char gCalendarTag[]="calendar"; +static const char gGregorianTag[]="gregorian"; +static const char gErasTag[]="eras"; +static const char gCyclicNameSetsTag[]="cyclicNameSets"; +static const char gNameSetYearsTag[]="years"; +static const char gNameSetZodiacsTag[]="zodiacs"; +static const char gMonthNamesTag[]="monthNames"; +static const char gMonthPatternsTag[]="monthPatterns"; +static const char gDayNamesTag[]="dayNames"; +static const char gNamesWideTag[]="wide"; +static const char gNamesAbbrTag[]="abbreviated"; +static const char gNamesShortTag[]="short"; +static const char gNamesNarrowTag[]="narrow"; +static const char gNamesAllTag[]="all"; +static const char gNamesFormatTag[]="format"; +static const char gNamesStandaloneTag[]="stand-alone"; +static const char gNamesNumericTag[]="numeric"; +static const char gAmPmMarkersTag[]="AmPmMarkers"; +static const char gAmPmMarkersAbbrTag[]="AmPmMarkersAbbr"; +static const char gAmPmMarkersNarrowTag[]="AmPmMarkersNarrow"; +static const char gQuartersTag[]="quarters"; +static const char gNumberElementsTag[]="NumberElements"; +static const char gSymbolsTag[]="symbols"; +static const char gTimeSeparatorTag[]="timeSeparator"; +static const char gDayPeriodTag[]="dayPeriod"; + +// static const char gZoneStringsTag[]="zoneStrings"; + +// static const char gLocalPatternCharsTag[]="localPatternChars"; + +static const char gContextTransformsTag[]="contextTransforms"; + +/** + * Jitterbug 2974: MSVC has a bug whereby new X[0] behaves badly. + * Work around this. + */ +static inline UnicodeString* newUnicodeStringArray(size_t count) { + return new UnicodeString[count ? count : 1]; +} + +//------------------------------------------------------ + +DateFormatSymbols * U_EXPORT2 +DateFormatSymbols::createForLocale( + const Locale& locale, UErrorCode &status) { + const SharedDateFormatSymbols *shared = nullptr; + UnifiedCache::getByLocale(locale, shared, status); + if (U_FAILURE(status)) { + return nullptr; + } + DateFormatSymbols *result = new DateFormatSymbols(shared->get()); + shared->removeRef(); + if (result == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } + return result; +} + +DateFormatSymbols::DateFormatSymbols(const Locale& locale, + UErrorCode& status) + : UObject() +{ + initializeData(locale, nullptr, status); +} + +DateFormatSymbols::DateFormatSymbols(UErrorCode& status) + : UObject() +{ + initializeData(Locale::getDefault(), nullptr, status, true); +} + + +DateFormatSymbols::DateFormatSymbols(const Locale& locale, + const char *type, + UErrorCode& status) + : UObject() +{ + initializeData(locale, type, status); +} + +DateFormatSymbols::DateFormatSymbols(const char *type, UErrorCode& status) + : UObject() +{ + initializeData(Locale::getDefault(), type, status, true); +} + +DateFormatSymbols::DateFormatSymbols(const DateFormatSymbols& other) + : UObject(other) +{ + copyData(other); +} + +void +DateFormatSymbols::assignArray(UnicodeString*& dstArray, + int32_t& dstCount, + const UnicodeString* srcArray, + int32_t srcCount) +{ + // assignArray() is only called by copyData() and initializeData(), which in turn + // implements the copy constructor and the assignment operator. + // All strings in a DateFormatSymbols object are created in one of the following + // three ways that all allow to safely use UnicodeString::fastCopyFrom(): + // - readonly-aliases from resource bundles + // - readonly-aliases or allocated strings from constants + // - safely cloned strings (with owned buffers) from setXYZ() functions + // + // Note that this is true for as long as DateFormatSymbols can be constructed + // only from a locale bundle or set via the cloning API, + // *and* for as long as all the strings are in *private* fields, preventing + // a subclass from creating these strings in an "unsafe" way (with respect to fastCopyFrom()). + if(srcArray == nullptr) { + // Do not attempt to copy bogus input (which will crash). + // Note that this assignArray method already had the potential to return a null dstArray; + // see handling below for "if(dstArray != nullptr)". + dstCount = 0; + dstArray = nullptr; + return; + } + dstCount = srcCount; + dstArray = newUnicodeStringArray(srcCount); + if(dstArray != nullptr) { + int32_t i; + for(i=0; i(uprv_malloc(fZoneStringsRowCount * sizeof(UnicodeString*))); + if (fZoneStrings != nullptr) { + for (row=0; row= 0; i--) { + delete[] fZoneStrings[i]; + } + uprv_free(fZoneStrings); + fZoneStrings = nullptr; + } +} + +/** + * Copy all of the other's data to this. + */ +void +DateFormatSymbols::copyData(const DateFormatSymbols& other) { + validLocale = other.validLocale; + actualLocale = other.actualLocale; + assignArray(fEras, fErasCount, other.fEras, other.fErasCount); + assignArray(fEraNames, fEraNamesCount, other.fEraNames, other.fEraNamesCount); + assignArray(fNarrowEras, fNarrowErasCount, other.fNarrowEras, other.fNarrowErasCount); + assignArray(fMonths, fMonthsCount, other.fMonths, other.fMonthsCount); + assignArray(fShortMonths, fShortMonthsCount, other.fShortMonths, other.fShortMonthsCount); + assignArray(fNarrowMonths, fNarrowMonthsCount, other.fNarrowMonths, other.fNarrowMonthsCount); + assignArray(fStandaloneMonths, fStandaloneMonthsCount, other.fStandaloneMonths, other.fStandaloneMonthsCount); + assignArray(fStandaloneShortMonths, fStandaloneShortMonthsCount, other.fStandaloneShortMonths, other.fStandaloneShortMonthsCount); + assignArray(fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, other.fStandaloneNarrowMonths, other.fStandaloneNarrowMonthsCount); + assignArray(fWeekdays, fWeekdaysCount, other.fWeekdays, other.fWeekdaysCount); + assignArray(fShortWeekdays, fShortWeekdaysCount, other.fShortWeekdays, other.fShortWeekdaysCount); + assignArray(fShorterWeekdays, fShorterWeekdaysCount, other.fShorterWeekdays, other.fShorterWeekdaysCount); + assignArray(fNarrowWeekdays, fNarrowWeekdaysCount, other.fNarrowWeekdays, other.fNarrowWeekdaysCount); + assignArray(fStandaloneWeekdays, fStandaloneWeekdaysCount, other.fStandaloneWeekdays, other.fStandaloneWeekdaysCount); + assignArray(fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, other.fStandaloneShortWeekdays, other.fStandaloneShortWeekdaysCount); + assignArray(fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount, other.fStandaloneShorterWeekdays, other.fStandaloneShorterWeekdaysCount); + assignArray(fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, other.fStandaloneNarrowWeekdays, other.fStandaloneNarrowWeekdaysCount); + assignArray(fAmPms, fAmPmsCount, other.fAmPms, other.fAmPmsCount); + assignArray(fWideAmPms, fWideAmPmsCount, other.fWideAmPms, other.fWideAmPmsCount ); + assignArray(fNarrowAmPms, fNarrowAmPmsCount, other.fNarrowAmPms, other.fNarrowAmPmsCount ); + fTimeSeparator.fastCopyFrom(other.fTimeSeparator); // fastCopyFrom() - see assignArray comments + assignArray(fQuarters, fQuartersCount, other.fQuarters, other.fQuartersCount); + assignArray(fShortQuarters, fShortQuartersCount, other.fShortQuarters, other.fShortQuartersCount); + assignArray(fNarrowQuarters, fNarrowQuartersCount, other.fNarrowQuarters, other.fNarrowQuartersCount); + assignArray(fStandaloneQuarters, fStandaloneQuartersCount, other.fStandaloneQuarters, other.fStandaloneQuartersCount); + assignArray(fStandaloneShortQuarters, fStandaloneShortQuartersCount, other.fStandaloneShortQuarters, other.fStandaloneShortQuartersCount); + assignArray(fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount, other.fStandaloneNarrowQuarters, other.fStandaloneNarrowQuartersCount); + assignArray(fWideDayPeriods, fWideDayPeriodsCount, + other.fWideDayPeriods, other.fWideDayPeriodsCount); + assignArray(fNarrowDayPeriods, fNarrowDayPeriodsCount, + other.fNarrowDayPeriods, other.fNarrowDayPeriodsCount); + assignArray(fAbbreviatedDayPeriods, fAbbreviatedDayPeriodsCount, + other.fAbbreviatedDayPeriods, other.fAbbreviatedDayPeriodsCount); + assignArray(fStandaloneWideDayPeriods, fStandaloneWideDayPeriodsCount, + other.fStandaloneWideDayPeriods, other.fStandaloneWideDayPeriodsCount); + assignArray(fStandaloneNarrowDayPeriods, fStandaloneNarrowDayPeriodsCount, + other.fStandaloneNarrowDayPeriods, other.fStandaloneNarrowDayPeriodsCount); + assignArray(fStandaloneAbbreviatedDayPeriods, fStandaloneAbbreviatedDayPeriodsCount, + other.fStandaloneAbbreviatedDayPeriods, other.fStandaloneAbbreviatedDayPeriodsCount); + if (other.fLeapMonthPatterns != nullptr) { + assignArray(fLeapMonthPatterns, fLeapMonthPatternsCount, other.fLeapMonthPatterns, other.fLeapMonthPatternsCount); + } else { + fLeapMonthPatterns = nullptr; + fLeapMonthPatternsCount = 0; + } + if (other.fShortYearNames != nullptr) { + assignArray(fShortYearNames, fShortYearNamesCount, other.fShortYearNames, other.fShortYearNamesCount); + } else { + fShortYearNames = nullptr; + fShortYearNamesCount = 0; + } + if (other.fShortZodiacNames != nullptr) { + assignArray(fShortZodiacNames, fShortZodiacNamesCount, other.fShortZodiacNames, other.fShortZodiacNamesCount); + } else { + fShortZodiacNames = nullptr; + fShortZodiacNamesCount = 0; + } + + if (other.fZoneStrings != nullptr) { + fZoneStringsColCount = other.fZoneStringsColCount; + fZoneStringsRowCount = other.fZoneStringsRowCount; + createZoneStrings((const UnicodeString**)other.fZoneStrings); + + } else { + fZoneStrings = nullptr; + fZoneStringsColCount = 0; + fZoneStringsRowCount = 0; + } + fZSFLocale = other.fZSFLocale; + // Other zone strings data is created on demand + fLocaleZoneStrings = nullptr; + + // fastCopyFrom() - see assignArray comments + fLocalPatternChars.fastCopyFrom(other.fLocalPatternChars); + + uprv_memcpy(fCapitalization, other.fCapitalization, sizeof(fCapitalization)); +} + +/** + * Assignment operator. + */ +DateFormatSymbols& DateFormatSymbols::operator=(const DateFormatSymbols& other) +{ + if (this == &other) { return *this; } // self-assignment: no-op + dispose(); + copyData(other); + + return *this; +} + +DateFormatSymbols::~DateFormatSymbols() +{ + dispose(); +} + +void DateFormatSymbols::dispose() +{ + delete[] fEras; + delete[] fEraNames; + delete[] fNarrowEras; + delete[] fMonths; + delete[] fShortMonths; + delete[] fNarrowMonths; + delete[] fStandaloneMonths; + delete[] fStandaloneShortMonths; + delete[] fStandaloneNarrowMonths; + delete[] fWeekdays; + delete[] fShortWeekdays; + delete[] fShorterWeekdays; + delete[] fNarrowWeekdays; + delete[] fStandaloneWeekdays; + delete[] fStandaloneShortWeekdays; + delete[] fStandaloneShorterWeekdays; + delete[] fStandaloneNarrowWeekdays; + delete[] fAmPms; + delete[] fWideAmPms; + delete[] fNarrowAmPms; + delete[] fQuarters; + delete[] fShortQuarters; + delete[] fNarrowQuarters; + delete[] fStandaloneQuarters; + delete[] fStandaloneShortQuarters; + delete[] fStandaloneNarrowQuarters; + delete[] fLeapMonthPatterns; + delete[] fShortYearNames; + delete[] fShortZodiacNames; + delete[] fAbbreviatedDayPeriods; + delete[] fWideDayPeriods; + delete[] fNarrowDayPeriods; + delete[] fStandaloneAbbreviatedDayPeriods; + delete[] fStandaloneWideDayPeriods; + delete[] fStandaloneNarrowDayPeriods; + + actualLocale = Locale::getRoot(); + validLocale = Locale::getRoot(); + disposeZoneStrings(); +} + +void DateFormatSymbols::disposeZoneStrings() +{ + if (fZoneStrings) { + for (int32_t row = 0; row < fZoneStringsRowCount; ++row) { + delete[] fZoneStrings[row]; + } + uprv_free(fZoneStrings); + } + if (fLocaleZoneStrings) { + for (int32_t row = 0; row < fZoneStringsRowCount; ++row) { + delete[] fLocaleZoneStrings[row]; + } + uprv_free(fLocaleZoneStrings); + } + + fZoneStrings = nullptr; + fLocaleZoneStrings = nullptr; + fZoneStringsRowCount = 0; + fZoneStringsColCount = 0; +} + +UBool +DateFormatSymbols::arrayCompare(const UnicodeString* array1, + const UnicodeString* array2, + int32_t count) +{ + if (array1 == array2) return true; + while (count>0) + { + --count; + if (array1[count] != array2[count]) return false; + } + return true; +} + +bool +DateFormatSymbols::operator==(const DateFormatSymbols& other) const +{ + // First do cheap comparisons + if (this == &other) { + return true; + } + if (fErasCount == other.fErasCount && + fEraNamesCount == other.fEraNamesCount && + fNarrowErasCount == other.fNarrowErasCount && + fMonthsCount == other.fMonthsCount && + fShortMonthsCount == other.fShortMonthsCount && + fNarrowMonthsCount == other.fNarrowMonthsCount && + fStandaloneMonthsCount == other.fStandaloneMonthsCount && + fStandaloneShortMonthsCount == other.fStandaloneShortMonthsCount && + fStandaloneNarrowMonthsCount == other.fStandaloneNarrowMonthsCount && + fWeekdaysCount == other.fWeekdaysCount && + fShortWeekdaysCount == other.fShortWeekdaysCount && + fShorterWeekdaysCount == other.fShorterWeekdaysCount && + fNarrowWeekdaysCount == other.fNarrowWeekdaysCount && + fStandaloneWeekdaysCount == other.fStandaloneWeekdaysCount && + fStandaloneShortWeekdaysCount == other.fStandaloneShortWeekdaysCount && + fStandaloneShorterWeekdaysCount == other.fStandaloneShorterWeekdaysCount && + fStandaloneNarrowWeekdaysCount == other.fStandaloneNarrowWeekdaysCount && + fAmPmsCount == other.fAmPmsCount && + fWideAmPmsCount == other.fWideAmPmsCount && + fNarrowAmPmsCount == other.fNarrowAmPmsCount && + fQuartersCount == other.fQuartersCount && + fShortQuartersCount == other.fShortQuartersCount && + fNarrowQuartersCount == other.fNarrowQuartersCount && + fStandaloneQuartersCount == other.fStandaloneQuartersCount && + fStandaloneShortQuartersCount == other.fStandaloneShortQuartersCount && + fStandaloneNarrowQuartersCount == other.fStandaloneNarrowQuartersCount && + fLeapMonthPatternsCount == other.fLeapMonthPatternsCount && + fShortYearNamesCount == other.fShortYearNamesCount && + fShortZodiacNamesCount == other.fShortZodiacNamesCount && + fAbbreviatedDayPeriodsCount == other.fAbbreviatedDayPeriodsCount && + fWideDayPeriodsCount == other.fWideDayPeriodsCount && + fNarrowDayPeriodsCount == other.fNarrowDayPeriodsCount && + fStandaloneAbbreviatedDayPeriodsCount == other.fStandaloneAbbreviatedDayPeriodsCount && + fStandaloneWideDayPeriodsCount == other.fStandaloneWideDayPeriodsCount && + fStandaloneNarrowDayPeriodsCount == other.fStandaloneNarrowDayPeriodsCount && + (uprv_memcmp(fCapitalization, other.fCapitalization, sizeof(fCapitalization))==0)) + { + // Now compare the arrays themselves + if (arrayCompare(fEras, other.fEras, fErasCount) && + arrayCompare(fEraNames, other.fEraNames, fEraNamesCount) && + arrayCompare(fNarrowEras, other.fNarrowEras, fNarrowErasCount) && + arrayCompare(fMonths, other.fMonths, fMonthsCount) && + arrayCompare(fShortMonths, other.fShortMonths, fShortMonthsCount) && + arrayCompare(fNarrowMonths, other.fNarrowMonths, fNarrowMonthsCount) && + arrayCompare(fStandaloneMonths, other.fStandaloneMonths, fStandaloneMonthsCount) && + arrayCompare(fStandaloneShortMonths, other.fStandaloneShortMonths, fStandaloneShortMonthsCount) && + arrayCompare(fStandaloneNarrowMonths, other.fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount) && + arrayCompare(fWeekdays, other.fWeekdays, fWeekdaysCount) && + arrayCompare(fShortWeekdays, other.fShortWeekdays, fShortWeekdaysCount) && + arrayCompare(fShorterWeekdays, other.fShorterWeekdays, fShorterWeekdaysCount) && + arrayCompare(fNarrowWeekdays, other.fNarrowWeekdays, fNarrowWeekdaysCount) && + arrayCompare(fStandaloneWeekdays, other.fStandaloneWeekdays, fStandaloneWeekdaysCount) && + arrayCompare(fStandaloneShortWeekdays, other.fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount) && + arrayCompare(fStandaloneShorterWeekdays, other.fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount) && + arrayCompare(fStandaloneNarrowWeekdays, other.fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount) && + arrayCompare(fAmPms, other.fAmPms, fAmPmsCount) && + arrayCompare(fWideAmPms, other.fWideAmPms, fWideAmPmsCount) && + arrayCompare(fNarrowAmPms, other.fNarrowAmPms, fNarrowAmPmsCount) && + fTimeSeparator == other.fTimeSeparator && + arrayCompare(fQuarters, other.fQuarters, fQuartersCount) && + arrayCompare(fShortQuarters, other.fShortQuarters, fShortQuartersCount) && + arrayCompare(fNarrowQuarters, other.fNarrowQuarters, fNarrowQuartersCount) && + arrayCompare(fStandaloneQuarters, other.fStandaloneQuarters, fStandaloneQuartersCount) && + arrayCompare(fStandaloneShortQuarters, other.fStandaloneShortQuarters, fStandaloneShortQuartersCount) && + arrayCompare(fStandaloneNarrowQuarters, other.fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount) && + arrayCompare(fLeapMonthPatterns, other.fLeapMonthPatterns, fLeapMonthPatternsCount) && + arrayCompare(fShortYearNames, other.fShortYearNames, fShortYearNamesCount) && + arrayCompare(fShortZodiacNames, other.fShortZodiacNames, fShortZodiacNamesCount) && + arrayCompare(fAbbreviatedDayPeriods, other.fAbbreviatedDayPeriods, fAbbreviatedDayPeriodsCount) && + arrayCompare(fWideDayPeriods, other.fWideDayPeriods, fWideDayPeriodsCount) && + arrayCompare(fNarrowDayPeriods, other.fNarrowDayPeriods, fNarrowDayPeriodsCount) && + arrayCompare(fStandaloneAbbreviatedDayPeriods, other.fStandaloneAbbreviatedDayPeriods, + fStandaloneAbbreviatedDayPeriodsCount) && + arrayCompare(fStandaloneWideDayPeriods, other.fStandaloneWideDayPeriods, + fStandaloneWideDayPeriodsCount) && + arrayCompare(fStandaloneNarrowDayPeriods, other.fStandaloneNarrowDayPeriods, + fStandaloneWideDayPeriodsCount)) + { + // Compare the contents of fZoneStrings + if (fZoneStrings == nullptr && other.fZoneStrings == nullptr) { + if (fZSFLocale == other.fZSFLocale) { + return true; + } + } else if (fZoneStrings != nullptr && other.fZoneStrings != nullptr) { + if (fZoneStringsRowCount == other.fZoneStringsRowCount + && fZoneStringsColCount == other.fZoneStringsColCount) { + bool cmpres = true; + for (int32_t i = 0; (i < fZoneStringsRowCount) && cmpres; i++) { + cmpres = arrayCompare(fZoneStrings[i], other.fZoneStrings[i], fZoneStringsColCount); + } + return cmpres; + } + } + return false; + } + } + return false; +} + +//------------------------------------------------------ + +const UnicodeString* +DateFormatSymbols::getEras(int32_t &count) const +{ + count = fErasCount; + return fEras; +} + +const UnicodeString* +DateFormatSymbols::getEraNames(int32_t &count) const +{ + count = fEraNamesCount; + return fEraNames; +} + +const UnicodeString* +DateFormatSymbols::getNarrowEras(int32_t &count) const +{ + count = fNarrowErasCount; + return fNarrowEras; +} + +const UnicodeString* +DateFormatSymbols::getMonths(int32_t &count) const +{ + count = fMonthsCount; + return fMonths; +} + +const UnicodeString* +DateFormatSymbols::getShortMonths(int32_t &count) const +{ + count = fShortMonthsCount; + return fShortMonths; +} + +const UnicodeString* +DateFormatSymbols::getMonths(int32_t &count, DtContextType context, DtWidthType width ) const +{ + UnicodeString *returnValue = nullptr; + + switch (context) { + case FORMAT : + switch(width) { + case WIDE : + count = fMonthsCount; + returnValue = fMonths; + break; + case ABBREVIATED : + case SHORT : // no month data for this, defaults to ABBREVIATED + count = fShortMonthsCount; + returnValue = fShortMonths; + break; + case NARROW : + count = fNarrowMonthsCount; + returnValue = fNarrowMonths; + break; + case DT_WIDTH_COUNT : + break; + } + break; + case STANDALONE : + switch(width) { + case WIDE : + count = fStandaloneMonthsCount; + returnValue = fStandaloneMonths; + break; + case ABBREVIATED : + case SHORT : // no month data for this, defaults to ABBREVIATED + count = fStandaloneShortMonthsCount; + returnValue = fStandaloneShortMonths; + break; + case NARROW : + count = fStandaloneNarrowMonthsCount; + returnValue = fStandaloneNarrowMonths; + break; + case DT_WIDTH_COUNT : + break; + } + break; + case DT_CONTEXT_COUNT : + break; + } + return returnValue; +} + +const UnicodeString* +DateFormatSymbols::getWeekdays(int32_t &count) const +{ + count = fWeekdaysCount; + return fWeekdays; +} + +const UnicodeString* +DateFormatSymbols::getShortWeekdays(int32_t &count) const +{ + count = fShortWeekdaysCount; + return fShortWeekdays; +} + +const UnicodeString* +DateFormatSymbols::getWeekdays(int32_t &count, DtContextType context, DtWidthType width) const +{ + UnicodeString *returnValue = nullptr; + switch (context) { + case FORMAT : + switch(width) { + case WIDE : + count = fWeekdaysCount; + returnValue = fWeekdays; + break; + case ABBREVIATED : + count = fShortWeekdaysCount; + returnValue = fShortWeekdays; + break; + case SHORT : + count = fShorterWeekdaysCount; + returnValue = fShorterWeekdays; + break; + case NARROW : + count = fNarrowWeekdaysCount; + returnValue = fNarrowWeekdays; + break; + case DT_WIDTH_COUNT : + break; + } + break; + case STANDALONE : + switch(width) { + case WIDE : + count = fStandaloneWeekdaysCount; + returnValue = fStandaloneWeekdays; + break; + case ABBREVIATED : + count = fStandaloneShortWeekdaysCount; + returnValue = fStandaloneShortWeekdays; + break; + case SHORT : + count = fStandaloneShorterWeekdaysCount; + returnValue = fStandaloneShorterWeekdays; + break; + case NARROW : + count = fStandaloneNarrowWeekdaysCount; + returnValue = fStandaloneNarrowWeekdays; + break; + case DT_WIDTH_COUNT : + break; + } + break; + case DT_CONTEXT_COUNT : + break; + } + return returnValue; +} + +const UnicodeString* +DateFormatSymbols::getQuarters(int32_t &count, DtContextType context, DtWidthType width ) const +{ + UnicodeString *returnValue = nullptr; + + switch (context) { + case FORMAT : + switch(width) { + case WIDE : + count = fQuartersCount; + returnValue = fQuarters; + break; + case ABBREVIATED : + case SHORT : // no quarter data for this, defaults to ABBREVIATED + count = fShortQuartersCount; + returnValue = fShortQuarters; + break; + case NARROW : + count = fNarrowQuartersCount; + returnValue = fNarrowQuarters; + break; + case DT_WIDTH_COUNT : + break; + } + break; + case STANDALONE : + switch(width) { + case WIDE : + count = fStandaloneQuartersCount; + returnValue = fStandaloneQuarters; + break; + case ABBREVIATED : + case SHORT : // no quarter data for this, defaults to ABBREVIATED + count = fStandaloneShortQuartersCount; + returnValue = fStandaloneShortQuarters; + break; + case NARROW : + count = fStandaloneNarrowQuartersCount; + returnValue = fStandaloneNarrowQuarters; + break; + case DT_WIDTH_COUNT : + break; + } + break; + case DT_CONTEXT_COUNT : + break; + } + return returnValue; +} + +UnicodeString& +DateFormatSymbols::getTimeSeparatorString(UnicodeString& result) const +{ + // fastCopyFrom() - see assignArray comments + return result.fastCopyFrom(fTimeSeparator); +} + +const UnicodeString* +DateFormatSymbols::getAmPmStrings(int32_t &count) const +{ + return getAmPmStrings(count, FORMAT, ABBREVIATED); +} + +const UnicodeString* +DateFormatSymbols::getAmPmStrings(int32_t &count, DtContextType /*ignored*/, DtWidthType width) const +{ + UnicodeString* const* srcArray; + int32_t const* srcCount; + switch (width) { + case WIDE: + srcArray = &fWideAmPms; + srcCount = &fWideAmPmsCount; + break; + case NARROW: + srcArray = &fNarrowAmPms; + srcCount = &fNarrowAmPmsCount; + break; + case ABBREVIATED: + default: + srcArray = &fAmPms; + srcCount = &fAmPmsCount; + break; + } + + count = *srcCount; + return *srcArray; +} + +const UnicodeString* +DateFormatSymbols::getLeapMonthPatterns(int32_t &count) const +{ + count = fLeapMonthPatternsCount; + return fLeapMonthPatterns; +} + +const UnicodeString* +DateFormatSymbols::getYearNames(int32_t& count, + DtContextType /*ignored*/, DtWidthType /*ignored*/) const +{ + count = fShortYearNamesCount; + return fShortYearNames; +} + +void +DateFormatSymbols::setYearNames(const UnicodeString* yearNames, int32_t count, + DtContextType context, DtWidthType width) +{ + if (context == FORMAT && width == ABBREVIATED) { + delete[] fShortYearNames; + fShortYearNames = newUnicodeStringArray(count); + uprv_arrayCopy(yearNames, fShortYearNames, count); + fShortYearNamesCount = count; + } +} + +const UnicodeString* +DateFormatSymbols::getZodiacNames(int32_t& count, + DtContextType /*ignored*/, DtWidthType /*ignored*/) const +{ + count = fShortZodiacNamesCount; + return fShortZodiacNames; +} + +void +DateFormatSymbols::setZodiacNames(const UnicodeString* zodiacNames, int32_t count, + DtContextType context, DtWidthType width) +{ + if (context == FORMAT && width == ABBREVIATED) { + delete[] fShortZodiacNames; + fShortZodiacNames = newUnicodeStringArray(count); + uprv_arrayCopy(zodiacNames, fShortZodiacNames, count); + fShortZodiacNamesCount = count; + } +} + +//------------------------------------------------------ + +void +DateFormatSymbols::setEras(const UnicodeString* erasArray, int32_t count) +{ + // delete the old list if we own it + delete[] fEras; + + // we always own the new list, which we create here (we duplicate rather + // than adopting the list passed in) + fEras = newUnicodeStringArray(count); + uprv_arrayCopy(erasArray,fEras, count); + fErasCount = count; +} + +void +DateFormatSymbols::setEraNames(const UnicodeString* eraNamesArray, int32_t count) +{ + // delete the old list if we own it + delete[] fEraNames; + + // we always own the new list, which we create here (we duplicate rather + // than adopting the list passed in) + fEraNames = newUnicodeStringArray(count); + uprv_arrayCopy(eraNamesArray,fEraNames, count); + fEraNamesCount = count; +} + +void +DateFormatSymbols::setNarrowEras(const UnicodeString* narrowErasArray, int32_t count) +{ + // delete the old list if we own it + delete[] fNarrowEras; + + // we always own the new list, which we create here (we duplicate rather + // than adopting the list passed in) + fNarrowEras = newUnicodeStringArray(count); + uprv_arrayCopy(narrowErasArray,fNarrowEras, count); + fNarrowErasCount = count; +} + +void +DateFormatSymbols::setMonths(const UnicodeString* monthsArray, int32_t count) +{ + // delete the old list if we own it + delete[] fMonths; + + // we always own the new list, which we create here (we duplicate rather + // than adopting the list passed in) + fMonths = newUnicodeStringArray(count); + uprv_arrayCopy( monthsArray,fMonths,count); + fMonthsCount = count; +} + +void +DateFormatSymbols::setShortMonths(const UnicodeString* shortMonthsArray, int32_t count) +{ + // delete the old list if we own it + delete[] fShortMonths; + + // we always own the new list, which we create here (we duplicate rather + // than adopting the list passed in) + fShortMonths = newUnicodeStringArray(count); + uprv_arrayCopy(shortMonthsArray,fShortMonths, count); + fShortMonthsCount = count; +} + +void +DateFormatSymbols::setMonths(const UnicodeString* monthsArray, int32_t count, DtContextType context, DtWidthType width) +{ + // delete the old list if we own it + // we always own the new list, which we create here (we duplicate rather + // than adopting the list passed in) + + switch (context) { + case FORMAT : + switch (width) { + case WIDE : + delete[] fMonths; + fMonths = newUnicodeStringArray(count); + uprv_arrayCopy( monthsArray,fMonths,count); + fMonthsCount = count; + break; + case ABBREVIATED : + delete[] fShortMonths; + fShortMonths = newUnicodeStringArray(count); + uprv_arrayCopy( monthsArray,fShortMonths,count); + fShortMonthsCount = count; + break; + case NARROW : + delete[] fNarrowMonths; + fNarrowMonths = newUnicodeStringArray(count); + uprv_arrayCopy( monthsArray,fNarrowMonths,count); + fNarrowMonthsCount = count; + break; + default : + break; + } + break; + case STANDALONE : + switch (width) { + case WIDE : + delete[] fStandaloneMonths; + fStandaloneMonths = newUnicodeStringArray(count); + uprv_arrayCopy( monthsArray,fStandaloneMonths,count); + fStandaloneMonthsCount = count; + break; + case ABBREVIATED : + delete[] fStandaloneShortMonths; + fStandaloneShortMonths = newUnicodeStringArray(count); + uprv_arrayCopy( monthsArray,fStandaloneShortMonths,count); + fStandaloneShortMonthsCount = count; + break; + case NARROW : + delete[] fStandaloneNarrowMonths; + fStandaloneNarrowMonths = newUnicodeStringArray(count); + uprv_arrayCopy( monthsArray,fStandaloneNarrowMonths,count); + fStandaloneNarrowMonthsCount = count; + break; + default : + break; + } + break; + case DT_CONTEXT_COUNT : + break; + } +} + +void DateFormatSymbols::setWeekdays(const UnicodeString* weekdaysArray, int32_t count) +{ + // delete the old list if we own it + delete[] fWeekdays; + + // we always own the new list, which we create here (we duplicate rather + // than adopting the list passed in) + fWeekdays = newUnicodeStringArray(count); + uprv_arrayCopy(weekdaysArray,fWeekdays,count); + fWeekdaysCount = count; +} + +void +DateFormatSymbols::setShortWeekdays(const UnicodeString* shortWeekdaysArray, int32_t count) +{ + // delete the old list if we own it + delete[] fShortWeekdays; + + // we always own the new list, which we create here (we duplicate rather + // than adopting the list passed in) + fShortWeekdays = newUnicodeStringArray(count); + uprv_arrayCopy(shortWeekdaysArray, fShortWeekdays, count); + fShortWeekdaysCount = count; +} + +void +DateFormatSymbols::setWeekdays(const UnicodeString* weekdaysArray, int32_t count, DtContextType context, DtWidthType width) +{ + // delete the old list if we own it + // we always own the new list, which we create here (we duplicate rather + // than adopting the list passed in) + + switch (context) { + case FORMAT : + switch (width) { + case WIDE : + delete[] fWeekdays; + fWeekdays = newUnicodeStringArray(count); + uprv_arrayCopy(weekdaysArray, fWeekdays, count); + fWeekdaysCount = count; + break; + case ABBREVIATED : + delete[] fShortWeekdays; + fShortWeekdays = newUnicodeStringArray(count); + uprv_arrayCopy(weekdaysArray, fShortWeekdays, count); + fShortWeekdaysCount = count; + break; + case SHORT : + delete[] fShorterWeekdays; + fShorterWeekdays = newUnicodeStringArray(count); + uprv_arrayCopy(weekdaysArray, fShorterWeekdays, count); + fShorterWeekdaysCount = count; + break; + case NARROW : + delete[] fNarrowWeekdays; + fNarrowWeekdays = newUnicodeStringArray(count); + uprv_arrayCopy(weekdaysArray, fNarrowWeekdays, count); + fNarrowWeekdaysCount = count; + break; + case DT_WIDTH_COUNT : + break; + } + break; + case STANDALONE : + switch (width) { + case WIDE : + delete[] fStandaloneWeekdays; + fStandaloneWeekdays = newUnicodeStringArray(count); + uprv_arrayCopy(weekdaysArray, fStandaloneWeekdays, count); + fStandaloneWeekdaysCount = count; + break; + case ABBREVIATED : + delete[] fStandaloneShortWeekdays; + fStandaloneShortWeekdays = newUnicodeStringArray(count); + uprv_arrayCopy(weekdaysArray, fStandaloneShortWeekdays, count); + fStandaloneShortWeekdaysCount = count; + break; + case SHORT : + delete[] fStandaloneShorterWeekdays; + fStandaloneShorterWeekdays = newUnicodeStringArray(count); + uprv_arrayCopy(weekdaysArray, fStandaloneShorterWeekdays, count); + fStandaloneShorterWeekdaysCount = count; + break; + case NARROW : + delete[] fStandaloneNarrowWeekdays; + fStandaloneNarrowWeekdays = newUnicodeStringArray(count); + uprv_arrayCopy(weekdaysArray, fStandaloneNarrowWeekdays, count); + fStandaloneNarrowWeekdaysCount = count; + break; + case DT_WIDTH_COUNT : + break; + } + break; + case DT_CONTEXT_COUNT : + break; + } +} + +void +DateFormatSymbols::setQuarters(const UnicodeString* quartersArray, int32_t count, DtContextType context, DtWidthType width) +{ + // delete the old list if we own it + // we always own the new list, which we create here (we duplicate rather + // than adopting the list passed in) + + switch (context) { + case FORMAT : + switch (width) { + case WIDE : + delete[] fQuarters; + fQuarters = newUnicodeStringArray(count); + uprv_arrayCopy( quartersArray,fQuarters,count); + fQuartersCount = count; + break; + case ABBREVIATED : + delete[] fShortQuarters; + fShortQuarters = newUnicodeStringArray(count); + uprv_arrayCopy( quartersArray,fShortQuarters,count); + fShortQuartersCount = count; + break; + case NARROW : + delete[] fNarrowQuarters; + fNarrowQuarters = newUnicodeStringArray(count); + uprv_arrayCopy( quartersArray,fNarrowQuarters,count); + fNarrowQuartersCount = count; + break; + default : + break; + } + break; + case STANDALONE : + switch (width) { + case WIDE : + delete[] fStandaloneQuarters; + fStandaloneQuarters = newUnicodeStringArray(count); + uprv_arrayCopy( quartersArray,fStandaloneQuarters,count); + fStandaloneQuartersCount = count; + break; + case ABBREVIATED : + delete[] fStandaloneShortQuarters; + fStandaloneShortQuarters = newUnicodeStringArray(count); + uprv_arrayCopy( quartersArray,fStandaloneShortQuarters,count); + fStandaloneShortQuartersCount = count; + break; + case NARROW : + delete[] fStandaloneNarrowQuarters; + fStandaloneNarrowQuarters = newUnicodeStringArray(count); + uprv_arrayCopy( quartersArray,fStandaloneNarrowQuarters,count); + fStandaloneNarrowQuartersCount = count; + break; + default : + break; + } + break; + case DT_CONTEXT_COUNT : + break; + } +} + +void +DateFormatSymbols::setAmPmStrings(const UnicodeString* amPmsArray, int32_t count) +{ + setAmPmStrings(amPmsArray, count, FORMAT, ABBREVIATED); +} + +void +DateFormatSymbols::setAmPmStrings(const UnicodeString* amPmsArray, int32_t count, DtContextType /*ignored*/, DtWidthType width) +{ + UnicodeString** targetArray; + int32_t* targetCount; + switch (width) { + case WIDE: + targetArray = &fWideAmPms; + targetCount = &fWideAmPmsCount; + break; + case NARROW: + targetArray = &fNarrowAmPms; + targetCount = &fNarrowAmPmsCount; + break; + case ABBREVIATED: + default: + targetArray = &fAmPms; + targetCount = &fAmPmsCount; + break; + } + + // delete the old list if we own it + delete[] *targetArray; + + // we always own the new list, which we create here (we duplicate rather + // than adopting the list passed in) + *targetArray = newUnicodeStringArray(count); + uprv_arrayCopy(amPmsArray,*targetArray,count); + *targetCount = count; +} + +void +DateFormatSymbols::setTimeSeparatorString(const UnicodeString& newTimeSeparator) +{ + fTimeSeparator = newTimeSeparator; +} + +const UnicodeString** +DateFormatSymbols::getZoneStrings(int32_t& rowCount, int32_t& columnCount) const +{ + const UnicodeString **result = nullptr; + static UMutex LOCK; + + umtx_lock(&LOCK); + if (fZoneStrings == nullptr) { + if (fLocaleZoneStrings == nullptr) { + const_cast(this)->initZoneStringsArray(); + } + result = (const UnicodeString**)fLocaleZoneStrings; + } else { + result = (const UnicodeString**)fZoneStrings; + } + rowCount = fZoneStringsRowCount; + columnCount = fZoneStringsColCount; + umtx_unlock(&LOCK); + + return result; +} + +// For now, we include all zones +#define ZONE_SET UCAL_ZONE_TYPE_ANY + +// This code must be called within a synchronized block +void +DateFormatSymbols::initZoneStringsArray() { + if (fZoneStrings != nullptr || fLocaleZoneStrings != nullptr) { + return; + } + + UErrorCode status = U_ZERO_ERROR; + + StringEnumeration *tzids = nullptr; + UnicodeString ** zarray = nullptr; + TimeZoneNames *tzNames = nullptr; + int32_t rows = 0; + + static const UTimeZoneNameType TYPES[] = { + UTZNM_LONG_STANDARD, UTZNM_SHORT_STANDARD, + UTZNM_LONG_DAYLIGHT, UTZNM_SHORT_DAYLIGHT + }; + static const int32_t NUM_TYPES = 4; + + do { // dummy do-while + + tzids = TimeZone::createTimeZoneIDEnumeration(ZONE_SET, nullptr, nullptr, status); + rows = tzids->count(status); + if (U_FAILURE(status)) { + break; + } + + // Allocate array + int32_t size = rows * sizeof(UnicodeString*); + zarray = static_cast(uprv_malloc(size)); + if (zarray == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + break; + } + uprv_memset(zarray, 0, size); + + tzNames = TimeZoneNames::createInstance(fZSFLocale, status); + tzNames->loadAllDisplayNames(status); + if (U_FAILURE(status)) { break; } + + const UnicodeString *tzid; + int32_t i = 0; + UDate now = Calendar::getNow(); + UnicodeString tzDispName; + + while ((tzid = tzids->snext(status)) != nullptr) { + if (U_FAILURE(status)) { + break; + } + + zarray[i] = new UnicodeString[5]; + if (zarray[i] == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + break; + } + + zarray[i][0].setTo(*tzid); + tzNames->getDisplayNames(*tzid, TYPES, NUM_TYPES, now, zarray[i]+1, status); + i++; + } + + } while (false); + + if (U_FAILURE(status)) { + if (zarray) { + for (int32_t i = 0; i < rows; i++) { + if (zarray[i]) { + delete[] zarray[i]; + } + } + uprv_free(zarray); + zarray = nullptr; + } + } + + delete tzNames; + delete tzids; + + fLocaleZoneStrings = zarray; + fZoneStringsRowCount = rows; + fZoneStringsColCount = 1 + NUM_TYPES; +} + +void +DateFormatSymbols::setZoneStrings(const UnicodeString* const *strings, int32_t rowCount, int32_t columnCount) +{ + // since deleting a 2-d array is a pain in the butt, we offload that task to + // a separate function + disposeZoneStrings(); + // we always own the new list, which we create here (we duplicate rather + // than adopting the list passed in) + fZoneStringsRowCount = rowCount; + fZoneStringsColCount = columnCount; + createZoneStrings(const_cast(strings)); +} + +//------------------------------------------------------ + +const char16_t * U_EXPORT2 +DateFormatSymbols::getPatternUChars() +{ + return gPatternChars; +} + +UDateFormatField U_EXPORT2 +DateFormatSymbols::getPatternCharIndex(char16_t c) { + if (c >= UPRV_LENGTHOF(gLookupPatternChars)) { + return UDAT_FIELD_COUNT; + } + const auto idx = gLookupPatternChars[c]; + return idx == -1 ? UDAT_FIELD_COUNT : static_cast(idx); +} + +static const uint64_t kNumericFieldsAlways = + (static_cast(1) << UDAT_YEAR_FIELD) | // y + (static_cast(1) << UDAT_DATE_FIELD) | // d + (static_cast(1) << UDAT_HOUR_OF_DAY1_FIELD) | // k + (static_cast(1) << UDAT_HOUR_OF_DAY0_FIELD) | // H + (static_cast(1) << UDAT_MINUTE_FIELD) | // m + (static_cast(1) << UDAT_SECOND_FIELD) | // s + (static_cast(1) << UDAT_FRACTIONAL_SECOND_FIELD) | // S + (static_cast(1) << UDAT_DAY_OF_YEAR_FIELD) | // D + (static_cast(1) << UDAT_DAY_OF_WEEK_IN_MONTH_FIELD) | // F + (static_cast(1) << UDAT_WEEK_OF_YEAR_FIELD) | // w + (static_cast(1) << UDAT_WEEK_OF_MONTH_FIELD) | // W + (static_cast(1) << UDAT_HOUR1_FIELD) | // h + (static_cast(1) << UDAT_HOUR0_FIELD) | // K + (static_cast(1) << UDAT_YEAR_WOY_FIELD) | // Y + (static_cast(1) << UDAT_EXTENDED_YEAR_FIELD) | // u + (static_cast(1) << UDAT_JULIAN_DAY_FIELD) | // g + (static_cast(1) << UDAT_MILLISECONDS_IN_DAY_FIELD) | // A + (static_cast(1) << UDAT_RELATED_YEAR_FIELD); // r + +static const uint64_t kNumericFieldsForCount12 = + (static_cast(1) << UDAT_MONTH_FIELD) | // M or MM + (static_cast(1) << UDAT_DOW_LOCAL_FIELD) | // e or ee + (static_cast(1) << UDAT_STANDALONE_DAY_FIELD) | // c or cc + (static_cast(1) << UDAT_STANDALONE_MONTH_FIELD) | // L or LL + (static_cast(1) << UDAT_QUARTER_FIELD) | // Q or QQ + (static_cast(1) << UDAT_STANDALONE_QUARTER_FIELD); // q or qq + +UBool U_EXPORT2 +DateFormatSymbols::isNumericField(UDateFormatField f, int32_t count) { + if (f == UDAT_FIELD_COUNT) { + return false; + } + uint64_t flag = static_cast(1) << f; + return ((kNumericFieldsAlways & flag) != 0 || ((kNumericFieldsForCount12 & flag) != 0 && count < 3)); +} + +UBool U_EXPORT2 +DateFormatSymbols::isNumericPatternChar(char16_t c, int32_t count) { + return isNumericField(getPatternCharIndex(c), count); +} + +//------------------------------------------------------ + +UnicodeString& +DateFormatSymbols::getLocalPatternChars(UnicodeString& result) const +{ + // fastCopyFrom() - see assignArray comments + return result.fastCopyFrom(fLocalPatternChars); +} + +//------------------------------------------------------ + +void +DateFormatSymbols::setLocalPatternChars(const UnicodeString& newLocalPatternChars) +{ + fLocalPatternChars = newLocalPatternChars; +} + +//------------------------------------------------------ + +namespace { + +// Constants declarations +const char16_t kCalendarAliasPrefixUChar[] = { + SOLIDUS, CAP_L, CAP_O, CAP_C, CAP_A, CAP_L, CAP_E, SOLIDUS, + LOW_C, LOW_A, LOW_L, LOW_E, LOW_N, LOW_D, LOW_A, LOW_R, SOLIDUS +}; +const char16_t kGregorianTagUChar[] = { + LOW_G, LOW_R, LOW_E, LOW_G, LOW_O, LOW_R, LOW_I, LOW_A, LOW_N +}; +const char16_t kVariantTagUChar[] = { + PERCENT, LOW_V, LOW_A, LOW_R, LOW_I, LOW_A, LOW_N, LOW_T +}; +const char16_t kLeapTagUChar[] = { + LOW_L, LOW_E, LOW_A, LOW_P +}; +const char16_t kCyclicNameSetsTagUChar[] = { + LOW_C, LOW_Y, LOW_C, LOW_L, LOW_I, LOW_C, CAP_N, LOW_A, LOW_M, LOW_E, CAP_S, LOW_E, LOW_T, LOW_S +}; +const char16_t kYearsTagUChar[] = { + SOLIDUS, LOW_Y, LOW_E, LOW_A, LOW_R, LOW_S +}; +const char16_t kZodiacsUChar[] = { + SOLIDUS, LOW_Z, LOW_O, LOW_D, LOW_I, LOW_A, LOW_C, LOW_S +}; +const char16_t kDayPartsTagUChar[] = { + SOLIDUS, LOW_D, LOW_A, LOW_Y, CAP_P, LOW_A, LOW_R, LOW_T, LOW_S +}; +const char16_t kFormatTagUChar[] = { + SOLIDUS, LOW_F, LOW_O, LOW_R, LOW_M, LOW_A, LOW_T +}; +const char16_t kAbbrTagUChar[] = { + SOLIDUS, LOW_A, LOW_B, LOW_B, LOW_R, LOW_E, LOW_V, LOW_I, LOW_A, LOW_T, LOW_E, LOW_D +}; + +// ResourceSink to enumerate all calendar resources +struct CalendarDataSink : public ResourceSink { + + // Enum which specifies the type of alias received, or no alias + enum AliasType { + SAME_CALENDAR, + DIFFERENT_CALENDAR, + GREGORIAN, + NONE + }; + + // Data structures to store resources from the current resource bundle + Hashtable arrays; + Hashtable arraySizes; + Hashtable maps; + /** + * Whenever there are aliases, the same object will be added twice to 'map'. + * To avoid double deletion, 'maps' won't take ownership of the objects. Instead, + * 'mapRefs' will own them and will delete them when CalendarDataSink is deleted. + */ + MemoryPool mapRefs; + + // Paths and the aliases they point to + UVector aliasPathPairs; + + // Current and next calendar resource table which should be loaded + UnicodeString currentCalendarType; + UnicodeString nextCalendarType; + + // Resources to visit when enumerating fallback calendars + LocalPointer resourcesToVisit; + + // Alias' relative path populated whenever an alias is read + UnicodeString aliasRelativePath; + + // Initializes CalendarDataSink with default values + CalendarDataSink(UErrorCode& status) + : arrays(false, status), arraySizes(false, status), maps(false, status), + mapRefs(), + aliasPathPairs(uprv_deleteUObject, uhash_compareUnicodeString, status), + currentCalendarType(), nextCalendarType(), + resourcesToVisit(nullptr), aliasRelativePath() { + if (U_FAILURE(status)) { return; } + } + virtual ~CalendarDataSink(); + + // Configure the CalendarSink to visit all the resources + void visitAllResources() { + resourcesToVisit.adoptInstead(nullptr); + } + + // Actions to be done before enumerating + void preEnumerate(const UnicodeString &calendarType) { + currentCalendarType = calendarType; + nextCalendarType.setToBogus(); + aliasPathPairs.removeAllElements(); + } + + virtual void put(const char *key, ResourceValue &value, UBool, UErrorCode &errorCode) override { + if (U_FAILURE(errorCode)) { return; } + U_ASSERT(!currentCalendarType.isEmpty()); + + // Stores the resources to visit on the next calendar. + LocalPointer resourcesToVisitNext(nullptr); + ResourceTable calendarData = value.getTable(errorCode); + if (U_FAILURE(errorCode)) { return; } + + // Enumerate all resources for this calendar + for (int i = 0; calendarData.getKeyAndValue(i, key, value); i++) { + UnicodeString keyUString(key, -1, US_INV); + + // == Handle aliases == + AliasType aliasType = processAliasFromValue(keyUString, value, errorCode); + if (U_FAILURE(errorCode)) { return; } + if (aliasType == GREGORIAN) { + // Ignore aliases to the gregorian calendar, all of its resources will be loaded anyway. + continue; + + } else if (aliasType == DIFFERENT_CALENDAR) { + // Whenever an alias to the next calendar (except gregorian) is encountered, register the + // calendar type it's pointing to + if (resourcesToVisitNext.isNull()) { + resourcesToVisitNext + .adoptInsteadAndCheckErrorCode(new UVector(uprv_deleteUObject, uhash_compareUnicodeString, errorCode), + errorCode); + if (U_FAILURE(errorCode)) { return; } + } + LocalPointer aliasRelativePathCopy(aliasRelativePath.clone(), errorCode); + resourcesToVisitNext->adoptElement(aliasRelativePathCopy.orphan(), errorCode); + if (U_FAILURE(errorCode)) { return; } + continue; + + } else if (aliasType == SAME_CALENDAR) { + // Register same-calendar alias + if (arrays.get(aliasRelativePath) == nullptr && maps.get(aliasRelativePath) == nullptr) { + LocalPointer aliasRelativePathCopy(aliasRelativePath.clone(), errorCode); + aliasPathPairs.adoptElement(aliasRelativePathCopy.orphan(), errorCode); + if (U_FAILURE(errorCode)) { return; } + LocalPointer keyUStringCopy(keyUString.clone(), errorCode); + aliasPathPairs.adoptElement(keyUStringCopy.orphan(), errorCode); + if (U_FAILURE(errorCode)) { return; } + } + continue; + } + + // Only visit the resources that were referenced by an alias on the previous calendar + // (AmPmMarkersAbbr is an exception). + if (!resourcesToVisit.isNull() && !resourcesToVisit->isEmpty() && !resourcesToVisit->contains(&keyUString) + && uprv_strcmp(key, gAmPmMarkersAbbrTag) != 0) { continue; } + + // == Handle data == + if (uprv_strcmp(key, gAmPmMarkersTag) == 0 + || uprv_strcmp(key, gAmPmMarkersAbbrTag) == 0 + || uprv_strcmp(key, gAmPmMarkersNarrowTag) == 0) { + if (arrays.get(keyUString) == nullptr) { + ResourceArray resourceArray = value.getArray(errorCode); + int32_t arraySize = resourceArray.getSize(); + LocalArray stringArray(new UnicodeString[arraySize], errorCode); + value.getStringArray(stringArray.getAlias(), arraySize, errorCode); + arrays.put(keyUString, stringArray.orphan(), errorCode); + arraySizes.puti(keyUString, arraySize, errorCode); + if (U_FAILURE(errorCode)) { return; } + } + } else if (uprv_strcmp(key, gErasTag) == 0 + || uprv_strcmp(key, gDayNamesTag) == 0 + || uprv_strcmp(key, gMonthNamesTag) == 0 + || uprv_strcmp(key, gQuartersTag) == 0 + || uprv_strcmp(key, gDayPeriodTag) == 0 + || uprv_strcmp(key, gMonthPatternsTag) == 0 + || uprv_strcmp(key, gCyclicNameSetsTag) == 0) { + processResource(keyUString, key, value, errorCode); + } + } + + // Apply same-calendar aliases + UBool modified; + do { + modified = false; + for (int32_t i = 0; i < aliasPathPairs.size();) { + UBool mod = false; + UnicodeString* alias = static_cast(aliasPathPairs[i]); + UnicodeString *aliasArray; + Hashtable *aliasMap; + if ((aliasArray = static_cast(arrays.get(*alias))) != nullptr) { + UnicodeString* path = static_cast(aliasPathPairs[i + 1]); + if (arrays.get(*path) == nullptr) { + // Clone the array + int32_t aliasArraySize = arraySizes.geti(*alias); + LocalArray aliasArrayCopy(new UnicodeString[aliasArraySize], errorCode); + if (U_FAILURE(errorCode)) { return; } + uprv_arrayCopy(aliasArray, aliasArrayCopy.getAlias(), aliasArraySize); + // Put the array on the 'arrays' map + arrays.put(*path, aliasArrayCopy.orphan(), errorCode); + arraySizes.puti(*path, aliasArraySize, errorCode); + } + if (U_FAILURE(errorCode)) { return; } + mod = true; + } else if ((aliasMap = static_cast(maps.get(*alias))) != nullptr) { + UnicodeString* path = static_cast(aliasPathPairs[i + 1]); + if (maps.get(*path) == nullptr) { + maps.put(*path, aliasMap, errorCode); + } + if (U_FAILURE(errorCode)) { return; } + mod = true; + } + if (mod) { + aliasPathPairs.removeElementAt(i + 1); + aliasPathPairs.removeElementAt(i); + modified = true; + } else { + i += 2; + } + } + } while (modified && !aliasPathPairs.isEmpty()); + + // Set the resources to visit on the next calendar + if (!resourcesToVisitNext.isNull()) { + resourcesToVisit = std::move(resourcesToVisitNext); + } + } + + // Process the nested resource bundle tables + void processResource(UnicodeString &path, const char *key, ResourceValue &value, UErrorCode &errorCode) { + if (U_FAILURE(errorCode)) return; + + ResourceTable table = value.getTable(errorCode); + if (U_FAILURE(errorCode)) return; + Hashtable* stringMap = nullptr; + + // Iterate over all the elements of the table and add them to the map + for (int i = 0; table.getKeyAndValue(i, key, value); i++) { + UnicodeString keyUString(key, -1, US_INV); + + // Ignore '%variant' keys + if (keyUString.endsWith(kVariantTagUChar, UPRV_LENGTHOF(kVariantTagUChar))) { + continue; + } + + // == Handle String elements == + if (value.getType() == URES_STRING) { + // We are on a leaf, store the map elements into the stringMap + if (i == 0) { + // mapRefs will keep ownership of 'stringMap': + stringMap = mapRefs.create(false, errorCode); + if (stringMap == nullptr) { + errorCode = U_MEMORY_ALLOCATION_ERROR; + return; + } + maps.put(path, stringMap, errorCode); + if (U_FAILURE(errorCode)) { return; } + stringMap->setValueDeleter(uprv_deleteUObject); + } + U_ASSERT(stringMap != nullptr); + int32_t valueStringSize; + const char16_t *valueString = value.getString(valueStringSize, errorCode); + if (U_FAILURE(errorCode)) { return; } + LocalPointer valueUString(new UnicodeString(true, valueString, valueStringSize), errorCode); + stringMap->put(keyUString, valueUString.orphan(), errorCode); + if (U_FAILURE(errorCode)) { return; } + continue; + } + U_ASSERT(stringMap == nullptr); + + // Store the current path's length and append the current key to the path. + int32_t pathLength = path.length(); + path.append(SOLIDUS).append(keyUString); + + // In cyclicNameSets ignore everything but years/format/abbreviated + // and zodiacs/format/abbreviated + if (path.startsWith(kCyclicNameSetsTagUChar, UPRV_LENGTHOF(kCyclicNameSetsTagUChar))) { + UBool skip = true; + int32_t startIndex = UPRV_LENGTHOF(kCyclicNameSetsTagUChar); + int32_t length = 0; + if (startIndex == path.length() + || path.compare(startIndex, (length = UPRV_LENGTHOF(kZodiacsUChar)), kZodiacsUChar, 0, UPRV_LENGTHOF(kZodiacsUChar)) == 0 + || path.compare(startIndex, (length = UPRV_LENGTHOF(kYearsTagUChar)), kYearsTagUChar, 0, UPRV_LENGTHOF(kYearsTagUChar)) == 0 + || path.compare(startIndex, (length = UPRV_LENGTHOF(kDayPartsTagUChar)), kDayPartsTagUChar, 0, UPRV_LENGTHOF(kDayPartsTagUChar)) == 0) { + startIndex += length; + length = 0; + if (startIndex == path.length() + || path.compare(startIndex, (length = UPRV_LENGTHOF(kFormatTagUChar)), kFormatTagUChar, 0, UPRV_LENGTHOF(kFormatTagUChar)) == 0) { + startIndex += length; + length = 0; + if (startIndex == path.length() + || path.compare(startIndex, (length = UPRV_LENGTHOF(kAbbrTagUChar)), kAbbrTagUChar, 0, UPRV_LENGTHOF(kAbbrTagUChar)) == 0) { + skip = false; + } + } + } + if (skip) { + // Drop the latest key on the path and continue + path.retainBetween(0, pathLength); + continue; + } + } + + // == Handle aliases == + if (arrays.get(path) != nullptr || maps.get(path) != nullptr) { + // Drop the latest key on the path and continue + path.retainBetween(0, pathLength); + continue; + } + + AliasType aliasType = processAliasFromValue(path, value, errorCode); + if (U_FAILURE(errorCode)) { return; } + if (aliasType == SAME_CALENDAR) { + // Store the alias path and the current path on aliasPathPairs + LocalPointer aliasRelativePathCopy(aliasRelativePath.clone(), errorCode); + aliasPathPairs.adoptElement(aliasRelativePathCopy.orphan(), errorCode); + if (U_FAILURE(errorCode)) { return; } + LocalPointer pathCopy(path.clone(), errorCode); + aliasPathPairs.adoptElement(pathCopy.orphan(), errorCode); + if (U_FAILURE(errorCode)) { return; } + + // Drop the latest key on the path and continue + path.retainBetween(0, pathLength); + continue; + } + U_ASSERT(aliasType == NONE); + + // == Handle data == + if (value.getType() == URES_ARRAY) { + // We are on a leaf, store the array + ResourceArray rDataArray = value.getArray(errorCode); + int32_t dataArraySize = rDataArray.getSize(); + LocalArray dataArray(new UnicodeString[dataArraySize], errorCode); + value.getStringArray(dataArray.getAlias(), dataArraySize, errorCode); + arrays.put(path, dataArray.orphan(), errorCode); + arraySizes.puti(path, dataArraySize, errorCode); + if (U_FAILURE(errorCode)) { return; } + } else if (value.getType() == URES_TABLE) { + // We are not on a leaf, recursively process the subtable. + processResource(path, key, value, errorCode); + if (U_FAILURE(errorCode)) { return; } + } + + // Drop the latest key on the path + path.retainBetween(0, pathLength); + } + } + + // Populates an AliasIdentifier with the alias information contained on the UResource.Value. + AliasType processAliasFromValue(UnicodeString ¤tRelativePath, ResourceValue &value, + UErrorCode &errorCode) { + if (U_FAILURE(errorCode)) { return NONE; } + + if (value.getType() == URES_ALIAS) { + int32_t aliasPathSize; + const char16_t* aliasPathUChar = value.getAliasString(aliasPathSize, errorCode); + if (U_FAILURE(errorCode)) { return NONE; } + UnicodeString aliasPath(aliasPathUChar, aliasPathSize); + const int32_t aliasPrefixLength = UPRV_LENGTHOF(kCalendarAliasPrefixUChar); + if (aliasPath.startsWith(kCalendarAliasPrefixUChar, aliasPrefixLength) + && aliasPath.length() > aliasPrefixLength) { + int32_t typeLimit = aliasPath.indexOf(SOLIDUS, aliasPrefixLength); + if (typeLimit > aliasPrefixLength) { + const UnicodeString aliasCalendarType = + aliasPath.tempSubStringBetween(aliasPrefixLength, typeLimit); + aliasRelativePath.setTo(aliasPath, typeLimit + 1, aliasPath.length()); + + if (currentCalendarType == aliasCalendarType + && currentRelativePath != aliasRelativePath) { + // If we have an alias to the same calendar, the path to the resource must be different + return SAME_CALENDAR; + + } else if (currentCalendarType != aliasCalendarType + && currentRelativePath == aliasRelativePath) { + // If we have an alias to a different calendar, the path to the resource must be the same + if (aliasCalendarType.compare(kGregorianTagUChar, UPRV_LENGTHOF(kGregorianTagUChar)) == 0) { + return GREGORIAN; + } else if (nextCalendarType.isBogus()) { + nextCalendarType = aliasCalendarType; + return DIFFERENT_CALENDAR; + } else if (nextCalendarType == aliasCalendarType) { + return DIFFERENT_CALENDAR; + } + } + } + } + errorCode = U_INTERNAL_PROGRAM_ERROR; + return NONE; + } + return NONE; + } + + // Deleter function to be used by 'arrays' + static void U_CALLCONV deleteUnicodeStringArray(void *uArray) { + delete[] static_cast(uArray); + } +}; +// Virtual destructors have to be defined out of line +CalendarDataSink::~CalendarDataSink() { + arrays.setValueDeleter(deleteUnicodeStringArray); +} +} + +//------------------------------------------------------ + +static void +initField(UnicodeString **field, int32_t& length, const char16_t *data, LastResortSize numStr, LastResortSize strLen, UErrorCode &status) { + if (U_SUCCESS(status)) { + length = numStr; + *field = newUnicodeStringArray(static_cast(numStr)); + if (*field) { + for(int32_t i = 0; isetTo(true, data + (i * (static_cast(strLen))), -1); + } + } + else { + length = 0; + status = U_MEMORY_ALLOCATION_ERROR; + } + } +} + +static void +initField(UnicodeString **field, int32_t& length, CalendarDataSink &sink, CharString &key, UErrorCode &status) { + if (U_SUCCESS(status)) { + UnicodeString keyUString(key.data(), -1, US_INV); + UnicodeString* array = static_cast(sink.arrays.get(keyUString)); + + if (array != nullptr) { + length = sink.arraySizes.geti(keyUString); + *field = array; + // DateFormatSymbols takes ownership of the array: + sink.arrays.remove(keyUString); + } else { + length = 0; + status = U_MISSING_RESOURCE_ERROR; + } + } +} + +static void +initField(UnicodeString **field, int32_t& length, CalendarDataSink &sink, CharString &key, int32_t arrayOffset, UErrorCode &status) { + if (U_SUCCESS(status)) { + UnicodeString keyUString(key.data(), -1, US_INV); + UnicodeString* array = static_cast(sink.arrays.get(keyUString)); + + if (array != nullptr) { + int32_t arrayLength = sink.arraySizes.geti(keyUString); + length = arrayLength + arrayOffset; + *field = new UnicodeString[length]; + if (*field == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } + uprv_arrayCopy(array, 0, *field, arrayOffset, arrayLength); + } else { + length = 0; + status = U_MISSING_RESOURCE_ERROR; + } + } +} + +static void +initEras(UnicodeString **field, int32_t& length, CalendarDataSink &sink, CharString &key, const UResourceBundle *ctebPtr, const char* eraWidth, int32_t maxEra, UErrorCode &status) { + if (U_SUCCESS(status)) { + length = 0; + UnicodeString keyUString(key.data(), -1, US_INV); + Hashtable *eraNamesTable = static_cast(sink.maps.get(keyUString)); + + if (eraNamesTable != nullptr) { + UErrorCode resStatus = U_ZERO_ERROR; + LocalUResourceBundlePointer ctewb(ures_getByKeyWithFallback(ctebPtr, eraWidth, nullptr, &resStatus)); + const UResourceBundle *ctewbPtr = (U_SUCCESS(resStatus))? ctewb.getAlias() : nullptr; + *field = new UnicodeString[maxEra + 1]; + if (*field == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } + length = maxEra + 1; + for (int32_t eraCode = 0; eraCode <= maxEra; eraCode++) { + char eraCodeStr[12]; // T_CString_integerToString is documented to generate at most 12 bytes including nul terminator + int32_t eraCodeStrLen = T_CString_integerToString(eraCodeStr, eraCode, 10); + UnicodeString eraCodeKey = UnicodeString(eraCodeStr, eraCodeStrLen, US_INV); + UnicodeString *eraName = static_cast(eraNamesTable->get(eraCodeKey)); + (*field)[eraCode].remove(); + if (eraName != nullptr) { + // Get eraName from map (created by CalendarSink) + (*field)[eraCode].fastCopyFrom(*eraName); + } else if (ctewbPtr != nullptr) { + // Try filling in missing items from parent locale(s) + resStatus = U_ZERO_ERROR; + LocalUResourceBundlePointer ctewkb(ures_getByKeyWithFallback(ctewbPtr, eraCodeStr, nullptr, &resStatus)); + if (U_SUCCESS(resStatus)) { + int32_t eraNameLen; + const UChar* eraNamePtr = ures_getString(ctewkb.getAlias(), &eraNameLen, &resStatus); + if (U_SUCCESS(resStatus)) { + (*field)[eraCode].setTo(false, eraNamePtr, eraNameLen); + } + } + } + } + return; + } + status = U_MISSING_RESOURCE_ERROR; + } +} + +static void +initLeapMonthPattern(UnicodeString *field, int32_t index, CalendarDataSink &sink, CharString &path, UErrorCode &status) { + field[index].remove(); + if (U_SUCCESS(status)) { + UnicodeString pathUString(path.data(), -1, US_INV); + Hashtable *leapMonthTable = static_cast(sink.maps.get(pathUString)); + if (leapMonthTable != nullptr) { + UnicodeString leapLabel(false, kLeapTagUChar, UPRV_LENGTHOF(kLeapTagUChar)); + UnicodeString *leapMonthPattern = static_cast(leapMonthTable->get(leapLabel)); + if (leapMonthPattern != nullptr) { + field[index].fastCopyFrom(*leapMonthPattern); + } else { + field[index].setToBogus(); + } + return; + } + status = U_MISSING_RESOURCE_ERROR; + } +} + +static CharString +&buildResourcePath(CharString &path, const char* segment1, UErrorCode &errorCode) { + return path.clear().append(segment1, -1, errorCode); +} + +static CharString +&buildResourcePath(CharString &path, const char* segment1, const char* segment2, + UErrorCode &errorCode) { + return buildResourcePath(path, segment1, errorCode).append('/', errorCode) + .append(segment2, -1, errorCode); +} + +static CharString +&buildResourcePath(CharString &path, const char* segment1, const char* segment2, + const char* segment3, UErrorCode &errorCode) { + return buildResourcePath(path, segment1, segment2, errorCode).append('/', errorCode) + .append(segment3, -1, errorCode); +} + +static CharString +&buildResourcePath(CharString &path, const char* segment1, const char* segment2, + const char* segment3, const char* segment4, UErrorCode &errorCode) { + return buildResourcePath(path, segment1, segment2, segment3, errorCode).append('/', errorCode) + .append(segment4, -1, errorCode); +} + +typedef struct { + const char * usageTypeName; + DateFormatSymbols::ECapitalizationContextUsageType usageTypeEnumValue; +} ContextUsageTypeNameToEnumValue; + +static const ContextUsageTypeNameToEnumValue contextUsageTypeMap[] = { + // Entries must be sorted by usageTypeName; entry with nullptr name terminates list. + { "day-format-except-narrow", DateFormatSymbols::kCapContextUsageDayFormat }, + { "day-narrow", DateFormatSymbols::kCapContextUsageDayNarrow }, + { "day-standalone-except-narrow", DateFormatSymbols::kCapContextUsageDayStandalone }, + { "era-abbr", DateFormatSymbols::kCapContextUsageEraAbbrev }, + { "era-name", DateFormatSymbols::kCapContextUsageEraWide }, + { "era-narrow", DateFormatSymbols::kCapContextUsageEraNarrow }, + { "metazone-long", DateFormatSymbols::kCapContextUsageMetazoneLong }, + { "metazone-short", DateFormatSymbols::kCapContextUsageMetazoneShort }, + { "month-format-except-narrow", DateFormatSymbols::kCapContextUsageMonthFormat }, + { "month-narrow", DateFormatSymbols::kCapContextUsageMonthNarrow }, + { "month-standalone-except-narrow", DateFormatSymbols::kCapContextUsageMonthStandalone }, + { "zone-long", DateFormatSymbols::kCapContextUsageZoneLong }, + { "zone-short", DateFormatSymbols::kCapContextUsageZoneShort }, + { nullptr, static_cast(0) }, +}; + +// Resource keys to look up localized strings for day periods. +// The first one must be midnight and the second must be noon, so that their indices coincide +// with the am/pm field. Formatting and parsing code for day periods relies on this coincidence. +static const char *dayPeriodKeys[] = {"midnight", "noon", + "morning1", "afternoon1", "evening1", "night1", + "morning2", "afternoon2", "evening2", "night2"}; + +UnicodeString* loadDayPeriodStrings(CalendarDataSink &sink, CharString &path, + int32_t &stringCount, UErrorCode &status) { + if (U_FAILURE(status)) { return nullptr; } + + UnicodeString pathUString(path.data(), -1, US_INV); + Hashtable* map = static_cast(sink.maps.get(pathUString)); + + stringCount = UPRV_LENGTHOF(dayPeriodKeys); + UnicodeString *strings = new UnicodeString[stringCount]; + if (strings == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } + + if (map != nullptr) { + for (int32_t i = 0; i < stringCount; ++i) { + UnicodeString dayPeriodKey(dayPeriodKeys[i], -1, US_INV); + UnicodeString *dayPeriod = static_cast(map->get(dayPeriodKey)); + if (dayPeriod != nullptr) { + strings[i].fastCopyFrom(*dayPeriod); + } else { + strings[i].setToBogus(); + } + } + } else { + for (int32_t i = 0; i < stringCount; i++) { + strings[i].setToBogus(); + } + } + return strings; +} + + +void +DateFormatSymbols::initializeData(const Locale& locale, const char *type, UErrorCode& status, UBool useLastResortData) +{ + int32_t len = 0; + /* In case something goes wrong, initialize all of the data to nullptr. */ + fEras = nullptr; + fErasCount = 0; + fEraNames = nullptr; + fEraNamesCount = 0; + fNarrowEras = nullptr; + fNarrowErasCount = 0; + fMonths = nullptr; + fMonthsCount=0; + fShortMonths = nullptr; + fShortMonthsCount=0; + fNarrowMonths = nullptr; + fNarrowMonthsCount=0; + fStandaloneMonths = nullptr; + fStandaloneMonthsCount=0; + fStandaloneShortMonths = nullptr; + fStandaloneShortMonthsCount=0; + fStandaloneNarrowMonths = nullptr; + fStandaloneNarrowMonthsCount=0; + fWeekdays = nullptr; + fWeekdaysCount=0; + fShortWeekdays = nullptr; + fShortWeekdaysCount=0; + fShorterWeekdays = nullptr; + fShorterWeekdaysCount=0; + fNarrowWeekdays = nullptr; + fNarrowWeekdaysCount=0; + fStandaloneWeekdays = nullptr; + fStandaloneWeekdaysCount=0; + fStandaloneShortWeekdays = nullptr; + fStandaloneShortWeekdaysCount=0; + fStandaloneShorterWeekdays = nullptr; + fStandaloneShorterWeekdaysCount=0; + fStandaloneNarrowWeekdays = nullptr; + fStandaloneNarrowWeekdaysCount=0; + fAmPms = nullptr; + fAmPmsCount=0; + fWideAmPms = nullptr; + fWideAmPmsCount=0; + fNarrowAmPms = nullptr; + fNarrowAmPmsCount=0; + fTimeSeparator.setToBogus(); + fQuarters = nullptr; + fQuartersCount = 0; + fShortQuarters = nullptr; + fShortQuartersCount = 0; + fNarrowQuarters = nullptr; + fNarrowQuartersCount = 0; + fStandaloneQuarters = nullptr; + fStandaloneQuartersCount = 0; + fStandaloneShortQuarters = nullptr; + fStandaloneShortQuartersCount = 0; + fStandaloneNarrowQuarters = nullptr; + fStandaloneNarrowQuartersCount = 0; + fLeapMonthPatterns = nullptr; + fLeapMonthPatternsCount = 0; + fShortYearNames = nullptr; + fShortYearNamesCount = 0; + fShortZodiacNames = nullptr; + fShortZodiacNamesCount = 0; + fZoneStringsRowCount = 0; + fZoneStringsColCount = 0; + fZoneStrings = nullptr; + fLocaleZoneStrings = nullptr; + fAbbreviatedDayPeriods = nullptr; + fAbbreviatedDayPeriodsCount = 0; + fWideDayPeriods = nullptr; + fWideDayPeriodsCount = 0; + fNarrowDayPeriods = nullptr; + fNarrowDayPeriodsCount = 0; + fStandaloneAbbreviatedDayPeriods = nullptr; + fStandaloneAbbreviatedDayPeriodsCount = 0; + fStandaloneWideDayPeriods = nullptr; + fStandaloneWideDayPeriodsCount = 0; + fStandaloneNarrowDayPeriods = nullptr; + fStandaloneNarrowDayPeriodsCount = 0; + uprv_memset(fCapitalization, 0, sizeof(fCapitalization)); + + // We need to preserve the requested locale for + // lazy ZoneStringFormat instantiation. ZoneStringFormat + // is region sensitive, thus, bundle locale bundle's locale + // is not sufficient. + fZSFLocale = locale; + + if (U_FAILURE(status)) return; + + // Create a CalendarDataSink to process this data and the resource bundles + CalendarDataSink calendarSink(status); + LocalUResourceBundlePointer rb(ures_open(nullptr, locale.getBaseName(), &status)); + LocalUResourceBundlePointer cb(ures_getByKey(rb.getAlias(), gCalendarTag, nullptr, &status)); + + if (U_FAILURE(status)) return; + + // Iterate over the resource bundle data following the fallbacks through different calendar types + UnicodeString calendarType((type != nullptr && *type != '\0')? type : gGregorianTag, -1, US_INV); + while (!calendarType.isBogus()) { + CharString calendarTypeBuffer; + calendarTypeBuffer.appendInvariantChars(calendarType, status); + if (U_FAILURE(status)) { return; } + const char *calendarTypeCArray = calendarTypeBuffer.data(); + + // Enumerate this calendar type. If the calendar is not found fallback to gregorian + UErrorCode oldStatus = status; + LocalUResourceBundlePointer ctb(ures_getByKeyWithFallback(cb.getAlias(), calendarTypeCArray, nullptr, &status)); + if (status == U_MISSING_RESOURCE_ERROR) { + if (uprv_strcmp(calendarTypeCArray, gGregorianTag) != 0) { + calendarType.setTo(false, kGregorianTagUChar, UPRV_LENGTHOF(kGregorianTagUChar)); + calendarSink.visitAllResources(); + status = oldStatus; + continue; + } + return; + } + + calendarSink.preEnumerate(calendarType); + ures_getAllItemsWithFallback(ctb.getAlias(), "", calendarSink, status); + if (U_FAILURE(status)) break; + + // Stop loading when gregorian was loaded + if (uprv_strcmp(calendarTypeCArray, gGregorianTag) == 0) { + break; + } + + // Get the next calendar type to process from the sink + calendarType = calendarSink.nextCalendarType; + + // Gregorian is always the last fallback + if (calendarType.isBogus()) { + calendarType.setTo(false, kGregorianTagUChar, UPRV_LENGTHOF(kGregorianTagUChar)); + calendarSink.visitAllResources(); + } + } + + // CharString object to build paths + CharString path; + + // Load Leap Month Patterns + UErrorCode tempStatus = status; + fLeapMonthPatterns = newUnicodeStringArray(kMonthPatternsCount); + if (fLeapMonthPatterns) { + initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternFormatWide, calendarSink, + buildResourcePath(path, gMonthPatternsTag, gNamesFormatTag, gNamesWideTag, tempStatus), tempStatus); + initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternFormatAbbrev, calendarSink, + buildResourcePath(path, gMonthPatternsTag, gNamesFormatTag, gNamesAbbrTag, tempStatus), tempStatus); + initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternFormatNarrow, calendarSink, + buildResourcePath(path, gMonthPatternsTag, gNamesFormatTag, gNamesNarrowTag, tempStatus), tempStatus); + initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternStandaloneWide, calendarSink, + buildResourcePath(path, gMonthPatternsTag, gNamesStandaloneTag, gNamesWideTag, tempStatus), tempStatus); + initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternStandaloneAbbrev, calendarSink, + buildResourcePath(path, gMonthPatternsTag, gNamesStandaloneTag, gNamesAbbrTag, tempStatus), tempStatus); + initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternStandaloneNarrow, calendarSink, + buildResourcePath(path, gMonthPatternsTag, gNamesStandaloneTag, gNamesNarrowTag, tempStatus), tempStatus); + initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternNumeric, calendarSink, + buildResourcePath(path, gMonthPatternsTag, gNamesNumericTag, gNamesAllTag, tempStatus), tempStatus); + if (U_SUCCESS(tempStatus)) { + // Hack to fix bad C inheritance for dangi monthPatterns (OK in J); this should be handled by aliases in root, but isn't. + // The ordering of the following statements is important. + if (fLeapMonthPatterns[kLeapMonthPatternFormatAbbrev].isEmpty()) { + fLeapMonthPatterns[kLeapMonthPatternFormatAbbrev].setTo(fLeapMonthPatterns[kLeapMonthPatternFormatWide]); + } + if (fLeapMonthPatterns[kLeapMonthPatternFormatNarrow].isEmpty()) { + fLeapMonthPatterns[kLeapMonthPatternFormatNarrow].setTo(fLeapMonthPatterns[kLeapMonthPatternStandaloneNarrow]); + } + if (fLeapMonthPatterns[kLeapMonthPatternStandaloneWide].isEmpty()) { + fLeapMonthPatterns[kLeapMonthPatternStandaloneWide].setTo(fLeapMonthPatterns[kLeapMonthPatternFormatWide]); + } + if (fLeapMonthPatterns[kLeapMonthPatternStandaloneAbbrev].isEmpty()) { + fLeapMonthPatterns[kLeapMonthPatternStandaloneAbbrev].setTo(fLeapMonthPatterns[kLeapMonthPatternFormatAbbrev]); + } + // end of hack + fLeapMonthPatternsCount = kMonthPatternsCount; + } else { + delete[] fLeapMonthPatterns; + fLeapMonthPatterns = nullptr; + } + } + + // Load cyclic names sets + tempStatus = status; + initField(&fShortYearNames, fShortYearNamesCount, calendarSink, + buildResourcePath(path, gCyclicNameSetsTag, gNameSetYearsTag, gNamesFormatTag, gNamesAbbrTag, tempStatus), tempStatus); + initField(&fShortZodiacNames, fShortZodiacNamesCount, calendarSink, + buildResourcePath(path, gCyclicNameSetsTag, gNameSetZodiacsTag, gNamesFormatTag, gNamesAbbrTag, tempStatus), tempStatus); + + // Load context transforms and capitalization + tempStatus = U_ZERO_ERROR; + LocalUResourceBundlePointer localeBundle(ures_open(nullptr, locale.getName(), &tempStatus)); + if (U_SUCCESS(tempStatus)) { + LocalUResourceBundlePointer contextTransforms(ures_getByKeyWithFallback(localeBundle.getAlias(), gContextTransformsTag, nullptr, &tempStatus)); + if (U_SUCCESS(tempStatus)) { + for (LocalUResourceBundlePointer contextTransformUsage; + contextTransformUsage.adoptInstead(ures_getNextResource(contextTransforms.getAlias(), nullptr, &tempStatus)), + contextTransformUsage.isValid();) { + const int32_t * intVector = ures_getIntVector(contextTransformUsage.getAlias(), &len, &status); + if (U_SUCCESS(tempStatus) && intVector != nullptr && len >= 2) { + const char* usageType = ures_getKey(contextTransformUsage.getAlias()); + if (usageType != nullptr) { + const ContextUsageTypeNameToEnumValue * typeMapPtr = contextUsageTypeMap; + int32_t compResult = 0; + // linear search; list is short and we cannot be sure that bsearch is available + while ( typeMapPtr->usageTypeName != nullptr && (compResult = uprv_strcmp(usageType, typeMapPtr->usageTypeName)) > 0 ) { + ++typeMapPtr; + } + if (typeMapPtr->usageTypeName != nullptr && compResult == 0) { + fCapitalization[typeMapPtr->usageTypeEnumValue][0] = static_cast(intVector[0]); + fCapitalization[typeMapPtr->usageTypeEnumValue][1] = static_cast(intVector[1]); + } + } + } + tempStatus = U_ZERO_ERROR; + } + } + + tempStatus = U_ZERO_ERROR; + const LocalPointer numberingSystem( + NumberingSystem::createInstance(locale, tempStatus), tempStatus); + if (U_SUCCESS(tempStatus)) { + // These functions all fail gracefully if passed nullptr pointers and + // do nothing unless U_SUCCESS(tempStatus), so it's only necessary + // to check for errors once after all calls are made. + const LocalUResourceBundlePointer numberElementsData(ures_getByKeyWithFallback( + localeBundle.getAlias(), gNumberElementsTag, nullptr, &tempStatus)); + const LocalUResourceBundlePointer nsNameData(ures_getByKeyWithFallback( + numberElementsData.getAlias(), numberingSystem->getName(), nullptr, &tempStatus)); + const LocalUResourceBundlePointer symbolsData(ures_getByKeyWithFallback( + nsNameData.getAlias(), gSymbolsTag, nullptr, &tempStatus)); + fTimeSeparator = ures_getUnicodeStringByKey( + symbolsData.getAlias(), gTimeSeparatorTag, &tempStatus); + if (U_FAILURE(tempStatus)) { + fTimeSeparator.setToBogus(); + } + } + + } + + if (fTimeSeparator.isBogus()) { + fTimeSeparator.setTo(DateFormatSymbols::DEFAULT_TIME_SEPARATOR); + } + + // Load day periods + fAbbreviatedDayPeriods = loadDayPeriodStrings(calendarSink, + buildResourcePath(path, gDayPeriodTag, gNamesFormatTag, gNamesAbbrTag, status), + fAbbreviatedDayPeriodsCount, status); + + fWideDayPeriods = loadDayPeriodStrings(calendarSink, + buildResourcePath(path, gDayPeriodTag, gNamesFormatTag, gNamesWideTag, status), + fWideDayPeriodsCount, status); + fNarrowDayPeriods = loadDayPeriodStrings(calendarSink, + buildResourcePath(path, gDayPeriodTag, gNamesFormatTag, gNamesNarrowTag, status), + fNarrowDayPeriodsCount, status); + + fStandaloneAbbreviatedDayPeriods = loadDayPeriodStrings(calendarSink, + buildResourcePath(path, gDayPeriodTag, gNamesStandaloneTag, gNamesAbbrTag, status), + fStandaloneAbbreviatedDayPeriodsCount, status); + + fStandaloneWideDayPeriods = loadDayPeriodStrings(calendarSink, + buildResourcePath(path, gDayPeriodTag, gNamesStandaloneTag, gNamesWideTag, status), + fStandaloneWideDayPeriodsCount, status); + fStandaloneNarrowDayPeriods = loadDayPeriodStrings(calendarSink, + buildResourcePath(path, gDayPeriodTag, gNamesStandaloneTag, gNamesNarrowTag, status), + fStandaloneNarrowDayPeriodsCount, status); + + // Fill in for missing/bogus items (dayPeriods are a map so single items might be missing) + if (U_SUCCESS(status)) { + for (int32_t dpidx = 0; dpidx < fAbbreviatedDayPeriodsCount; ++dpidx) { + if (dpidx < fWideDayPeriodsCount && fWideDayPeriods != nullptr && fWideDayPeriods[dpidx].isBogus()) { + fWideDayPeriods[dpidx].fastCopyFrom(fAbbreviatedDayPeriods[dpidx]); + } + if (dpidx < fNarrowDayPeriodsCount && fNarrowDayPeriods != nullptr && fNarrowDayPeriods[dpidx].isBogus()) { + fNarrowDayPeriods[dpidx].fastCopyFrom(fAbbreviatedDayPeriods[dpidx]); + } + if (dpidx < fStandaloneAbbreviatedDayPeriodsCount && fStandaloneAbbreviatedDayPeriods != nullptr && fStandaloneAbbreviatedDayPeriods[dpidx].isBogus()) { + fStandaloneAbbreviatedDayPeriods[dpidx].fastCopyFrom(fAbbreviatedDayPeriods[dpidx]); + } + if (dpidx < fStandaloneWideDayPeriodsCount && fStandaloneWideDayPeriods != nullptr && fStandaloneWideDayPeriods[dpidx].isBogus()) { + fStandaloneWideDayPeriods[dpidx].fastCopyFrom(fStandaloneAbbreviatedDayPeriods[dpidx]); + } + if (dpidx < fStandaloneNarrowDayPeriodsCount && fStandaloneNarrowDayPeriods != nullptr && fStandaloneNarrowDayPeriods[dpidx].isBogus()) { + fStandaloneNarrowDayPeriods[dpidx].fastCopyFrom(fStandaloneAbbreviatedDayPeriods[dpidx]); + } + } + } + + // if we make it to here, the resource data is cool, and we can get everything out + // of it that we need except for the time-zone and localized-pattern data, which + // are stored in a separate file + validLocale = Locale(ures_getLocaleByType(cb.getAlias(), ULOC_VALID_LOCALE, &status)); + actualLocale = Locale(ures_getLocaleByType(cb.getAlias(), ULOC_ACTUAL_LOCALE, &status)); + + // Era setup + if (type == nullptr) { + type = "gregorian"; + } + LocalPointer eraRules(EraRules::createInstance(type, false, status)); + int32_t maxEra = (U_SUCCESS(status))? eraRules->getMaxEraCode(): 0; + UErrorCode resStatus = U_ZERO_ERROR; + LocalUResourceBundlePointer ctpb(ures_getByKeyWithFallback(cb.getAlias(), type, nullptr, &resStatus)); + LocalUResourceBundlePointer cteb(ures_getByKeyWithFallback(ctpb.getAlias(), gErasTag, nullptr, &resStatus)); + const UResourceBundle *ctebPtr = (U_SUCCESS(resStatus))? cteb.getAlias() : nullptr; + // Load eras + initEras(&fEras, fErasCount, calendarSink, buildResourcePath(path, gErasTag, gNamesAbbrTag, status), + ctebPtr, gNamesAbbrTag, maxEra, status); + UErrorCode oldStatus = status; + initEras(&fEraNames, fEraNamesCount, calendarSink, buildResourcePath(path, gErasTag, gNamesWideTag, status), + ctebPtr, gNamesWideTag, maxEra, status); + if (status == U_MISSING_RESOURCE_ERROR) { // Workaround because eras/wide was omitted from CLDR 1.3 + status = U_ZERO_ERROR; + assignArray(fEraNames, fEraNamesCount, fEras, fErasCount); + } + // current ICU4J falls back to abbreviated if narrow eras are missing, so we will too + oldStatus = status; + initEras(&fNarrowEras, fNarrowErasCount, calendarSink, buildResourcePath(path, gErasTag, gNamesNarrowTag, status), + ctebPtr, gNamesNarrowTag, maxEra, status); + if (status == U_MISSING_RESOURCE_ERROR) { // Workaround because eras/wide was omitted from CLDR 1.3 + status = U_ZERO_ERROR; + assignArray(fNarrowEras, fNarrowErasCount, fEras, fErasCount); + } + + // Load month names + initField(&fMonths, fMonthsCount, calendarSink, + buildResourcePath(path, gMonthNamesTag, gNamesFormatTag, gNamesWideTag, status), status); + initField(&fShortMonths, fShortMonthsCount, calendarSink, + buildResourcePath(path, gMonthNamesTag, gNamesFormatTag, gNamesAbbrTag, status), status); + initField(&fStandaloneMonths, fStandaloneMonthsCount, calendarSink, + buildResourcePath(path, gMonthNamesTag, gNamesStandaloneTag, gNamesWideTag, status), status); + if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/wide not available, use format/wide */ + status = U_ZERO_ERROR; + assignArray(fStandaloneMonths, fStandaloneMonthsCount, fMonths, fMonthsCount); + } + initField(&fStandaloneShortMonths, fStandaloneShortMonthsCount, calendarSink, + buildResourcePath(path, gMonthNamesTag, gNamesStandaloneTag, gNamesAbbrTag, status), status); + if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/abbreviated not available, use format/abbreviated */ + status = U_ZERO_ERROR; + assignArray(fStandaloneShortMonths, fStandaloneShortMonthsCount, fShortMonths, fShortMonthsCount); + } + + UErrorCode narrowMonthsEC = status; + UErrorCode standaloneNarrowMonthsEC = status; + initField(&fNarrowMonths, fNarrowMonthsCount, calendarSink, + buildResourcePath(path, gMonthNamesTag, gNamesFormatTag, gNamesNarrowTag, narrowMonthsEC), narrowMonthsEC); + initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, calendarSink, + buildResourcePath(path, gMonthNamesTag, gNamesStandaloneTag, gNamesNarrowTag, narrowMonthsEC), standaloneNarrowMonthsEC); + if (narrowMonthsEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowMonthsEC != U_MISSING_RESOURCE_ERROR) { + // If format/narrow not available, use standalone/narrow + assignArray(fNarrowMonths, fNarrowMonthsCount, fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount); + } else if (narrowMonthsEC != U_MISSING_RESOURCE_ERROR && standaloneNarrowMonthsEC == U_MISSING_RESOURCE_ERROR) { + // If standalone/narrow not available, use format/narrow + assignArray(fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, fNarrowMonths, fNarrowMonthsCount); + } else if (narrowMonthsEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowMonthsEC == U_MISSING_RESOURCE_ERROR) { + // If neither is available, use format/abbreviated + assignArray(fNarrowMonths, fNarrowMonthsCount, fShortMonths, fShortMonthsCount); + assignArray(fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, fShortMonths, fShortMonthsCount); + } + + // Load AM/PM markers. + ErrorCode ampmStatus; + initField(&fAmPms, fAmPmsCount, calendarSink, + buildResourcePath(path, gAmPmMarkersAbbrTag, ampmStatus), ampmStatus); + if (ampmStatus.isFailure()) { + // No-op: fall back to last-resort names, which are pre-populated + } + ampmStatus.reset(); + initField(&fNarrowAmPms, fNarrowAmPmsCount, calendarSink, + buildResourcePath(path, gAmPmMarkersNarrowTag, ampmStatus), ampmStatus); + if (ampmStatus.isFailure()) { + // Narrow falls back to Abbreviated + assignArray(fNarrowAmPms, fNarrowAmPmsCount, fAmPms, fAmPmsCount); + } + ampmStatus.reset(); + initField(&fWideAmPms, fWideAmPmsCount, calendarSink, + buildResourcePath(path, gAmPmMarkersTag, ampmStatus), ampmStatus); + if (ampmStatus.isFailure()) { + // Wide falls back to Abbreviated + assignArray(fWideAmPms, fWideAmPmsCount, fAmPms, fAmPmsCount); + } + ampmStatus.reset(); + + // Load quarters + initField(&fQuarters, fQuartersCount, calendarSink, + buildResourcePath(path, gQuartersTag, gNamesFormatTag, gNamesWideTag, status), status); + initField(&fShortQuarters, fShortQuartersCount, calendarSink, + buildResourcePath(path, gQuartersTag, gNamesFormatTag, gNamesAbbrTag, status), status); + if(status == U_MISSING_RESOURCE_ERROR) { + status = U_ZERO_ERROR; + assignArray(fShortQuarters, fShortQuartersCount, fQuarters, fQuartersCount); + } + + initField(&fStandaloneQuarters, fStandaloneQuartersCount, calendarSink, + buildResourcePath(path, gQuartersTag, gNamesStandaloneTag, gNamesWideTag, status), status); + if(status == U_MISSING_RESOURCE_ERROR) { + status = U_ZERO_ERROR; + assignArray(fStandaloneQuarters, fStandaloneQuartersCount, fQuarters, fQuartersCount); + } + initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, calendarSink, + buildResourcePath(path, gQuartersTag, gNamesStandaloneTag, gNamesAbbrTag, status), status); + if(status == U_MISSING_RESOURCE_ERROR) { + status = U_ZERO_ERROR; + assignArray(fStandaloneShortQuarters, fStandaloneShortQuartersCount, fShortQuarters, fShortQuartersCount); + } + + // unlike the fields above, narrow format quarters fall back on narrow standalone quarters + initField(&fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount, calendarSink, + buildResourcePath(path, gQuartersTag, gNamesStandaloneTag, gNamesNarrowTag, status), status); + initField(&fNarrowQuarters, fNarrowQuartersCount, calendarSink, + buildResourcePath(path, gQuartersTag, gNamesFormatTag, gNamesNarrowTag, status), status); + if(status == U_MISSING_RESOURCE_ERROR) { + status = U_ZERO_ERROR; + assignArray(fNarrowQuarters, fNarrowQuartersCount, fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount); + } + + // ICU 3.8 or later version no longer uses localized date-time pattern characters by default (ticket#5597) + /* + // fastCopyFrom()/setTo() - see assignArray comments + resStr = ures_getStringByKey(fResourceBundle, gLocalPatternCharsTag, &len, &status); + fLocalPatternChars.setTo(true, resStr, len); + // If the locale data does not include new pattern chars, use the defaults + // TODO: Consider making this an error, since this may add conflicting characters. + if (len < PATTERN_CHARS_LEN) { + fLocalPatternChars.append(UnicodeString(true, &gPatternChars[len], PATTERN_CHARS_LEN-len)); + } + */ + fLocalPatternChars.setTo(true, gPatternChars, PATTERN_CHARS_LEN); + + // Format wide weekdays -> fWeekdays + // {sfb} fixed to handle 1-based weekdays + initField(&fWeekdays, fWeekdaysCount, calendarSink, + buildResourcePath(path, gDayNamesTag, gNamesFormatTag, gNamesWideTag, status), 1, status); + + // Format abbreviated weekdays -> fShortWeekdays + initField(&fShortWeekdays, fShortWeekdaysCount, calendarSink, + buildResourcePath(path, gDayNamesTag, gNamesFormatTag, gNamesAbbrTag, status), 1, status); + + // Format short weekdays -> fShorterWeekdays (fall back to abbreviated) + initField(&fShorterWeekdays, fShorterWeekdaysCount, calendarSink, + buildResourcePath(path, gDayNamesTag, gNamesFormatTag, gNamesShortTag, status), 1, status); + if (status == U_MISSING_RESOURCE_ERROR) { + status = U_ZERO_ERROR; + assignArray(fShorterWeekdays, fShorterWeekdaysCount, fShortWeekdays, fShortWeekdaysCount); + } + + // Stand-alone wide weekdays -> fStandaloneWeekdays + initField(&fStandaloneWeekdays, fStandaloneWeekdaysCount, calendarSink, + buildResourcePath(path, gDayNamesTag, gNamesStandaloneTag, gNamesWideTag, status), 1, status); + if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/wide is not available, use format/wide */ + status = U_ZERO_ERROR; + assignArray(fStandaloneWeekdays, fStandaloneWeekdaysCount, fWeekdays, fWeekdaysCount); + } + + // Stand-alone abbreviated weekdays -> fStandaloneShortWeekdays + initField(&fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, calendarSink, + buildResourcePath(path, gDayNamesTag, gNamesStandaloneTag, gNamesAbbrTag, status), 1, status); + if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/abbreviated is not available, use format/abbreviated */ + status = U_ZERO_ERROR; + assignArray(fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, fShortWeekdays, fShortWeekdaysCount); + } + + // Stand-alone short weekdays -> fStandaloneShorterWeekdays (fall back to format abbreviated) + initField(&fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount, calendarSink, + buildResourcePath(path, gDayNamesTag, gNamesStandaloneTag, gNamesShortTag, status), 1, status); + if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/short is not available, use format/short */ + status = U_ZERO_ERROR; + assignArray(fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount, fShorterWeekdays, fShorterWeekdaysCount); + } + + // Format narrow weekdays -> fNarrowWeekdays + UErrorCode narrowWeeksEC = status; + initField(&fNarrowWeekdays, fNarrowWeekdaysCount, calendarSink, + buildResourcePath(path, gDayNamesTag, gNamesFormatTag, gNamesNarrowTag, status), 1, narrowWeeksEC); + // Stand-alone narrow weekdays -> fStandaloneNarrowWeekdays + UErrorCode standaloneNarrowWeeksEC = status; + initField(&fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, calendarSink, + buildResourcePath(path, gDayNamesTag, gNamesStandaloneTag, gNamesNarrowTag, status), 1, standaloneNarrowWeeksEC); + + if (narrowWeeksEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowWeeksEC != U_MISSING_RESOURCE_ERROR) { + // If format/narrow not available, use standalone/narrow + assignArray(fNarrowWeekdays, fNarrowWeekdaysCount, fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount); + } else if (narrowWeeksEC != U_MISSING_RESOURCE_ERROR && standaloneNarrowWeeksEC == U_MISSING_RESOURCE_ERROR) { + // If standalone/narrow not available, use format/narrow + assignArray(fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, fNarrowWeekdays, fNarrowWeekdaysCount); + } else if (narrowWeeksEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowWeeksEC == U_MISSING_RESOURCE_ERROR ) { + // If neither is available, use format/abbreviated + assignArray(fNarrowWeekdays, fNarrowWeekdaysCount, fShortWeekdays, fShortWeekdaysCount); + assignArray(fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, fShortWeekdays, fShortWeekdaysCount); + } + + // Last resort fallback in case previous data wasn't loaded + if (U_FAILURE(status)) + { + if (useLastResortData) + { + // Handle the case in which there is no resource data present. + // We don't have to generate usable patterns in this situation; + // we just need to produce something that will be semi-intelligible + // in most locales. + + status = U_USING_FALLBACK_WARNING; + //TODO(fabalbon): make sure we are storing las resort data for all fields in here. + initField(&fEras, fErasCount, reinterpret_cast(gLastResortEras), kEraNum, kEraLen, status); + initField(&fEraNames, fEraNamesCount, reinterpret_cast(gLastResortEras), kEraNum, kEraLen, status); + initField(&fNarrowEras, fNarrowErasCount, reinterpret_cast(gLastResortEras), kEraNum, kEraLen, status); + initField(&fMonths, fMonthsCount, reinterpret_cast(gLastResortMonthNames), kMonthNum, kMonthLen, status); + initField(&fShortMonths, fShortMonthsCount, reinterpret_cast(gLastResortMonthNames), kMonthNum, kMonthLen, status); + initField(&fNarrowMonths, fNarrowMonthsCount, reinterpret_cast(gLastResortMonthNames), kMonthNum, kMonthLen, status); + initField(&fStandaloneMonths, fStandaloneMonthsCount, reinterpret_cast(gLastResortMonthNames), kMonthNum, kMonthLen, status); + initField(&fStandaloneShortMonths, fStandaloneShortMonthsCount, reinterpret_cast(gLastResortMonthNames), kMonthNum, kMonthLen, status); + initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, reinterpret_cast(gLastResortMonthNames), kMonthNum, kMonthLen, status); + initField(&fWeekdays, fWeekdaysCount, reinterpret_cast(gLastResortDayNames), kDayNum, kDayLen, status); + initField(&fShortWeekdays, fShortWeekdaysCount, reinterpret_cast(gLastResortDayNames), kDayNum, kDayLen, status); + initField(&fShorterWeekdays, fShorterWeekdaysCount, reinterpret_cast(gLastResortDayNames), kDayNum, kDayLen, status); + initField(&fNarrowWeekdays, fNarrowWeekdaysCount, reinterpret_cast(gLastResortDayNames), kDayNum, kDayLen, status); + initField(&fStandaloneWeekdays, fStandaloneWeekdaysCount, reinterpret_cast(gLastResortDayNames), kDayNum, kDayLen, status); + initField(&fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, reinterpret_cast(gLastResortDayNames), kDayNum, kDayLen, status); + initField(&fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount, reinterpret_cast(gLastResortDayNames), kDayNum, kDayLen, status); + initField(&fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, reinterpret_cast(gLastResortDayNames), kDayNum, kDayLen, status); + initField(&fAmPms, fAmPmsCount, reinterpret_cast(gLastResortAmPmMarkers), kAmPmNum, kAmPmLen, status); + initField(&fNarrowAmPms, fNarrowAmPmsCount, reinterpret_cast(gLastResortAmPmMarkers), kAmPmNum, kAmPmLen, status); + initField(&fQuarters, fQuartersCount, reinterpret_cast(gLastResortQuarters), kQuarterNum, kQuarterLen, status); + initField(&fShortQuarters, fShortQuartersCount, reinterpret_cast(gLastResortQuarters), kQuarterNum, kQuarterLen, status); + initField(&fNarrowQuarters, fNarrowQuartersCount, reinterpret_cast(gLastResortQuarters), kQuarterNum, kQuarterLen, status); + initField(&fStandaloneQuarters, fStandaloneQuartersCount, reinterpret_cast(gLastResortQuarters), kQuarterNum, kQuarterLen, status); + initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, reinterpret_cast(gLastResortQuarters), kQuarterNum, kQuarterLen, status); + initField(&fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount, reinterpret_cast(gLastResortQuarters), kQuarterNum, kQuarterLen, status); + fLocalPatternChars.setTo(true, gPatternChars, PATTERN_CHARS_LEN); + } + } +} + +Locale +DateFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) const { + return LocaleBased::getLocale(validLocale, actualLocale, type, status); +} + +U_NAMESPACE_END + +#endif /* #if !UCONFIG_NO_FORMATTING */ + +//eof diff --git a/tools/lint-md/package-lock.json b/tools/lint-md/package-lock.json index 9f4539b0837e..1ab4268328b2 100644 --- a/tools/lint-md/package-lock.json +++ b/tools/lint-md/package-lock.json @@ -326,9 +326,9 @@ } }, "node_modules/js-yaml": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", - "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", "funding": [ { "type": "github", diff --git a/tools/mk-ca-bundle.pl b/tools/mk-ca-bundle.pl index 4057c808bc60..6763ac52bf20 100755 --- a/tools/mk-ca-bundle.pl +++ b/tools/mk-ca-bundle.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl -w +#!/usr/bin/env perl # *************************************************************************** # * _ _ ____ _ # * Project ___| | | | _ \| | @@ -6,11 +6,11 @@ # * | (__| |_| | _ <| |___ # * \___|\___/|_| \_\_____| # * -# * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. +# * Copyright (C) Daniel Stenberg, , et al. # * # * This software is licensed as described in the file COPYING, which # * you should have received as part of this distribution. The terms -# * are also available at http://curl.haxx.se/docs/copyright.html. +# * are also available at https://curl.se/docs/copyright.html. # * # * You may opt to use, copy, modify, merge, publish, distribute and/or sell # * copies of the Software, and permit persons to whom the Software is @@ -19,6 +19,8 @@ # * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # * KIND, either express or implied. # * +# * SPDX-License-Identifier: curl +# * # *************************************************************************** # This Perl script creates a fresh ca-bundle.crt file for use with libcurl. # It downloads certdata.txt from Mozilla's source tree (see URL below), @@ -34,156 +36,165 @@ use Getopt::Std; use MIME::Base64; use strict; -use vars qw($opt_h $opt_i $opt_l $opt_p $opt_q $opt_s $opt_t $opt_v $opt_w); +use warnings; +use vars qw($opt_h $opt_i $opt_l $opt_m $opt_p $opt_q $opt_s $opt_t $opt_v $opt_w); use List::Util; use Text::Wrap; # If the OpenSSL commandline is not in search path you can configure it here! my $openssl = 'openssl'; -my $version = '1.25'; +my $version = '1.33'; $opt_w = 72; # default base64 encoded lines length -# default cert types to include in the output (default is to include CAs which may issue SSL server certs) +# default cert types to include in the output (default is to include CAs which +# may issue SSL server certs) my $default_mozilla_trust_purposes = "SERVER_AUTH"; my $default_mozilla_trust_levels = "TRUSTED_DELEGATOR"; $opt_p = $default_mozilla_trust_purposes . ":" . $default_mozilla_trust_levels; my @valid_mozilla_trust_purposes = ( - "DIGITAL_SIGNATURE", - "NON_REPUDIATION", - "KEY_ENCIPHERMENT", - "DATA_ENCIPHERMENT", - "KEY_AGREEMENT", - "KEY_CERT_SIGN", - "CRL_SIGN", - "SERVER_AUTH", - "CLIENT_AUTH", - "CODE_SIGNING", - "EMAIL_PROTECTION", - "IPSEC_END_SYSTEM", - "IPSEC_TUNNEL", - "IPSEC_USER", - "TIME_STAMPING", - "STEP_UP_APPROVED" + "DIGITAL_SIGNATURE", + "NON_REPUDIATION", + "KEY_ENCIPHERMENT", + "DATA_ENCIPHERMENT", + "KEY_AGREEMENT", + "KEY_CERT_SIGN", + "CRL_SIGN", + "SERVER_AUTH", + "CLIENT_AUTH", + "CODE_SIGNING", + "EMAIL_PROTECTION", + "IPSEC_END_SYSTEM", + "IPSEC_TUNNEL", + "IPSEC_USER", + "TIME_STAMPING", + "STEP_UP_APPROVED" ); my @valid_mozilla_trust_levels = ( - "TRUSTED_DELEGATOR", # CAs - "NOT_TRUSTED", # Don't trust these certs. - "MUST_VERIFY_TRUST", # This explicitly tells us that it ISN'T a CA but is otherwise ok. In other words, this should tell the app to ignore any other sources that claim this is a CA. - "TRUSTED" # This cert is trusted, but only for itself and not for delegates (i.e. it is not a CA). + "TRUSTED_DELEGATOR", # CAs + "NOT_TRUSTED", # Do not trust these certs. + "MUST_VERIFY_TRUST", # This explicitly tells us that it IS NOT a CA but is + # otherwise ok. In other words, this should tell the + # app to ignore any other sources that claim this is + # a CA. + "TRUSTED" # This cert is trusted, but only for itself and not + # for delegates (i.e. it is not a CA). ); -my $default_signature_algorithms = $opt_s = "MD5"; +my $default_signature_algorithms = $opt_s = "SHA256"; my @valid_signature_algorithms = ( - "MD5", - "SHA1", - "SHA256", - "SHA384", - "SHA512" + "SHA256", + "SHA384", + "SHA512" ); $0 =~ s@.*(/|\\)@@; $Getopt::Std::STANDARD_HELP_VERSION = 1; -getopts('bd:fhilnp:qs:tuvw:'); - -if ($opt_i) { - print ("=" x 78 . "\n"); - print "Script Version : $version\n"; - print "Perl Version : $]\n"; - print "Operating System Name : $^O\n"; - print "Getopt::Std.pm Version : ${Getopt::Std::VERSION}\n"; - print "MIME::Base64.pm Version : ${MIME::Base64::VERSION}\n"; - print ("=" x 78 . "\n"); +getopts('hilmp:qs:tvw:'); + +if($opt_i) { + print ("=" x 78 . "\n"); + print "Script Version : $version\n"; + print "Perl Version : $]\n"; + print "Operating System Name : $^O\n"; + print "Getopt::Std.pm Version : ${Getopt::Std::VERSION}\n"; + print "MIME::Base64.pm Version : ${MIME::Base64::VERSION}\n"; + print ("=" x 78 . "\n"); } sub HELP_MESSAGE() { - print "Usage:\t${0} [-i] [-l] [-p] [-q] [-s] [-t] [-v] [-w] []\n"; - print "\t-i\tprint version info about used modules\n"; - print "\t-l\tprint license info about certdata.txt\n"; - print wrap("\t","\t\t", "-p\tlist of Mozilla trust purposes and levels for certificates to include in output. Takes the form of a comma separated list of purposes, a colon, and a comma separated list of levels. (default: $default_mozilla_trust_purposes:$default_mozilla_trust_levels)"), "\n"; - print "\t\t Valid purposes are:\n"; - print wrap("\t\t ","\t\t ", join( ", ", "ALL", @valid_mozilla_trust_purposes ) ), "\n"; - print "\t\t Valid levels are:\n"; - print wrap("\t\t ","\t\t ", join( ", ", "ALL", @valid_mozilla_trust_levels ) ), "\n"; - print "\t-q\tbe really quiet (no progress output at all)\n"; - print wrap("\t","\t\t", "-s\tcomma separated list of certificate signatures/hashes to output in plain text mode. (default: $default_signature_algorithms)\n"); - print "\t\t Valid signature algorithms are:\n"; - print wrap("\t\t ","\t\t ", join( ", ", "ALL", @valid_signature_algorithms ) ), "\n"; - print "\t-t\tinclude plain text listing of certificates\n"; - print "\t-v\tbe verbose and print out processed CAs\n"; - print "\t-w \twrap base64 output lines after chars (default: ${opt_w})\n"; - exit; + print "Usage:\t${0} [-i] [-l] [-m] [-p] [-q] [-s] [-t] [-v] [-w] []\n"; + print "\t-i\tprint version info about used modules\n"; + print "\t-l\tprint license info about certdata.txt\n"; + print "\t-m\tinclude meta data in output\n"; + print wrap("\t","\t\t", "-p\tlist of Mozilla trust purposes and levels for certificates to include in output. " . + "Takes the form of a comma separated list of purposes, a colon, and a comma separated list of levels. " . + "(default: $default_mozilla_trust_purposes:$default_mozilla_trust_levels)"), "\n"; + print "\t\t Valid purposes are:\n"; + print wrap("\t\t ","\t\t ", join(", ", "ALL", @valid_mozilla_trust_purposes)), "\n"; + print "\t\t Valid levels are:\n"; + print wrap("\t\t ","\t\t ", join(", ", "ALL", @valid_mozilla_trust_levels)), "\n"; + print "\t-q\tbe really quiet (no progress output at all)\n"; + print wrap("\t","\t\t", "-s\tcomma separated list of certificate signatures/hashes to output in plain text mode. (default: $default_signature_algorithms)\n"); + print "\t\t Valid signature algorithms are:\n"; + print wrap("\t\t ","\t\t ", join(", ", "ALL", @valid_signature_algorithms)), "\n"; + print "\t-t\tinclude plain text listing of certificates\n"; + print "\t-v\tbe verbose and print out processed CAs\n"; + print "\t-w \twrap base64 output lines after chars (default: ${opt_w})\n"; + exit; } sub VERSION_MESSAGE() { - print "${0} version ${version} running Perl ${]} on ${^O}\n"; + print "${0} version ${version} running Perl ${]} on ${^O}\n"; } -HELP_MESSAGE() if ($opt_h); +HELP_MESSAGE() if($opt_h); sub report($@) { - my $output = shift; + my $output = shift; - print STDERR $output . "\n" unless $opt_q; + print STDERR $output . "\n" unless $opt_q; } sub is_in_list($@) { - my $target = shift; + my $target = shift; - return defined(List::Util::first { $target eq $_ } @_); + return defined(List::Util::first { $target eq $_ } @_); } -# Parses $param_string as a case insensitive comma separated list with optional whitespace -# validates that only allowed parameters are supplied +# Parses $param_string as a case insensitive comma separated list with optional +# whitespace validates that only allowed parameters are supplied sub parse_csv_param($$@) { - my $description = shift; - my $param_string = shift; - my @valid_values = @_; - - my @values = map { - s/^\s+//; # strip leading spaces - s/\s+$//; # strip trailing spaces - uc $_ # return the modified string as upper case - } split( ',', $param_string ); - - # Find all values which are not in the list of valid values or "ALL" - my @invalid = grep { !is_in_list($_,"ALL",@valid_values) } @values; - - if ( scalar(@invalid) > 0 ) { - # Tell the user which parameters were invalid and print the standard help message which will exit - print "Error: Invalid ", $description, scalar(@invalid) == 1 ? ": " : "s: ", join( ", ", map { "\"$_\"" } @invalid ), "\n"; - HELP_MESSAGE(); - } + my $description = shift; + my $param_string = shift; + my @valid_values = @_; + + my @values = map { + s/^\s+//; # strip leading spaces + s/\s+$//; # strip trailing spaces + uc $_ # return the modified string as upper case + } split(',', $param_string); + + # Find all values which are not in the list of valid values or "ALL" + my @invalid = grep { !is_in_list($_, "ALL", @valid_values) } @values; + + if(scalar(@invalid) > 0) { + # Tell the user which parameters were invalid and print the standard help + # message which also exits + print "Error: Invalid ", $description, scalar(@invalid) == 1 ? ": " : "s: ", join(", ", map { "\"$_\"" } @invalid), "\n"; + HELP_MESSAGE(); + } - @values = @valid_values if ( is_in_list("ALL",@values) ); + @values = @valid_values if(is_in_list("ALL", @values)); - return @values; + return @values; } -if ( $opt_p !~ m/:/ ) { - print "Error: Mozilla trust identifier list must include both purposes and levels\n"; - HELP_MESSAGE(); +if($opt_p !~ m/:/) { + print "Error: Mozilla trust identifier list must include both purposes and levels\n"; + HELP_MESSAGE(); } -(my $included_mozilla_trust_purposes_string, my $included_mozilla_trust_levels_string) = split( ':', $opt_p ); -my @included_mozilla_trust_purposes = parse_csv_param( "trust purpose", $included_mozilla_trust_purposes_string, @valid_mozilla_trust_purposes ); -my @included_mozilla_trust_levels = parse_csv_param( "trust level", $included_mozilla_trust_levels_string, @valid_mozilla_trust_levels ); +(my $included_mozilla_trust_purposes_string, my $included_mozilla_trust_levels_string) = split(':', $opt_p); +my @included_mozilla_trust_purposes = parse_csv_param("trust purpose", $included_mozilla_trust_purposes_string, @valid_mozilla_trust_purposes); +my @included_mozilla_trust_levels = parse_csv_param("trust level", $included_mozilla_trust_levels_string, @valid_mozilla_trust_levels); -my @included_signature_algorithms = parse_csv_param( "signature algorithm", $opt_s, @valid_signature_algorithms ); +my @included_signature_algorithms = parse_csv_param("signature algorithm", $opt_s, @valid_signature_algorithms); sub should_output_cert(%) { - my %trust_purposes_by_level = @_; + my %trust_purposes_by_level = @_; - foreach my $level (@included_mozilla_trust_levels) { - # for each level we want to output, see if any of our desired purposes are included - return 1 if ( defined( List::Util::first { is_in_list( $_, @included_mozilla_trust_purposes ) } @{$trust_purposes_by_level{$level}} ) ); - } + foreach my $level (@included_mozilla_trust_levels) { + # for each level we want to output, see if any of our desired purposes are + # included + return 1 if(defined(List::Util::first { is_in_list($_, @included_mozilla_trust_purposes) } @{$trust_purposes_by_level{$level}})); + } - return 0; + return 0; } my $crt = $ARGV[0] || dirname(__FILE__) . '/../src/node_root_certs.h'; @@ -191,132 +202,242 @@ (%) my $stdout = $crt eq '-'; -if( $stdout ) { - open(CRT, '> -') or die "Couldn't open STDOUT: $!\n"; +if($stdout) { + open(CRT, '> -') or die "Could not open STDOUT: $!\n"; } else { - open(CRT,">$crt.~") or die "Couldn't open $crt.~: $!\n"; + open(CRT, ">", "$crt.~") or die "Could not open $crt.~: $!\n"; } my $caname; my $certnum = 0; my $skipnum = 0; my $start_of_cert = 0; - -open(TXT,"$txt") or die "Couldn't open $txt: $!\n"; +my $main_block = 0; +my $main_block_name; +my $trust_block = 0; +my $trust_block_name; +my @precert; +my $cka_value; +my $valid = 0; + +open(TXT, $txt) or die "Could not open $txt: $!\n"; print CRT "#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS\n"; -while () { - if (/\*\*\*\*\* BEGIN LICENSE BLOCK \*\*\*\*\*/) { - print CRT; - print if ($opt_l); - while () { - print CRT; - print if ($opt_l); - last if (/\*\*\*\*\* END LICENSE BLOCK \*\*\*\*\*/); +while() { + if(/\*\*\*\*\* BEGIN LICENSE BLOCK \*\*\*\*\*/) { + print CRT; + print if($opt_l); + while() { + print CRT; + print if($opt_l); + last if(/\*\*\*\*\* END LICENSE BLOCK \*\*\*\*\*/); + } + next; } - } - next if /^#|^\s*$/; - chomp; - if (/^CVS_ID\s+\"(.*)\"/) { - print CRT "/* $1 */\n"; - } - - # this is a match for the start of a certificate - if (/^CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE/) { - $start_of_cert = 1 - } - if ($start_of_cert && /^CKA_LABEL UTF8 \"(.*)\"/) { - $caname = $1; - } - my %trust_purposes_by_level; - if ($start_of_cert && /^CKA_VALUE MULTILINE_OCTAL/) { - my $data; - while () { - last if (/^END/); - chomp; - my @octets = split(/\\/); - shift @octets; - for (@octets) { - $data .= chr(oct); - } + # The input file format consists of blocks of Mozilla objects. + # The blocks are separated by blank lines but may be related. + elsif(/^\s*$/) { + $main_block = 0; + $trust_block = 0; + next; } - # scan forwards until the trust part - while () { - last if (/^CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST/); - chomp; + # Each certificate has a main block. + elsif(/^# Certificate "(.*)"/) { + (!$main_block && !$trust_block) or die "Unexpected certificate block"; + $main_block = 1; + $main_block_name = $1; + # Reset all other certificate variables. + $trust_block = 0; + $trust_block_name = ""; + $valid = 0; + $start_of_cert = 0; + $caname = ""; + $cka_value = ""; + undef @precert; + next; } - # now scan the trust part to determine how we should trust this cert - while () { - last if (/^#/); - if (/^CKA_TRUST_([A-Z_]+)\s+CK_TRUST\s+CKT_NSS_([A-Z_]+)\s*$/) { - if ( !is_in_list($1,@valid_mozilla_trust_purposes) ) { - report "Warning: Unrecognized trust purpose for cert: $caname. Trust purpose: $1. Trust Level: $2"; - } elsif ( !is_in_list($2,@valid_mozilla_trust_levels) ) { - report "Warning: Unrecognized trust level for cert: $caname. Trust purpose: $1. Trust Level: $2"; - } else { - push @{$trust_purposes_by_level{$2}}, $1; + # Each certificate's main block is followed by a trust block. + elsif(/^# Trust for (?:Certificate )?"(.*)"/) { + (!$main_block && !$trust_block) or die "Unexpected trust block"; + $trust_block = 1; + $trust_block_name = $1; + if($main_block_name ne $trust_block_name) { + die "cert name \"$main_block_name\" != trust name \"$trust_block_name\""; + } + next; + } + # Ignore other blocks. + # + # There is a documentation comment block, a BEGINDATA block, and a bunch of + # blocks starting with "# Explicitly Distrust ". + # + # The latter is for certificates that have already been removed and are not + # included. Not all explicitly distrusted certificates are ignored at this + # point, only those without an actual certificate. + elsif(!$main_block && !$trust_block) { + next; + } + elsif(/^#/) { + # The commented lines in a main block are plaintext metadata that describes + # the certificate. Issuer, Subject, Fingerprint, etc. + if($main_block) { + push @precert, s{^#}{//}r if not /^#$/; + if(/^# Not Valid After : (.*)/) { + my $stamp = $1; + use Time::Piece; + # Not Valid After : Thu Sep 30 14:01:15 2021 + my $t = Time::Piece->strptime($stamp, "%a %b %d %H:%M:%S %Y"); + my $delta = ($t->epoch - time()); # negative means no longer valid + if($delta < 0) { + $skipnum++; + report "Skipping: $main_block_name is not valid anymore" if($opt_v); + $valid = 0; + } + else { + $valid = 1; + } + } } - } + next; + } + elsif(!$valid) { + next; } - if ( !should_output_cert(%trust_purposes_by_level) ) { - $skipnum ++; - } elsif ($caname =~ /TrustCor/) { - $skipnum ++; - } else { - my $encoded = MIME::Base64::encode_base64($data, ''); - $encoded =~ s/(.{1,${opt_w}})/"$1\\n"\n/g; - my $pem = "\"-----BEGIN CERTIFICATE-----\\n\"\n" - . $encoded - . "\"-----END CERTIFICATE-----\",\n"; - print CRT "\n/* $caname */\n"; - - my $maxStringLength = length($caname); - if ($opt_t) { - foreach my $key (keys %trust_purposes_by_level) { - my $string = $key . ": " . join(", ", @{$trust_purposes_by_level{$key}}); - $maxStringLength = List::Util::max( length($string), $maxStringLength ); - print CRT $string . "\n"; + chomp; + + if($main_block) { + if(/^CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE/) { + !$start_of_cert or die "Duplicate CKO_CERTIFICATE object"; + $start_of_cert = 1; + next; + } + elsif(!$start_of_cert) { + next; + } + elsif(/^CKA_LABEL UTF8 \"(.*)\"/) { + ($caname eq "") or die "Duplicate CKA_LABEL attribute"; + $caname = $1; + if($caname ne $main_block_name) { + die "caname \"$caname\" != cert name \"$main_block_name\""; + } + next; } - } - if (!$opt_t) { - print CRT $pem; - } else { - my $pipe = ""; - foreach my $hash (@included_signature_algorithms) { - $pipe = "|$openssl x509 -" . $hash . " -fingerprint -noout -inform PEM"; - if (!$stdout) { - $pipe .= " >> $crt.~"; - close(CRT) or die "Couldn't close $crt.~: $!"; - } - open(TMP, $pipe) or die "Couldn't open openssl pipe: $!"; - print TMP $pem; - close(TMP) or die "Couldn't close openssl pipe: $!"; - if (!$stdout) { - open(CRT, ">>$crt.~") or die "Couldn't open $crt.~: $!"; - } + elsif(/^CKA_VALUE MULTILINE_OCTAL/) { + ($cka_value eq "") or die "Duplicate CKA_VALUE attribute"; + while() { + last if(/^END/); + chomp; + my @octets = split(/\\/); + shift @octets; + for(@octets) { + $cka_value .= chr(oct); + } + } + next; + } + else { + next; + } + } + + if(!$trust_block || !$start_of_cert || $caname eq "" || $cka_value eq "") { + die "Certificate extraction failed"; + } + + my %trust_purposes_by_level; + + if(/^CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST/) { + # now scan the trust part to determine how we should trust this cert + while() { + if(/^\s*$/) { + $trust_block = 0; + last; + } + if(/^CKA_TRUST_([A-Z_]+)\s+CK_TRUST\s+CKT_NSS_([A-Z_]+)\s*$/) { + if(!is_in_list($1, @valid_mozilla_trust_purposes)) { + report "Warning: Unrecognized trust purpose for cert: $caname. Trust purpose: $1. Trust Level: $2"; + } elsif(!is_in_list($2, @valid_mozilla_trust_levels)) { + report "Warning: Unrecognized trust level for cert: $caname. Trust purpose: $1. Trust Level: $2"; + } else { + push @{$trust_purposes_by_level{$2}}, $1; + } + } } - $pipe = "|$openssl x509 -text -inform PEM"; - if (!$stdout) { - $pipe .= " >> $crt.~"; - close(CRT) or die "Couldn't close $crt.~: $!"; + + # Sanity check that an explicitly distrusted certificate only has trust + # purposes with a trust level of NOT_TRUSTED. + # + # Certificate objects that are explicitly distrusted are in a certificate + # block that starts # Certificate "Explicitly Distrust(ed) ", + # where "Explicitly Distrust(ed) " was prepended to the original cert name. + if($caname =~ /distrust/i || + $main_block_name =~ /distrust/i || + $trust_block_name =~ /distrust/i) { + my @levels = keys %trust_purposes_by_level; + if(scalar(@levels) != 1 || $levels[0] ne "NOT_TRUSTED") { + die "\"$caname\" must have all trust purposes at level NOT_TRUSTED."; + } } - open(TMP, $pipe) or die "Couldn't open openssl pipe: $!"; - print TMP $pem; - close(TMP) or die "Couldn't close openssl pipe: $!"; - if (!$stdout) { - open(CRT, ">>$crt.~") or die "Couldn't open $crt.~: $!"; + + if(!should_output_cert(%trust_purposes_by_level)) { + $skipnum ++; + report "Skipping: $caname lacks acceptable trust level" if($opt_v); + } elsif($caname =~ /TrustCor/) { + $skipnum ++; + } else { + my $encoded = MIME::Base64::encode_base64($cka_value, ''); + $encoded =~ s/(.{1,${opt_w}})/"$1\\n"\n/g; + my $pem = "\"-----BEGIN CERTIFICATE-----\\n\"\n" + . $encoded + . "\"-----END CERTIFICATE-----\",\n"; + print CRT "\n/* $caname */\n"; + if($opt_t) { + foreach my $key (sort keys %trust_purposes_by_level) { + my $string = $key . ": " . join(", ", @{$trust_purposes_by_level{$key}}); + print CRT $string . "\n"; + } + } + if($opt_m) { + print CRT for @precert; + } + if(!$opt_t) { + print CRT $pem; + } else { + my $pipe = ""; + foreach my $hash (@included_signature_algorithms) { + $pipe = "|$openssl x509 -" . $hash . " -fingerprint -noout -inform PEM"; + if(!$stdout) { + $pipe .= " >> $crt.~"; + close(CRT) or die "Could not close $crt.~: $!"; + } + open(TMP, $pipe) or die "Could not open openssl pipe: $!"; + print TMP $pem; + close(TMP) or die "Could not close openssl pipe: $!"; + if(!$stdout) { + open(CRT, ">>", "$crt.~") or die "Could not open $crt.~: $!"; + } + } + $pipe = "|$openssl x509 -text -inform PEM"; + if(!$stdout) { + $pipe .= " >> $crt.~"; + close(CRT) or die "Could not close $crt.~: $!"; + } + open(TMP, $pipe) or die "Could not open openssl pipe: $!"; + print TMP $pem; + close(TMP) or die "Could not close openssl pipe: $!"; + if(!$stdout) { + open(CRT, ">>", "$crt.~") or die "Could not open $crt.~: $!"; + } + } + report "Processed: $caname" if($opt_v); + $certnum++; } - } - report "Parsing: $caname" if ($opt_v); - $certnum ++; - $start_of_cert = 0; } - } } print CRT "#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS\n"; -close(TXT) or die "Couldn't close $txt: $!\n"; -close(CRT) or die "Couldn't close $crt.~: $!\n"; -unless( $stdout ) { +close(TXT) or die "Could not close $txt: $!\n"; +close(CRT) or die "Could not close $crt.~: $!\n"; +unless($stdout) { rename "$crt.~", $crt or die "Failed to rename $crt.~ to $crt: $!\n"; } report "Done ($certnum CA certs processed, $skipnum skipped)."; diff --git a/tools/pgo/README.md b/tools/pgo/README.md new file mode 100644 index 000000000000..9277315508ca --- /dev/null +++ b/tools/pgo/README.md @@ -0,0 +1,98 @@ +# Node.js PGO Training Scripts + +Training workloads for Profile-Guided Optimization (PGO) builds using +Clang/LLVM (including Clang-CL on Windows). + +## What is PGO? + +PGO uses runtime profile data to guide compiler optimizations (inlining, +branch prediction, code layout), typically improving throughput by 5-20%. + +The process has three phases: + +1. **Instrument** — Build with `-fprofile-generate` (produces `.profraw` files) +2. **Train** — Run representative workloads to collect profile data +3. **Optimize** — Merge `.profraw` → `node.profdata` via `llvm-profdata`, + then rebuild with `-fprofile-use` + +## Quick Start + +From a VS Developer Command Prompt: + +```powershell +# Step 1: Build the instrumented binary +vcbuild.bat pgo-generate + +# Step 2: Run workloads and merge profile data +.\pgo.ps1 + +# Step 3: Build the optimized binary +vcbuild.bat pgo-use +``` + +`pgo.ps1` expects the instrumented binary at `Release\node.exe` (produced by +step 1) and writes `node.profdata` to the repo root (consumed by step 3). + +```powershell +# Optionally set a longer training duration (default: 15s per script) +.\pgo.ps1 -Duration 30 +``` + +## Training Scripts + +All scripts use only Node.js built-in modules (no npm dependencies). +Each script is run as a separate process via `fork()`, producing its own +`.profraw` file. + +| Script | What it exercises | +| ------------------------ | ------------------------------------------------------------- | +| `pgo-http-server.js` | llhttp parser, TCP stack, header serialization, JSON, routing | +| `pgo-json.js` | V8 JSON parser/serializer, string allocation, GC pressure | +| `pgo-crypto.js` | OpenSSL (hashing, HMAC, AES, RSA, ECDSA, random, KDF) | +| `pgo-streams-buffers.js` | Buffer C++ impl, stream state machine, back-pressure | +| `pgo-fs.js` | libuv fs operations, thread pool, path module | +| `pgo-async-patterns.js` | V8 Promises, microtask queue, EventEmitter, timers | +| `pgo-url-string.js` | Ada URL parser, V8 string internals, regex JIT | +| `pgo-compression.js` | zlib, brotli C libraries, streaming compression | +| `pgo-net.js` | libuv TCP/pipe handles, c-ares DNS resolver | +| `pgo-module-loading.js` | Module resolver, V8 script compilation, vm module | +| `pgo-child-workers.js` | Worker thread messaging, SharedArrayBuffer, inline eval | + +### Running the Orchestrator Directly + +The orchestrator can also be invoked directly (e.g. for testing individual +workloads). When used with `pgo.ps1`, this is handled automatically. + +```bash +# Run all scripts +node tools/pgo/pgo-run-all.js --duration=15 --verbose + +# Run specific scripts +node tools/pgo/pgo-run-all.js --scripts=http-server,json,crypto --duration=30 + +# Show help +node tools/pgo/pgo-run-all.js --help +``` + +Each script reads the `PGO_TRAINING_DURATION` environment variable (in +milliseconds) to determine how long to run. The orchestrator sets this +automatically from the `--duration` flag (in seconds). + +## Files + +``` +tools/pgo/ +├── pgo-run-all.js # Training orchestrator +├── pgo-http-server.js # HTTP server + client workload +├── pgo-json.js # JSON parse/stringify workload +├── pgo-crypto.js # Crypto operations workload +├── pgo-streams-buffers.js # Streams and Buffer workload +├── pgo-fs.js # File system operations workload +├── pgo-async-patterns.js # Promise/async, EventEmitter, timers workload +├── pgo-url-string.js # URL parsing, string ops, regex workload +├── pgo-compression.js # Gzip/brotli/deflate compression workload +├── pgo-net.js # TCP networking and DNS workload +├── pgo-module-loading.js # Module require/import, VM compilation workload +├── pgo-child-workers.js # Worker threads workload +└── README.md # This file +``` diff --git a/tools/pgo/pgo-async-patterns.js b/tools/pgo/pgo-async-patterns.js new file mode 100644 index 000000000000..3f00c13fb08f --- /dev/null +++ b/tools/pgo/pgo-async-patterns.js @@ -0,0 +1,467 @@ +'use strict'; + +/* eslint-disable no-void */ + +// PGO Training Script: Async Patterns, Timers, and Events +// +// Modern Node.js code is dominated by async/await and Promises. +// This script exercises: +// - Promise creation, chaining, and resolution (every async operation) +// - async/await control flow (the primary coding pattern) +// - Promise.all/allSettled/race/any (concurrent operation patterns) +// - EventEmitter (backbone of all Node.js I/O) +// - Timers: setTimeout, setInterval, setImmediate (scheduling) +// - AbortController/AbortSignal (cancellation - growing usage) +// - queueMicrotask / process.nextTick (microtask scheduling) +// - AsyncLocalStorage (request context propagation - growing fast) +// +// This exercises: V8 Promise machinery, microtask queue, libuv timer heap, +// EventEmitter C++/JS boundary, AbortSignal C++ implementation. + +const { EventEmitter } = require('events'); +const { AsyncLocalStorage } = require('async_hooks'); +const { + setTimeout: setTimeoutPromise, + setImmediate: setImmediatePromise, +} = require('timers/promises'); + +const DURATION_MS = parseInt(process.env.PGO_TRAINING_DURATION, 10) || 15_000; + +// Workload 1: Promise chains (REST API middleware pattern) +async function workloadPromiseChains(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + // Simple promise chain (Express middleware-like) + await Promise.resolve({ method: 'GET', url: '/api/users' }) + .then((req) => ({ ...req, authenticated: true })) + .then((req) => ({ ...req, parsed: true, body: {} })) + .then((req) => ({ ...req, validated: true })) + .then(() => ({ + status: 200, + body: JSON.stringify({ users: [], total: 0 }), + headers: { 'content-type': 'application/json' }, + })); + ops++; + + // Promise with error handling (try/catch in async flow) + try { + await Promise.resolve(i) + .then((v) => { + if (v % 7 === 0) throw new Error('validation'); + return v; + }) + .then((v) => v * 2) + .catch((err) => ({ error: err.message })); + ops++; + } catch { + ops++; + } + + // Nested promise resolution (database query pattern) + const result = await new Promise((resolve) => { + // Simulate async work + resolve({ + rows: Array.from({ length: 10 }, (_, j) => ({ id: j, value: i + j })), + }); + }); + await new Promise((resolve) => { + resolve(result.rows.map((r) => ({ ...r, processed: true }))); + }); + ops++; + } + return ops; +} + +// Workload 2: Promise.all / allSettled / race / any (concurrent patterns) +async function workloadPromiseConcurrency(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + // Promise.all (parallel database queries, batch API calls) + await Promise.all( + Array.from({ length: 20 }, (_, j) => + Promise.resolve({ id: j, data: `result_${j}` }), + ), + ); + ops++; + + // Promise.allSettled (fault-tolerant batch operations) + await Promise.allSettled( + Array.from({ length: 15 }, (_, j) => + (j % 5 === 0 ? + Promise.reject(new Error(`fail_${j}`)) : + Promise.resolve({ id: j, ok: true })), + ), + ); + ops++; + + // Promise.race (timeout pattern) + await Promise.race([ + Promise.resolve('fast'), + new Promise((resolve) => setTimeout(resolve, 10000, 'slow')), + ]); + ops++; + + // Promise.any (failover pattern) + await Promise.any([ + Promise.reject(new Error('server1')), + Promise.resolve('server2'), + Promise.resolve('server3'), + ]); + ops++; + + // Batched parallel with limit (connection pool pattern) + const batchSize = 5; + const items = Array.from({ length: 20 }, (_, j) => j); + for (let start = 0; start < items.length; start += batchSize) { + const batch = items.slice(start, start + batchSize); + await Promise.all(batch.map((item) => Promise.resolve(item * 2))); + } + ops++; + } + return ops; +} + +// Workload 3: EventEmitter (core Node.js pattern) +function workloadEventEmitter(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + const emitter = new EventEmitter(); + + // Add multiple listeners (typical server setup) + const listeners = []; + for (let j = 0; j < 10; j++) { + const listener = (data) => { + data.processed = true; + }; + listeners.push(listener); + emitter.on('data', listener); + } + ops++; + + // Once listener (connection setup pattern) + emitter.once('connect', () => {}); + emitter.once('ready', () => {}); + ops++; + + // Emit events (hot path in I/O) + for (let j = 0; j < 100; j++) { + emitter.emit('data', { id: j, value: j * 2 }); + } + ops += 100; + + // Emit with multiple arguments + for (let j = 0; j < 20; j++) { + emitter.emit('data', { id: j }, 'extra', j); + } + ops += 20; + + // Error event handling + emitter.on('error', () => {}); + emitter.emit('error', new Error('test')); + ops++; + + // listenerCount / listeners (monitoring) + emitter.listenerCount('data'); + emitter.listeners('data'); + emitter.rawListeners('data'); + emitter.eventNames(); + ops += 4; + + // Remove listeners (cleanup) + for (const listener of listeners) { + emitter.removeListener('data', listener); + } + emitter.removeAllListeners(); + ops++; + } + return ops; +} + +// Workload 4: EventTarget (Web API compatibility — growing usage) +function workloadEventTarget(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + const target = new EventTarget(); + + // Add listeners + const handlers = []; + for (let j = 0; j < 5; j++) { + const handler = (e) => { + void e.detail; + }; + handlers.push(handler); + target.addEventListener('message', handler); + } + ops++; + + // Dispatch events + for (let j = 0; j < 50; j++) { + target.dispatchEvent(new Event('message')); + } + ops += 50; + + // Remove listeners + for (const handler of handlers) { + target.removeEventListener('message', handler); + } + ops++; + } + return ops; +} + +// Workload 5: Timers (setTimeout, setInterval, setImmediate) +async function workloadTimers(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + // setTimeout with 0 (defer to next event loop - very common) + await new Promise((resolve) => setTimeout(resolve, 0)); + ops++; + + // setImmediate (process next I/O callbacks first) + await new Promise((resolve) => setImmediate(resolve)); + ops++; + + // setTimeout promise API + await setTimeoutPromise(0); + ops++; + + // setImmediate promise API + await setImmediatePromise(); + ops++; + + // Timer creation and cancellation (debounce/throttle patterns) + for (let j = 0; j < 10; j++) { + const timer = setTimeout(() => {}, 10000); + clearTimeout(timer); + } + ops += 10; + + // setInterval + clearInterval (polling pattern) + const interval = setInterval(() => {}, 1000); + clearInterval(interval); + ops++; + + // process.nextTick (microtask — higher priority than timers) + await new Promise((resolve) => process.nextTick(resolve)); + ops++; + + // queueMicrotask + await new Promise((resolve) => queueMicrotask(resolve)); + ops++; + + // Nested nextTick/microtask (realistic: multiple middleware layers) + await new Promise((outerResolve) => { + process.nextTick(() => { + queueMicrotask(() => { + process.nextTick(() => { + outerResolve(); + }); + }); + }); + }); + ops++; + } + return ops; +} + +// Workload 6: AbortController (cancellation — widely used since Node.js 16+) +async function workloadAbortController(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + // Create and signal (timeout pattern) + const ac1 = new AbortController(); + const { signal: sig1 } = ac1; + sig1.addEventListener('abort', () => {}); + ac1.abort(); + ops++; + + // AbortSignal.timeout (modern API) + const sig2 = AbortSignal.timeout(5000); + void sig2.aborted; // check status + ops++; + + // AbortSignal.any (composite signals) + const ac3 = new AbortController(); + const sig3 = AbortSignal.any([ac3.signal, AbortSignal.timeout(10000)]); + sig3.addEventListener('abort', () => {}); + ac3.abort('cancelled'); + ops++; + + // Using with setTimeout (common pattern) + try { + const ac = new AbortController(); + const timer = setTimeout(() => ac.abort(), 0); + await setTimeoutPromise(0, undefined, { signal: ac.signal }); + clearTimeout(timer); + ops++; + } catch { + ops++; // AbortError is expected sometimes + } + } + return ops; +} + +// Workload 7: AsyncLocalStorage (request context — Express, Fastify, Nest.js) +async function workloadAsyncLocalStorage(iterations) { + let ops = 0; + const als = new AsyncLocalStorage(); + + for (let i = 0; i < iterations; i++) { + // Run with context (HTTP request lifecycle) + await als.run( + { requestId: `req-${i}`, userId: `user-${i % 100}` }, + async () => { + const store = als.getStore(); + + // "Middleware" that reads context + void store.requestId; + + // "Service" layer — context propagates through async calls + await Promise.resolve().then(() => { + const ctx = als.getStore(); + return { ...ctx, processed: true }; + }); + + // Nested async operation with context + await new Promise((resolve) => { + setImmediate(() => { + const ctx = als.getStore(); + resolve(ctx); + }); + }); + + ops++; + }, + ); + + // enterWith pattern (alternative API) + als.enterWith({ contextId: i }); + als.getStore(); + ops++; + } + return ops; +} + +// Workload 8: Error creation and stack traces (very frequent in real apps) +function workloadErrors(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + // Error creation with stack trace + const err1 = new Error(`Something went wrong: ${i}`); + void err1.stack; // Access stack (forces stack trace computation) + void err1.message; + ops++; + + // TypeError (most common runtime error) + const err2 = new TypeError(`Cannot read property of undefined`); + void err2.stack; + ops++; + + // RangeError + const err3 = new RangeError(`Value out of range: ${i}`); + err3.code = 'ERR_OUT_OF_RANGE'; + void err3.stack; + ops++; + + // try/catch (V8's exception handling path) + for (let j = 0; j < 10; j++) { + try { + if (j % 3 === 0) throw new Error(`Caught error ${j}`); + if (j % 7 === 0) throw new TypeError(`Type error ${j}`); + } catch (e) { + void e.message; // Access message + } + } + ops += 10; + + // Error.captureStackTrace (custom errors pattern) + class AppError extends Error { + constructor(message, code) { + super(message); + this.code = code; + Error.captureStackTrace(this, AppError); + } + } + const err4 = new AppError('Not found', 404); + void err4.stack; + ops++; + } + return ops; +} + +async function main() { + console.log('[pgo-async-patterns] Starting async patterns workload...'); + const startTime = Date.now(); + let totalOps = 0; + let round = 0; + + const remaining = () => DURATION_MS - (Date.now() - startTime); + + while (remaining() > 0) { + round++; + const scale = Math.max(0.1, remaining() / DURATION_MS); + const iterScale = (base) => Math.max(1, Math.floor(base * scale)); + + // Promise chains (extremely high frequency) + if (round === 1) + console.log('[pgo-async-patterns] Running promise chains...'); + totalOps += await workloadPromiseChains(iterScale(500)); + if (remaining() <= 0) break; + + // Promise concurrency + if (round === 1) + console.log('[pgo-async-patterns] Running promise concurrency...'); + totalOps += await workloadPromiseConcurrency(iterScale(200)); + if (remaining() <= 0) break; + + // EventEmitter (core pattern) + if (round === 1) + console.log('[pgo-async-patterns] Running EventEmitter...'); + totalOps += workloadEventEmitter(iterScale(200)); + if (remaining() <= 0) break; + + // EventTarget + if (round === 1) console.log('[pgo-async-patterns] Running EventTarget...'); + totalOps += workloadEventTarget(iterScale(100)); + if (remaining() <= 0) break; + + // Timers + if (round === 1) console.log('[pgo-async-patterns] Running timers...'); + totalOps += await workloadTimers(iterScale(100)); + if (remaining() <= 0) break; + + // AbortController + if (round === 1) + console.log('[pgo-async-patterns] Running AbortController...'); + totalOps += await workloadAbortController(iterScale(100)); + if (remaining() <= 0) break; + + // AsyncLocalStorage + if (round === 1) + console.log('[pgo-async-patterns] Running AsyncLocalStorage...'); + totalOps += await workloadAsyncLocalStorage(iterScale(100)); + if (remaining() <= 0) break; + + // Errors + if (round === 1) + console.log('[pgo-async-patterns] Running error patterns...'); + totalOps += workloadErrors(iterScale(300)); + } + + const elapsed = (Date.now() - startTime) / 1000; + console.log( + `[pgo-async-patterns] Completed ${totalOps} ops in ${elapsed.toFixed(1)}s (${(totalOps / elapsed).toFixed(0)} ops/s) [${round} rounds]`, + ); +} + +main().catch((err) => { + console.error('[pgo-async-patterns] Error:', err); + process.exit(1); +}); diff --git a/tools/pgo/pgo-child-workers.js b/tools/pgo/pgo-child-workers.js new file mode 100644 index 000000000000..9f8451641cb3 --- /dev/null +++ b/tools/pgo/pgo-child-workers.js @@ -0,0 +1,284 @@ +'use strict'; + +// PGO Training Script: Worker Threads +// +// Node.js Worker threads are used for: +// - CPU-intensive parallel work (image processing, parsing, compilation) +// - Thread pool patterns for offloading blocking work +// - SharedArrayBuffer-based parallel computation +// - Inline eval workers (used by some frameworks) +// +// This exercises: Worker thread messaging, structured clone serialization, +// SharedArrayBuffer, Atomics, V8 isolate creation, module loading in workers. +// +// Note: child_process.spawn/fork are excluded from PGO training because each +// spawned process generates its own .profraw file, creating hundreds of +// startup-heavy profiles that dilute the steady-state profile data. + +const { Worker, isMainThread } = require('worker_threads'); +const path = require('path'); +const os = require('os'); +const fs = require('fs'); + +const DURATION_MS = parseInt(process.env.PGO_TRAINING_DURATION, 10) || 15_000; +const TEMP_DIR = path.join( + os.tmpdir(), + `node-pgo-workers-${process.pid}-${Date.now()}`, +); + +function setup() { + fs.mkdirSync(TEMP_DIR, { recursive: true }); + + // Write worker script files + fs.writeFileSync( + path.join(TEMP_DIR, 'worker-cpu.js'), + ` + 'use strict'; + const { parentPort, workerData } = require('worker_threads'); + + // CPU-intensive work: hash computation, JSON processing, regex + function doWork(data) { + const crypto = require('crypto'); + const results = []; + + for (let i = 0; i < data.iterations; i++) { + // Hash computation + const hash = crypto.createHash('sha256') + .update(JSON.stringify({ index: i, data: data.payload })) + .digest('hex'); + + // JSON round-trip + const obj = JSON.parse(JSON.stringify({ + id: i, + hash, + timestamp: Date.now(), + nested: { a: { b: { c: i } } }, + })); + + // Regex processing + const text = 'The quick brown fox jumps over the lazy dog '.repeat(10); + const matches = text.match(/\\b\\w{4,}\\b/g) || []; + + results.push({ hash: hash.slice(0, 8), matches: matches.length }); + } + + return { count: results.length, sample: results[0] }; + } + + parentPort.on('message', (msg) => { + if (msg.type === 'work') { + const result = doWork(msg.data); + parentPort.postMessage({ type: 'result', data: result }); + } + if (msg.type === 'exit') { + process.exit(0); + } + }); + + // Also handle direct workerData + if (workerData && workerData.autoStart) { + const result = doWork(workerData); + parentPort.postMessage({ type: 'result', data: result }); + } + `, + ); + + fs.writeFileSync( + path.join(TEMP_DIR, 'worker-shared.js'), + ` + 'use strict'; + const { parentPort, workerData } = require('worker_threads'); + + // Shared memory worker: operates on SharedArrayBuffer + const { buffer, offset, length } = workerData; + const view = new Int32Array(buffer); + + // Process assigned segment + for (let i = offset; i < offset + length; i++) { + // Atomic operations + Atomics.add(view, i, 1); + Atomics.load(view, i); + } + + parentPort.postMessage({ done: true, processed: length }); + `, + ); +} + +function cleanup() { + try { + fs.rmSync(TEMP_DIR, { recursive: true, force: true }); + } catch { + // best effort + } +} + +// Workload 1: Worker threads — message passing (the dominant pattern) +async function workloadWorkerMessages(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + const worker = new Worker(path.join(TEMP_DIR, 'worker-cpu.js')); + + await new Promise((resolve, reject) => { + worker.on('message', (msg) => { + if (msg.type === 'result') { + ops++; + worker.postMessage({ type: 'exit' }); + } + }); + worker.on('exit', resolve); + worker.on('error', reject); + + // Send work + worker.postMessage({ + type: 'work', + data: { iterations: 50, payload: `batch_${i}` }, + }); + }); + } + return ops; +} + +// Workload 2: Worker threads — workerData initialization +async function workloadWorkerData(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + const worker = new Worker(path.join(TEMP_DIR, 'worker-cpu.js'), { + workerData: { autoStart: true, iterations: 30, payload: `init_${i}` }, + }); + + await new Promise((resolve, reject) => { + worker.on('message', (msg) => { + if (msg.type === 'result') { + ops++; + worker.terminate(); + } + }); + worker.on('exit', resolve); + worker.on('error', reject); + }); + } + return ops; +} + +// Workload 3: Worker threads — SharedArrayBuffer (parallel computation) +async function workloadSharedMemory(iterations) { + let ops = 0; + const ARRAY_SIZE = 1024; + const NUM_WORKERS = Math.min(4, os.cpus().length); + + for (let i = 0; i < iterations; i++) { + const sharedBuffer = new SharedArrayBuffer(ARRAY_SIZE * 4); // Int32Array + const segmentSize = Math.floor(ARRAY_SIZE / NUM_WORKERS); + + const workers = []; + const promises = []; + + for (let w = 0; w < NUM_WORKERS; w++) { + const worker = new Worker(path.join(TEMP_DIR, 'worker-shared.js'), { + workerData: { + buffer: sharedBuffer, + offset: w * segmentSize, + length: segmentSize, + }, + }); + + const promise = new Promise((resolve, reject) => { + worker.on('message', (msg) => { + ops++; + resolve(msg); + }); + worker.on('error', reject); + worker.on('exit', () => resolve()); + }); + + workers.push(worker); + promises.push(promise); + } + + await Promise.all(promises); + } + return ops; +} + +// Workload 4: Worker from inline code (eval pattern — used by some frameworks) +async function workloadInlineWorker(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + const code = ` + const { parentPort } = require('worker_threads'); + const crypto = require('crypto'); + const result = crypto.createHash('sha256').update('data-${i}').digest('hex'); + parentPort.postMessage({ hash: result }); + `; + + const worker = new Worker(code, { eval: true }); + + await new Promise((resolve, reject) => { + worker.on('message', (msg) => { + ops++; + resolve(msg); + }); + worker.on('error', reject); + worker.on('exit', () => resolve()); + }); + } + return ops; +} + +async function main() { + if (!isMainThread) return; // Guard against being loaded as worker + + console.log('[pgo-child-workers] Starting worker thread workload...'); + + setup(); + const startTime = Date.now(); + let totalOps = 0; + let round = 0; + + const remaining = () => DURATION_MS - (Date.now() - startTime); + + try { + while (remaining() > 0) { + round++; + const scale = Math.max(0.1, remaining() / DURATION_MS); + const iterScale = (base) => Math.max(1, Math.floor(base * scale)); + + // Worker threads (most impactful for PGO) + if (round === 1) + console.log('[pgo-child-workers] Running worker messages...'); + totalOps += await workloadWorkerMessages(iterScale(10)); + if (remaining() <= 0) break; + + if (round === 1) + console.log('[pgo-child-workers] Running workerData init...'); + totalOps += await workloadWorkerData(iterScale(10)); + if (remaining() <= 0) break; + + if (round === 1) + console.log('[pgo-child-workers] Running shared memory workers...'); + totalOps += await workloadSharedMemory(iterScale(5)); + if (remaining() <= 0) break; + + if (round === 1) + console.log('[pgo-child-workers] Running inline workers...'); + totalOps += await workloadInlineWorker(iterScale(10)); + } + + const elapsed = (Date.now() - startTime) / 1000; + console.log( + `[pgo-child-workers] Completed ${totalOps} ops in ${elapsed.toFixed(1)}s (${(totalOps / elapsed).toFixed(0)} ops/s) [${round} rounds]`, + ); + } finally { + cleanup(); + } +} + +main().catch((err) => { + console.error('[pgo-child-workers] Error:', err); + cleanup(); + process.exit(1); +}); diff --git a/tools/pgo/pgo-compression.js b/tools/pgo/pgo-compression.js new file mode 100644 index 000000000000..4c1c7570b8b4 --- /dev/null +++ b/tools/pgo/pgo-compression.js @@ -0,0 +1,417 @@ +'use strict'; + +// PGO Training Script: Compression (zlib/brotli) +// +// HTTP response compression is used on virtually every production Node.js server. +// This script exercises: +// - gzip compression/decompression (the most common HTTP content-encoding) +// - deflate compression/decompression +// - brotli compression/decompression (modern, better ratio) +// - Streaming compression (piped through HTTP responses) +// - One-shot compression (in-memory buffers) +// - Various compression levels and data types +// - CRC-32 computation +// +// This exercises: zlib C library, brotli C library, libuv thread pool +// (async compression), stream infrastructure, Buffer allocation. + +const zlib = require('zlib'); +const crypto = require('crypto'); +const { pipeline } = require('stream/promises'); +const { Readable, Writable } = require('stream'); + +const DURATION_MS = parseInt(process.env.PGO_TRAINING_DURATION, 10) || 15_000; + +// Test data of different types and sizes (compression ratio varies) +const JSON_DATA = Buffer.from( + JSON.stringify({ + users: Array.from({ length: 200 }, (_, i) => ({ + id: i, + name: `User ${i}`, + email: `user${i}@example.com`, + role: ['admin', 'editor', 'viewer'][i % 3], + active: i % 4 !== 0, + profile: { + bio: `This is the biography for user ${i}. It contains some repetitive text to demonstrate compression.`, + location: ['New York', 'London', 'Tokyo', 'Berlin', 'Sydney'][i % 5], + joinDate: `2024-${String((i % 12) + 1).padStart(2, '0')}-${String((i % 28) + 1).padStart(2, '0')}`, + }, + })), + }), +); + +const HTML_DATA = Buffer.from(` + +Test Page + +${Array.from( + { length: 100 }, + (_, i) => ` +
+

Card Title ${i}

+

This is the body text for card number ${i}. It contains enough text to be meaningful for compression benchmarks.

+ +
`, +).join('\n')} +`); + +const CSS_DATA = Buffer.from( + Array.from( + { length: 200 }, + (_, i) => ` +.component-${i} { display: flex; align-items: center; padding: ${i}px; margin: ${i % 20}px; } +.component-${i}:hover { background-color: #${String(i * 111) + .padStart(6, '0') + .slice(0, 6)}; transition: all 0.3s ease; } +.component-${i} .title { font-size: ${12 + (i % 8)}px; font-weight: ${i % 2 === 0 ? 'bold' : 'normal'}; } +.component-${i} .description { color: #666; line-height: 1.5; max-width: ${200 + i * 5}px; } +`, + ).join('\n'), +); + +const JS_DATA = Buffer.from( + Array.from( + { length: 100 }, + (_, i) => ` +function handler${i}(req, res) { + const data = req.body; + if (!data || !data.id) { + return res.status(400).json({ error: 'Missing id' }); + } + const result = processData${i}(data); + return res.json({ success: true, data: result, timestamp: Date.now() }); +} +function processData${i}(data) { + return { ...data, processed: true, handler: 'handler${i}' }; +} +module.exports = { handler${i}, processData${i} }; +`, + ).join('\n'), +); + +// Binary data (images, wasm — less compressible) +const BINARY_DATA = crypto.randomBytes(32768); + +const TEST_DATA = [ + { name: 'JSON', data: JSON_DATA, weight: 5 }, + { name: 'HTML', data: HTML_DATA, weight: 3 }, + { name: 'CSS', data: CSS_DATA, weight: 2 }, + { name: 'JS', data: JS_DATA, weight: 2 }, + { name: 'Binary', data: BINARY_DATA, weight: 1 }, +]; + +const weightedData = []; +for (const item of TEST_DATA) { + for (let i = 0; i < item.weight; i++) { + weightedData.push(item); + } +} + +// Workload 1: Gzip compress/decompress (one-shot, most common pattern) +async function workloadGzip(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + const item = weightedData[i % weightedData.length]; + + // Compress (HTTP response compression) + const compressed = await new Promise((resolve, reject) => { + zlib.gzip(item.data, (err, result) => { + if (err) reject(err); + else resolve(result); + }); + }); + ops++; + + // Decompress (HTTP response decompression on client) + await new Promise((resolve, reject) => { + zlib.gunzip(compressed, (err, result) => { + if (err) reject(err); + else resolve(result); + }); + }); + ops++; + + // Sync variant (used in some build tools) + if (i % 5 === 0) { + const compSync = zlib.gzipSync(item.data); + zlib.gunzipSync(compSync); + ops += 2; + } + + // Different compression levels + if (i % 3 === 0) { + await new Promise((resolve, reject) => { + zlib.gzip(item.data, { level: 1 }, (err, result) => { + // Fast + if (err) reject(err); + else resolve(result); + }); + }); + ops++; + } + if (i % 7 === 0) { + await new Promise((resolve, reject) => { + zlib.gzip(item.data, { level: 9 }, (err, result) => { + // Best + if (err) reject(err); + else resolve(result); + }); + }); + ops++; + } + } + return ops; +} + +// Workload 2: Deflate compress/decompress +async function workloadDeflate(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + const item = weightedData[i % weightedData.length]; + + // deflate (used in some HTTP implementations) + const compressed = await new Promise((resolve, reject) => { + zlib.deflate(item.data, (err, result) => { + if (err) reject(err); + else resolve(result); + }); + }); + ops++; + + await new Promise((resolve, reject) => { + zlib.inflate(compressed, (err, result) => { + if (err) reject(err); + else resolve(result); + }); + }); + ops++; + + // deflateRaw (no header — used in some protocols) + if (i % 3 === 0) { + const raw = zlib.deflateRawSync(item.data); + zlib.inflateRawSync(raw); + ops += 2; + } + } + return ops; +} + +// Workload 3: Brotli compress/decompress (modern HTTP content-encoding) +async function workloadBrotli(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + const item = weightedData[i % weightedData.length]; + + // Brotli compress (response compression for supported clients) + const compressed = await new Promise((resolve, reject) => { + zlib.brotliCompress(item.data, (err, result) => { + if (err) reject(err); + else resolve(result); + }); + }); + ops++; + + // Brotli decompress + await new Promise((resolve, reject) => { + zlib.brotliDecompress(compressed, (err, result) => { + if (err) reject(err); + else resolve(result); + }); + }); + ops++; + + // Different quality levels + if (i % 3 === 0) { + await new Promise((resolve, reject) => { + zlib.brotliCompress( + item.data, + { + params: { [zlib.constants.BROTLI_PARAM_QUALITY]: 1 }, // Fast + }, + (err, result) => { + if (err) reject(err); + else resolve(result); + }, + ); + }); + ops++; + } + } + return ops; +} + +// Workload 4: Streaming compression (piped HTTP responses) +async function workloadStreamCompress(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + const item = weightedData[i % weightedData.length]; + + // Gzip stream (Express compression middleware pattern) + await pipeline( + Readable.from([item.data]), + zlib.createGzip(), + new Writable({ + write(chunk, encoding, callback) { + callback(); + }, + }), + ); + ops++; + + // Brotli stream + if (i % 2 === 0) { + await pipeline( + Readable.from([item.data]), + zlib.createBrotliCompress(), + new Writable({ + write(chunk, encoding, callback) { + callback(); + }, + }), + ); + ops++; + } + + // Chunked stream compression (large response simulation) + if (i % 3 === 0) { + const chunkSize = 4096; + const chunks = []; + for (let offset = 0; offset < item.data.length; offset += chunkSize) { + chunks.push( + item.data.subarray( + offset, + Math.min(offset + chunkSize, item.data.length), + ), + ); + } + + await pipeline( + Readable.from(chunks), + zlib.createGzip({ flush: zlib.constants.Z_SYNC_FLUSH }), + new Writable({ + write(chunk, encoding, callback) { + callback(); + }, + }), + ); + ops++; + } + } + return ops; +} + +// Workload 5: CRC-32 (used in gzip, PNG, etc.) +function workloadCRC32(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + const item = weightedData[i % weightedData.length]; + zlib.crc32(item.data); + ops++; + + // Incremental CRC (streaming pattern) + if (i % 3 === 0) { + const chunkSize = 1024; + let crc = 0; + for (let offset = 0; offset < item.data.length; offset += chunkSize) { + const chunk = item.data.subarray( + offset, + Math.min(offset + chunkSize, item.data.length), + ); + crc = zlib.crc32(chunk, crc); + } + ops++; + } + } + return ops; +} + +// Workload 6: Compression object creation (middleware initialization) +function workloadCompressionCreation(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + // Express compression middleware creates these per-request + zlib.createGzip(); + zlib.createGunzip(); + zlib.createDeflate(); + zlib.createInflate(); + zlib.createBrotliCompress(); + zlib.createBrotliDecompress(); + ops += 6; + + // With options (common in production) + zlib.createGzip({ level: 6, memLevel: 8, windowBits: 15 }); + zlib.createBrotliCompress({ + params: { + [zlib.constants.BROTLI_PARAM_QUALITY]: 4, + [zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT, + }, + }); + ops += 2; + } + return ops; +} + +async function main() { + console.log('[pgo-compression] Starting compression workload...'); + const startTime = Date.now(); + let totalOps = 0; + let round = 0; + + const remaining = () => DURATION_MS - (Date.now() - startTime); + + while (remaining() > 0) { + round++; + const scale = Math.max(0.1, remaining() / DURATION_MS); + const iterScale = (base) => Math.max(1, Math.floor(base * scale)); + + // Gzip (most common — Accept-Encoding: gzip is universal) + if (round === 1) console.log('[pgo-compression] Running gzip...'); + totalOps += await workloadGzip(iterScale(100)); + if (remaining() <= 0) break; + + // Deflate + if (round === 1) console.log('[pgo-compression] Running deflate...'); + totalOps += await workloadDeflate(iterScale(50)); + if (remaining() <= 0) break; + + // Brotli (growing rapidly) + if (round === 1) console.log('[pgo-compression] Running brotli...'); + totalOps += await workloadBrotli(iterScale(50)); + if (remaining() <= 0) break; + + // Streaming compression + if (round === 1) + console.log('[pgo-compression] Running stream compression...'); + totalOps += await workloadStreamCompress(iterScale(30)); + if (remaining() <= 0) break; + + // CRC-32 + if (round === 1) console.log('[pgo-compression] Running CRC-32...'); + totalOps += workloadCRC32(iterScale(1000)); + if (remaining() <= 0) break; + + // Object creation + if (round === 1) + console.log('[pgo-compression] Running compression object creation...'); + totalOps += workloadCompressionCreation(iterScale(500)); + } + + const elapsed = (Date.now() - startTime) / 1000; + console.log( + `[pgo-compression] Completed ${totalOps} ops in ${elapsed.toFixed(1)}s (${(totalOps / elapsed).toFixed(0)} ops/s) [${round} rounds]`, + ); +} + +main().catch((err) => { + console.error('[pgo-compression] Error:', err); + process.exit(1); +}); diff --git a/tools/pgo/pgo-crypto.js b/tools/pgo/pgo-crypto.js new file mode 100644 index 000000000000..977942a0f7f3 --- /dev/null +++ b/tools/pgo/pgo-crypto.js @@ -0,0 +1,401 @@ +'use strict'; + +// PGO Training Script: Crypto Operations +// +// Exercises the most common crypto operations in Node.js applications: +// - TLS/HTTPS is used in virtually every production deployment +// - Password hashing (bcrypt-like patterns via pbkdf2/scrypt) +// - HMAC for API authentication (AWS Signature, JWT) +// - SHA-256/SHA-512 hashing for checksums, ETags, content-addressing +// - AES-GCM encryption for data-at-rest +// - Random byte generation (session tokens, UUIDs, nonces) +// - Certificate/key handling patterns +// +// This exercises: OpenSSL (via Node.js crypto binding), Buffer allocation, +// C++ ↔ JS boundary crossing, async crypto operations, KeyObject handling. + +const crypto = require('crypto'); +const { subtle } = globalThis.crypto; + +const DURATION_MS = parseInt(process.env.PGO_TRAINING_DURATION, 10) || 15_000; + +// Test data of varying sizes +const DATA_TINY = Buffer.from('Hello, World!'); +const DATA_SMALL = crypto.randomBytes(256); +const DATA_MEDIUM = crypto.randomBytes(4096); +const DATA_LARGE = crypto.randomBytes(65536); +const DATA_XLARGE = crypto.randomBytes(262144); // 256 KB +const DATA_SIZES = [ + DATA_TINY, + DATA_SMALL, + DATA_MEDIUM, + DATA_LARGE, + DATA_XLARGE, +]; + +// Pre-generated keys for symmetric encryption +const AES_KEY = crypto.randomBytes(32); // AES-256 +const HMAC_KEY = crypto.randomBytes(64); + +// RSA key pair (pre-generated for speed) +const { publicKey: RSA_PUBLIC, privateKey: RSA_PRIVATE } = + crypto.generateKeyPairSync('rsa', { + modulusLength: 2048, + publicKeyEncoding: { type: 'spki', format: 'pem' }, + privateKeyEncoding: { type: 'pkcs8', format: 'pem' }, + }); + +// EC key pair +const { publicKey: EC_PUBLIC, privateKey: EC_PRIVATE } = + crypto.generateKeyPairSync('ec', { + namedCurve: 'P-256', + publicKeyEncoding: { type: 'spki', format: 'pem' }, + privateKeyEncoding: { type: 'pkcs8', format: 'pem' }, + }); + +// Ed25519 for modern signing +const { publicKey: ED_PUBLIC, privateKey: ED_PRIVATE } = + crypto.generateKeyPairSync('ed25519', { + publicKeyEncoding: { type: 'spki', format: 'pem' }, + privateKeyEncoding: { type: 'pkcs8', format: 'pem' }, + }); + +// Workload 1: Hashing (most common crypto operation) +function workloadHashing(iterations) { + const algorithms = ['sha256', 'sha384', 'sha512', 'sha1', 'md5']; + let ops = 0; + + for (let i = 0; i < iterations; i++) { + for (const algo of algorithms) { + const data = DATA_SIZES[i % DATA_SIZES.length]; + + // One-shot hash (most common pattern: ETags, checksums) + crypto.createHash(algo).update(data).digest('hex'); + ops++; + + // Streaming hash (file hashing pattern) + if (i % 5 === 0) { + const hash = crypto.createHash(algo); + const chunkSize = 1024; + for (let offset = 0; offset < data.length; offset += chunkSize) { + hash.update( + data.subarray(offset, Math.min(offset + chunkSize, data.length)), + ); + } + hash.digest('base64'); + ops++; + } + } + } + return ops; +} + +// Workload 2: HMAC (API auth, JWT signatures, webhook verification) +function workloadHMAC(iterations) { + let ops = 0; + const algorithms = ['sha256', 'sha384', 'sha512']; + + for (let i = 0; i < iterations; i++) { + const algo = algorithms[i % algorithms.length]; + const data = DATA_SIZES[i % DATA_SIZES.length]; + + // HMAC compute (AWS Signature v4, JWT pattern) + const sig = crypto.createHmac(algo, HMAC_KEY).update(data).digest(); + ops++; + + // HMAC verify (webhook verification pattern) + const sig2 = crypto.createHmac(algo, HMAC_KEY).update(data).digest(); + crypto.timingSafeEqual(sig, sig2); + ops++; + } + return ops; +} + +// Workload 3: AES-GCM encryption/decryption (data protection) +function workloadAESGCM(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + const data = DATA_SIZES[i % DATA_SIZES.length]; + const iv = crypto.randomBytes(12); + + // Encrypt + const cipher = crypto.createCipheriv('aes-256-gcm', AES_KEY, iv); + const encrypted = Buffer.concat([cipher.update(data), cipher.final()]); + const tag = cipher.getAuthTag(); + ops++; + + // Decrypt + const decipher = crypto.createDecipheriv('aes-256-gcm', AES_KEY, iv); + decipher.setAuthTag(tag); + Buffer.concat([decipher.update(encrypted), decipher.final()]); + ops++; + } + return ops; +} + +// Workload 4: RSA sign/verify (JWT RS256, code signing) +function workloadRSASignVerify(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + const data = DATA_SIZES[Math.min(i % 3, DATA_SIZES.length - 1)]; // RSA limits payload size + + // Sign + const sign = crypto.createSign('RSA-SHA256'); + sign.update(data); + const signature = sign.sign(RSA_PRIVATE); + ops++; + + // Verify + const verify = crypto.createVerify('RSA-SHA256'); + verify.update(data); + verify.verify(RSA_PUBLIC, signature); + ops++; + } + return ops; +} + +// Workload 5: ECDSA sign/verify (modern TLS, smaller keys) +function workloadECDSA(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + const data = DATA_SIZES[i % DATA_SIZES.length]; + + const signature = crypto.sign('SHA256', data, EC_PRIVATE); + ops++; + + crypto.verify('SHA256', data, EC_PUBLIC, signature); + ops++; + } + return ops; +} + +// Workload 6: Ed25519 sign/verify (modern fast signing) +function workloadEd25519(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + const data = DATA_SIZES[i % DATA_SIZES.length]; + + const signature = crypto.sign(null, data, ED_PRIVATE); + ops++; + + crypto.verify(null, data, ED_PUBLIC, signature); + ops++; + } + return ops; +} + +// Workload 7: Random byte generation (tokens, session IDs, UUIDs) +function workloadRandom(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + // Session tokens + crypto.randomBytes(32); + ops++; + + // UUID generation + crypto.randomUUID(); + ops++; + + // Random integers (for OTP codes, etc.) + crypto.randomInt(100000, 999999); + ops++; + + // Fill existing buffer (pool pattern) + const buf = Buffer.allocUnsafe(64); + crypto.randomFillSync(buf); + ops++; + } + return ops; +} + +// Workload 8: PBKDF2 / Scrypt (password hashing - async) +async function workloadPasswordHashing(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + const password = `password_${i}_with_some_length`; + const salt = crypto.randomBytes(16); + + // PBKDF2 (most common password hashing in Node.js) + await new Promise((resolve, reject) => { + crypto.pbkdf2(password, salt, 1000, 64, 'sha512', (err, key) => { + if (err) reject(err); + else resolve(key); + }); + }); + ops++; + + // Scrypt (recommended for new apps) + if (i % 3 === 0) { + await new Promise((resolve, reject) => { + crypto.scrypt( + password, + salt, + 64, + { N: 1024, r: 8, p: 1 }, + (err, key) => { + if (err) reject(err); + else resolve(key); + }, + ); + }); + ops++; + } + } + return ops; +} + +// Workload 9: HKDF (key derivation for encryption key rotation) +async function workloadHKDF(iterations) { + let ops = 0; + const ikm = crypto.randomBytes(32); + const salt = crypto.randomBytes(32); + const info = Buffer.from('encryption-key-v1'); + + for (let i = 0; i < iterations; i++) { + await new Promise((resolve, reject) => { + crypto.hkdf('sha256', ikm, salt, info, 32, (err, key) => { + if (err) reject(err); + else resolve(key); + }); + }); + ops++; + } + return ops; +} + +// Workload 10: WebCrypto API (increasingly used in modern Node.js) +async function workloadWebCrypto(iterations) { + let ops = 0; + + // Generate WebCrypto key + const key = await subtle.generateKey( + { name: 'AES-GCM', length: 256 }, + false, + ['encrypt', 'decrypt'], + ); + + const hmacKey = await subtle.generateKey( + { name: 'HMAC', hash: 'SHA-256' }, + false, + ['sign', 'verify'], + ); + + for (let i = 0; i < iterations; i++) { + const data = DATA_SIZES[i % 3]; // Keep data smaller for WebCrypto + const iv = crypto.randomBytes(12); + + // AES-GCM encrypt/decrypt via WebCrypto + const encrypted = await subtle.encrypt({ name: 'AES-GCM', iv }, key, data); + await subtle.decrypt({ name: 'AES-GCM', iv }, key, encrypted); + ops += 2; + + // HMAC sign/verify via WebCrypto + const sig = await subtle.sign('HMAC', hmacKey, data); + await subtle.verify('HMAC', hmacKey, sig, data); + ops += 2; + + // SHA-256 digest via WebCrypto + await subtle.digest('SHA-256', data); + ops++; + } + return ops; +} + +// Workload 11: DH key exchange (TLS handshake simulation) +function workloadDH(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + // ECDH key exchange (used in every TLS connection) + const alice = crypto.createECDH('prime256v1'); + const bob = crypto.createECDH('prime256v1'); + + alice.generateKeys(); + bob.generateKeys(); + + const aliceSecret = alice.computeSecret(bob.getPublicKey()); + bob.computeSecret(alice.getPublicKey()); + + // Derive encryption key from shared secret + crypto.createHash('sha256').update(aliceSecret).digest(); + ops++; + } + return ops; +} + +async function main() { + console.log('[pgo-crypto] Starting crypto workload...'); + const startTime = Date.now(); + let totalOps = 0; + let round = 0; + + const remaining = () => DURATION_MS - (Date.now() - startTime); + + while (remaining() > 0) { + round++; + const scale = Math.max(0.1, remaining() / DURATION_MS); + const iterScale = (base) => Math.max(1, Math.floor(base * scale)); + + // Sync workloads (weighted by real-world frequency) + if (round === 1) console.log('[pgo-crypto] Running hash workloads...'); + totalOps += workloadHashing(iterScale(500)); + if (remaining() <= 0) break; + + if (round === 1) console.log('[pgo-crypto] Running HMAC workloads...'); + totalOps += workloadHMAC(iterScale(300)); + if (remaining() <= 0) break; + + if (round === 1) console.log('[pgo-crypto] Running AES-GCM workloads...'); + totalOps += workloadAESGCM(iterScale(200)); + if (remaining() <= 0) break; + + if (round === 1) console.log('[pgo-crypto] Running random generation...'); + totalOps += workloadRandom(iterScale(500)); + if (remaining() <= 0) break; + + if (round === 1) console.log('[pgo-crypto] Running RSA sign/verify...'); + totalOps += workloadRSASignVerify(iterScale(30)); + if (remaining() <= 0) break; + + if (round === 1) console.log('[pgo-crypto] Running ECDSA sign/verify...'); + totalOps += workloadECDSA(iterScale(100)); + if (remaining() <= 0) break; + + if (round === 1) console.log('[pgo-crypto] Running Ed25519 sign/verify...'); + totalOps += workloadEd25519(iterScale(100)); + if (remaining() <= 0) break; + + if (round === 1) console.log('[pgo-crypto] Running DH key exchange...'); + totalOps += workloadDH(iterScale(30)); + if (remaining() <= 0) break; + + // Async workloads + if (round === 1) + console.log('[pgo-crypto] Running password hashing (async)...'); + totalOps += await workloadPasswordHashing(iterScale(20)); + if (remaining() <= 0) break; + + if (round === 1) console.log('[pgo-crypto] Running HKDF (async)...'); + totalOps += await workloadHKDF(iterScale(50)); + if (remaining() <= 0) break; + + if (round === 1) console.log('[pgo-crypto] Running WebCrypto workloads...'); + totalOps += await workloadWebCrypto(iterScale(50)); + } + + const elapsed = (Date.now() - startTime) / 1000; + console.log( + `[pgo-crypto] Completed ${totalOps} crypto operations in ${elapsed.toFixed(1)}s (${(totalOps / elapsed).toFixed(0)} ops/s) [${round} rounds]`, + ); +} + +main().catch((err) => { + console.error('[pgo-crypto] Error:', err); + process.exit(1); +}); diff --git a/tools/pgo/pgo-fs.js b/tools/pgo/pgo-fs.js new file mode 100644 index 000000000000..6e0a9e05f0b4 --- /dev/null +++ b/tools/pgo/pgo-fs.js @@ -0,0 +1,447 @@ +'use strict'; + +// PGO Training Script: File System Operations +// +// Exercises the most common fs operations in Node.js applications: +// - readFile/writeFile (config loading, template rendering, static file serving) +// - stat/access (file existence checks, middleware, caching) +// - readdir (directory listings, file discovery, build tools) +// - read/write streams (log file appending, file upload/download) +// - mkdir/rmdir (temp directories, build artifacts) +// - path operations (resolve, join, parse — used constantly) +// - watch (file watchers in dev tools, though we only test creation here) +// +// This exercises: libuv filesystem operations, thread pool (async fs), +// Buffer allocation for file data, string encoding, path module. + +const fs = require('fs'); +const fsp = require('fs/promises'); +const path = require('path'); +const os = require('os'); +const crypto = require('crypto'); + +const DURATION_MS = parseInt(process.env.PGO_TRAINING_DURATION, 10) || 15_000; + +// Create a unique temp directory for our operations +const TEMP_DIR = path.join( + os.tmpdir(), + `node-pgo-fs-${process.pid}-${Date.now()}`, +); + +// Test data +const MEDIUM_CONTENT = Array.from( + { length: 100 }, + (_, i) => `Line ${i}: ${crypto.randomBytes(40).toString('hex')}`, +).join('\n'); +const LARGE_CONTENT = crypto.randomBytes(256 * 1024).toString('base64'); +const JSON_CONFIG = JSON.stringify( + { + database: { + host: 'localhost', + port: 5432, + name: 'myapp', + pool: { min: 2, max: 10 }, + }, + redis: { host: 'localhost', port: 6379, db: 0 }, + server: { port: 3000, host: '0.0.0.0', cors: { origin: '*' } }, + logging: { level: 'info', format: 'json', outputs: ['stdout', 'file'] }, + features: { darkMode: true, betaFeatures: false, maxUploadSize: 10485760 }, + }, + null, + 2, +); + +function setup() { + fs.mkdirSync(TEMP_DIR, { recursive: true }); + fs.mkdirSync(path.join(TEMP_DIR, 'subdir', 'nested'), { recursive: true }); + fs.mkdirSync(path.join(TEMP_DIR, 'logs'), { recursive: true }); + fs.mkdirSync(path.join(TEMP_DIR, 'uploads'), { recursive: true }); + fs.mkdirSync(path.join(TEMP_DIR, 'cache'), { recursive: true }); + + // Pre-create files for reading + for (let i = 0; i < 50; i++) { + fs.writeFileSync( + path.join(TEMP_DIR, `file-${i}.txt`), + `Content of file ${i}\n`.repeat(10), + ); + } + for (let i = 0; i < 10; i++) { + fs.writeFileSync( + path.join(TEMP_DIR, 'subdir', `sub-${i}.json`), + JSON.stringify({ id: i, data: `value-${i}` }), + ); + } + fs.writeFileSync(path.join(TEMP_DIR, 'config.json'), JSON_CONFIG); + fs.writeFileSync(path.join(TEMP_DIR, 'large.dat'), LARGE_CONTENT); + fs.writeFileSync(path.join(TEMP_DIR, 'medium.txt'), MEDIUM_CONTENT); +} + +function cleanup() { + try { + fs.rmSync(TEMP_DIR, { recursive: true, force: true }); + } catch { + // Best effort cleanup + } +} + +// Workload 1: readFile + writeFile (async, the dominant pattern) +async function workloadReadWriteAsync(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + // Read config file (very common — Express/Fastify load configs at startup) + await fsp.readFile(path.join(TEMP_DIR, 'config.json'), 'utf8'); + ops++; + + // Read and parse JSON config + const configStr = await fsp.readFile( + path.join(TEMP_DIR, 'config.json'), + 'utf8', + ); + JSON.parse(configStr); + ops++; + + // Read binary file (static file serving) + await fsp.readFile(path.join(TEMP_DIR, `file-${i % 50}.txt`)); + ops++; + + // Write new file (log rotation, temp files, uploads) + const tempFile = path.join(TEMP_DIR, 'uploads', `upload-${i}.tmp`); + await fsp.writeFile( + tempFile, + `Upload content ${i}: ${crypto.randomBytes(100).toString('hex')}`, + ); + ops++; + + // Read back + await fsp.readFile(tempFile, 'utf8'); + ops++; + + // Overwrite (atomic-ish update pattern) + await fsp.writeFile(tempFile, `Updated content ${i}`); + ops++; + + // Read large file (less frequently) + if (i % 10 === 0) { + await fsp.readFile(path.join(TEMP_DIR, 'large.dat')); + ops++; + } + } + return ops; +} + +// Workload 2: readFileSync + writeFileSync (startup, require.resolve) +function workloadReadWriteSync(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + // Sync read (very common in require() for package.json, .json configs) + fs.readFileSync(path.join(TEMP_DIR, 'config.json'), 'utf8'); + ops++; + + // Sync read various files + fs.readFileSync(path.join(TEMP_DIR, `file-${i % 50}.txt`), 'utf8'); + ops++; + + // Sync JSON file read/parse (package.json pattern) + for (let j = 0; j < 10; j++) { + const content = fs.readFileSync( + path.join(TEMP_DIR, 'subdir', `sub-${j}.json`), + 'utf8', + ); + JSON.parse(content); + } + ops += 10; + + // Sync write (cache files, lock files) + const cacheFile = path.join(TEMP_DIR, 'cache', `cache-${i % 20}.json`); + fs.writeFileSync( + cacheFile, + JSON.stringify({ key: `key-${i}`, value: i * 42, ts: Date.now() }), + ); + ops++; + } + return ops; +} + +// Workload 3: stat / access / exists (file existence checks) +async function workloadStatAccess(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + // stat (used by express.static, require.resolve, etc.) + await fsp.stat(path.join(TEMP_DIR, `file-${i % 50}.txt`)); + ops++; + + // stat directory + await fsp.stat(path.join(TEMP_DIR, 'subdir')); + ops++; + + // Access check (permission verification) + try { + await fsp.access( + path.join(TEMP_DIR, `file-${i % 50}.txt`), + fs.constants.R_OK, + ); + } catch { + /* expected for some */ + } + ops++; + + // lstat (symlink-aware, used by tools) + await fsp.lstat(path.join(TEMP_DIR, `file-${i % 50}.txt`)); + ops++; + + // Stat non-existent (cache miss pattern) + try { + await fsp.stat(path.join(TEMP_DIR, `nonexistent-${i}.txt`)); + } catch { + /* expected */ + } + ops++; + + // Sync variants (require.resolve uses these) + fs.statSync(path.join(TEMP_DIR, `file-${i % 50}.txt`)); + ops++; + + fs.existsSync(path.join(TEMP_DIR, `file-${i % 50}.txt`)); + ops++; + + fs.existsSync(path.join(TEMP_DIR, `nonexistent-${i}.txt`)); + ops++; + } + return ops; +} + +// Workload 4: readdir (directory listing, build tools, file watchers) +async function workloadReaddir(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + // Simple readdir + await fsp.readdir(TEMP_DIR); + ops++; + + // Readdir with file types (common for file tree traversal) + await fsp.readdir(TEMP_DIR, { withFileTypes: true }); + ops++; + + // Readdir subdirectory + await fsp.readdir(path.join(TEMP_DIR, 'subdir'), { withFileTypes: true }); + ops++; + + // Sync variant (build tools) + fs.readdirSync(TEMP_DIR); + ops++; + + // Recursive readdir (newer API, gaining adoption) + if (i % 5 === 0) { + await fsp.readdir(TEMP_DIR, { recursive: true }); + ops++; + } + } + return ops; +} + +// Workload 5: mkdir / rmdir / rename / copy (build tool patterns) +async function workloadDirectoryOps(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + const dir = path.join(TEMP_DIR, `build-${i}`); + + // mkdir (build output directories) + await fsp.mkdir(dir, { recursive: true }); + ops++; + + // Create file in new dir + const file = path.join(dir, 'output.txt'); + await fsp.writeFile(file, `Build output ${i}`); + ops++; + + // Rename (atomic file update pattern) + const newFile = path.join(dir, 'output.final.txt'); + await fsp.rename(file, newFile); + ops++; + + // Copy file + const copyDest = path.join(dir, 'output.backup.txt'); + await fsp.copyFile(newFile, copyDest); + ops++; + + // rmdir (cleanup) + await fsp.rm(dir, { recursive: true, force: true }); + ops++; + } + return ops; +} + +// Workload 6: Stream read/write (large file processing, log files) +async function workloadStreams(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + // Read stream (file download, static serving of large files) + await new Promise((resolve, reject) => { + const rs = fs.createReadStream(path.join(TEMP_DIR, 'large.dat'), { + highWaterMark: 16 * 1024, + }); + rs.on('data', () => {}); + rs.on('end', () => { + ops++; + resolve(); + }); + rs.on('error', reject); + }); + + // Write stream (log file appending) + await new Promise((resolve, reject) => { + const ws = fs.createWriteStream( + path.join(TEMP_DIR, 'logs', `app-${i % 5}.log`), + { flags: 'a' }, + ); + for (let j = 0; j < 50; j++) { + ws.write( + `[${new Date().toISOString()}] INFO: Request processed in ${Math.random() * 100}ms\n`, + ); + } + ws.end(() => { + ops++; + resolve(); + }); + ws.on('error', reject); + }); + + // Pipe pattern (file copy via streams) + if (i % 3 === 0) { + await new Promise((resolve, reject) => { + const rs = fs.createReadStream(path.join(TEMP_DIR, 'medium.txt')); + const ws = fs.createWriteStream( + path.join(TEMP_DIR, `pipe-copy-${i}.txt`), + ); + rs.pipe(ws); + ws.on('finish', () => { + ops++; + resolve(); + }); + ws.on('error', reject); + }); + } + } + return ops; +} + +// Workload 7: Path operations (used in every file operation) +function workloadPathOps(iterations) { + let ops = 0; + const testPaths = [ + '/usr/local/lib/node_modules/express/lib/router/index.js', + 'C:\\Users\\user\\project\\node_modules\\lodash\\lodash.js', + '../relative/path/to/file.js', + './src/components/Button/index.tsx', + 'https://example.com/path/to/resource?query=value#hash', + '/path/with spaces/and (parens)/file name.txt', + ]; + + for (let i = 0; i < iterations; i++) { + for (const p of testPaths) { + path.resolve(p); + path.dirname(p); + path.basename(p); + path.extname(p); + path.parse(p); + path.normalize(p); + path.isAbsolute(p); + ops += 7; + } + + // path.join (the most common path operation) + path.join('src', 'components', 'Button', 'index.tsx'); + path.join(TEMP_DIR, 'subdir', 'nested', 'file.txt'); + path.join('..', '..', 'node_modules', '.cache'); + ops += 3; + + // path.relative (monorepo/build tool pattern) + path.relative( + '/project/packages/core/src', + '/project/packages/utils/src/helpers.js', + ); + path.relative(TEMP_DIR, path.join(TEMP_DIR, 'subdir', 'file.txt')); + ops += 2; + + // path.format (inverse of parse) + path.format({ + root: '/', + dir: '/home/user', + base: 'file.txt', + ext: '.txt', + name: 'file', + }); + ops++; + } + return ops; +} + +async function main() { + console.log('[pgo-fs] Starting file system workload...'); + + setup(); + const startTime = Date.now(); + let totalOps = 0; + let round = 0; + const remaining = () => DURATION_MS - (Date.now() - startTime); + + try { + while (remaining() > 0) { + round++; + const scale = Math.max(0.1, remaining() / DURATION_MS); + const iterScale = (base) => Math.max(1, Math.floor(base * scale)); + + // Path ops first — pure CPU, exercises V8 string handling + if (round === 1) console.log('[pgo-fs] Running path operations...'); + totalOps += workloadPathOps(iterScale(2000)); + if (remaining() <= 0) break; + + // Sync reads (startup/require pattern) + if (round === 1) console.log('[pgo-fs] Running sync read/write...'); + totalOps += workloadReadWriteSync(iterScale(100)); + if (remaining() <= 0) break; + + // Async reads/writes (most common runtime pattern) + if (round === 1) console.log('[pgo-fs] Running async read/write...'); + totalOps += await workloadReadWriteAsync(iterScale(50)); + if (remaining() <= 0) break; + + // stat/access (middleware, require.resolve) + if (round === 1) console.log('[pgo-fs] Running stat/access...'); + totalOps += await workloadStatAccess(iterScale(100)); + if (remaining() <= 0) break; + + // Directory operations + if (round === 1) console.log('[pgo-fs] Running readdir...'); + totalOps += await workloadReaddir(iterScale(100)); + if (remaining() <= 0) break; + + if (round === 1) console.log('[pgo-fs] Running directory ops...'); + totalOps += await workloadDirectoryOps(iterScale(30)); + if (remaining() <= 0) break; + + // Stream operations + if (round === 1) console.log('[pgo-fs] Running stream read/write...'); + totalOps += await workloadStreams(iterScale(20)); + } + + const elapsed = (Date.now() - startTime) / 1000; + console.log( + `[pgo-fs] Completed ${totalOps} fs operations in ${elapsed.toFixed(1)}s (${(totalOps / elapsed).toFixed(0)} ops/s) [${round} rounds]`, + ); + } finally { + cleanup(); + } +} + +main().catch((err) => { + console.error('[pgo-fs] Error:', err); + cleanup(); + process.exit(1); +}); diff --git a/tools/pgo/pgo-http-server.js b/tools/pgo/pgo-http-server.js new file mode 100644 index 000000000000..0950bfbff50d --- /dev/null +++ b/tools/pgo/pgo-http-server.js @@ -0,0 +1,380 @@ +'use strict'; + +// PGO Training Script: HTTP Server Workload +// +// Simulates the most common Node.js use case — an HTTP server handling: +// - JSON REST API requests (GET/POST with JSON bodies) +// - Static content serving (HTML, CSS, JS responses) +// - Chunked transfer encoding +// - Various header patterns (few/many headers, Set-Cookie, CORS) +// - Keep-alive connections with request pipelining +// - URL routing with path parameters and query strings +// +// This exercises: llhttp parser, TCP stack (libuv), header serialization, +// Buffer encoding, URL parsing, JSON parse/stringify, EventEmitter, streams. + +const http = require('http'); +const { URL } = require('url'); +const crypto = require('crypto'); + +const DURATION_MS = parseInt(process.env.PGO_TRAINING_DURATION, 10) || 15_000; +const CONCURRENT_CLIENTS = 20; +const PORT = 0; // OS-assigned + +// Realistic JSON payloads of varying sizes +const SMALL_JSON = JSON.stringify({ id: 1, name: 'test', active: true }); +const MEDIUM_JSON = JSON.stringify({ + users: Array.from({ length: 50 }, (_, i) => ({ + id: i, + name: `user_${i}`, + email: `user${i}@example.com`, + age: 20 + (i % 40), + active: i % 3 !== 0, + tags: ['tag1', 'tag2', 'tag3'], + address: { + street: `${i * 100} Main St`, + city: 'Anytown', + state: 'CA', + zip: `${90000 + i}`, + }, + })), + total: 50, + page: 1, + perPage: 50, +}); +const LARGE_JSON = JSON.stringify({ + data: Array.from({ length: 500 }, (_, i) => ({ + id: crypto.randomUUID(), + timestamp: new Date().toISOString(), + type: ['click', 'view', 'purchase', 'signup'][i % 4], + properties: { + source: ['web', 'mobile', 'api'][i % 3], + browser: ['chrome', 'firefox', 'safari', 'edge'][i % 4], + os: ['windows', 'macos', 'linux', 'ios', 'android'][i % 5], + duration: Math.random() * 10000, + amount: i % 4 === 2 ? (Math.random() * 500).toFixed(2) : undefined, + items: + i % 4 === 2 ? + Array.from({ length: 3 }, (_, j) => ({ + sku: `SKU-${j}-${i}`, + qty: j + 1, + price: (Math.random() * 100).toFixed(2), + })) : + undefined, + }, + metadata: { + ip: `192.168.${i % 256}.${(i * 7) % 256}`, + userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', + sessionId: crypto.randomUUID(), + }, + })), +}); + +// Simulated HTML page +const HTML_PAGE = ` + + + + + App + + + +
+ + +`; + +// Simulated CSS +const CSS_CONTENT = `body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; } +.container { max-width: 1200px; margin: 0 auto; padding: 0 20px; } +.header { background: #1a1a2e; color: white; padding: 1rem 0; } +.nav { display: flex; gap: 1rem; } +.card { border: 1px solid #ddd; border-radius: 8px; padding: 1rem; margin: 1rem 0; } +.btn { display: inline-block; padding: 0.5rem 1rem; border-radius: 4px; cursor: pointer; } +.btn-primary { background: #0066cc; color: white; } +@media (max-width: 768px) { .container { padding: 0 10px; } }`; + +// Simulated JS bundle (minified-ish) +const JS_BUNDLE = + `!function(){"use strict";` + + 'const e=document.getElementById("root");' + + 'function t(e,t){return Object.assign(document.createElement(e),t)}' + + Array.from( + { length: 100 }, + (_, i) => + `function c${i}(d){return t("div",{className:"c${i}",textContent:JSON.stringify(d)})}`, + ).join(';') + + '}();'; + +function handleRequest(req, res) { + const url = new URL(req.url, `http://localhost`); + const path = url.pathname; + const method = req.method; + + // CORS headers (very common in REST APIs) + res.setHeader('Access-Control-Allow-Origin', '*'); + res.setHeader( + 'Access-Control-Allow-Methods', + 'GET, POST, PUT, DELETE, OPTIONS', + ); + res.setHeader('X-Request-Id', crypto.randomUUID()); + + if (method === 'OPTIONS') { + res.writeHead(204); + res.end(); + return; + } + + // REST API routes + if (path === '/api/users' && method === 'GET') { + const page = url.searchParams.get('page') || '1'; + const limit = url.searchParams.get('limit') || '50'; + res.writeHead(200, { + 'Content-Type': 'application/json', + 'X-Page': page, + 'X-Limit': limit, + 'X-Total': '500', + 'Cache-Control': 'no-cache', + }); + res.end(MEDIUM_JSON); + return; + } + + if (path === '/api/events' && method === 'POST') { + let body = ''; + req.on('data', (chunk) => { + body += chunk; + }); + req.on('end', () => { + try { + const parsed = JSON.parse(body); + const response = JSON.stringify({ + status: 'accepted', + count: Array.isArray(parsed) ? parsed.length : 1, + timestamp: new Date().toISOString(), + }); + res.writeHead(202, { + 'Content-Type': 'application/json', + 'Content-Length': Buffer.byteLength(response), + }); + res.end(response); + } catch { + res.writeHead(400, { 'Content-Type': 'application/json' }); + res.end('{"error":"Invalid JSON"}'); + } + }); + return; + } + + if (path === '/api/analytics' && method === 'GET') { + // Chunked response (common for large datasets) + res.writeHead(200, { + 'Content-Type': 'application/json', + 'Transfer-Encoding': 'chunked', + }); + res.write(LARGE_JSON.slice(0, 4096)); + res.write(LARGE_JSON.slice(4096, 8192)); + res.write(LARGE_JSON.slice(8192)); + res.end(); + return; + } + + if (path.startsWith('/api/users/') && method === 'GET') { + const userId = path.split('/')[3]; + const user = JSON.stringify({ + id: userId, + name: `User ${userId}`, + email: `user${userId}@example.com`, + createdAt: new Date().toISOString(), + profile: { bio: 'A sample user', avatar: '/img/default.png' }, + }); + res.writeHead(200, { + 'Content-Type': 'application/json', + 'ETag': `"${crypto.createHash('md5').update(user).digest('hex')}"`, + 'Cache-Control': 'max-age=60', + }); + res.end(user); + return; + } + + if (path === '/health') { + res.writeHead(200, { 'Content-Type': 'application/json' }); + res.end(SMALL_JSON); + return; + } + + // Static content routes + if (path === '/' || path === '/index.html') { + res.writeHead(200, { + 'Content-Type': 'text/html; charset=utf-8', + 'Content-Length': Buffer.byteLength(HTML_PAGE), + 'Cache-Control': 'public, max-age=3600', + }); + res.end(HTML_PAGE); + return; + } + + if (path === '/styles.css') { + res.writeHead(200, { + 'Content-Type': 'text/css', + 'Content-Length': Buffer.byteLength(CSS_CONTENT), + 'Cache-Control': 'public, max-age=86400', + }); + res.end(CSS_CONTENT); + return; + } + + if (path === '/app.js') { + res.writeHead(200, { + 'Content-Type': 'application/javascript', + 'Content-Length': Buffer.byteLength(JS_BUNDLE), + 'Cache-Control': 'public, max-age=86400', + }); + res.end(JS_BUNDLE); + return; + } + + // Set-Cookie responses (common for auth) + if (path === '/api/login' && method === 'POST') { + req.on('data', () => {}); + req.on('end', () => { + const token = crypto.randomBytes(32).toString('hex'); + res.writeHead(200, { + 'Content-Type': 'application/json', + 'Set-Cookie': [ + `token=${token}; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=3600`, + `session=${crypto.randomUUID()}; HttpOnly; Path=/`, + ], + }); + res.end(JSON.stringify({ token, expiresIn: 3600 })); + }); + return; + } + + // 404 + res.writeHead(404, { 'Content-Type': 'application/json' }); + res.end('{"error":"Not Found"}'); +} + +// Request patterns that clients will cycle through +const REQUEST_PATTERNS = [ + // Weight distribution reflects real API usage + { method: 'GET', path: '/api/users?page=1&limit=50', weight: 20 }, + { + method: 'GET', + path: '/api/users?page=2&limit=25&sort=name&order=asc', + weight: 10, + }, + { method: 'GET', path: '/api/users/123', weight: 15 }, + { method: 'GET', path: '/api/users/456', weight: 10 }, + { method: 'GET', path: '/api/analytics', weight: 5 }, + { method: 'GET', path: '/health', weight: 15 }, + { method: 'GET', path: '/', weight: 8 }, + { method: 'GET', path: '/styles.css', weight: 4 }, + { method: 'GET', path: '/app.js', weight: 4 }, + { + method: 'POST', + path: '/api/events', + body: JSON.stringify([ + { type: 'click', target: 'button', timestamp: Date.now() }, + { type: 'view', page: '/dashboard', timestamp: Date.now() }, + ]), + weight: 5, + }, + { + method: 'POST', + path: '/api/login', + body: '{"email":"test@example.com","password":"pass123"}', + weight: 3, + }, + { method: 'OPTIONS', path: '/api/users', weight: 1 }, +]; + +// Build weighted selection array +const weightedPatterns = []; +for (const pattern of REQUEST_PATTERNS) { + for (let i = 0; i < pattern.weight; i++) { + weightedPatterns.push(pattern); + } +} + +function makeRequest(port, pattern) { + return new Promise((resolve, reject) => { + const options = { + hostname: '127.0.0.1', + port, + path: pattern.path, + method: pattern.method, + headers: { + 'Host': 'localhost', + 'User-Agent': 'PGO-Training/1.0', + 'Accept': 'application/json, text/html', + 'Accept-Encoding': 'identity', + 'Connection': 'keep-alive', + }, + }; + + if (pattern.body) { + options.headers['Content-Type'] = 'application/json'; + options.headers['Content-Length'] = Buffer.byteLength(pattern.body); + } + + const req = http.request(options, (res) => { + let data = ''; + res.on('data', (chunk) => { + data += chunk; + }); + res.on('end', () => + resolve({ status: res.statusCode, size: data.length }), + ); + }); + req.on('error', reject); + if (pattern.body) req.write(pattern.body); + req.end(); + }); +} + +async function runClient(port, endTime) { + let requests = 0; + const agent = new http.Agent({ keepAlive: true, maxSockets: 2 }); + + while (Date.now() < endTime) { + const pattern = + weightedPatterns[Math.floor(Math.random() * weightedPatterns.length)]; + try { + await makeRequest(port, pattern); + requests++; + } catch { + // Instrumented builds are slow; brief pause on error + await new Promise((r) => setTimeout(r, 10)); + } + } + agent.destroy(); + return requests; +} + +async function main() { + const server = http.createServer(handleRequest); + + await new Promise((resolve) => server.listen(PORT, '127.0.0.1', resolve)); + const port = server.address().port; + console.log(`[pgo-http-server] Server listening on port ${port}`); + + const endTime = Date.now() + DURATION_MS; + const clients = Array.from({ length: CONCURRENT_CLIENTS }, () => + runClient(port, endTime), + ); + const results = await Promise.all(clients); + const totalRequests = results.reduce((a, b) => a + b, 0); + + server.close(); + console.log( + `[pgo-http-server] Completed ${totalRequests} requests in ${DURATION_MS / 1000}s (${(totalRequests / (DURATION_MS / 1000)).toFixed(0)} req/s)`, + ); +} + +main().catch((err) => { + console.error('[pgo-http-server] Error:', err); + process.exit(1); +}); diff --git a/tools/pgo/pgo-json.js b/tools/pgo/pgo-json.js new file mode 100644 index 000000000000..203d746f7716 --- /dev/null +++ b/tools/pgo/pgo-json.js @@ -0,0 +1,341 @@ +'use strict'; + +// PGO Training Script: JSON Processing Workload +// +// JSON.parse() and JSON.stringify() are among the most frequently called +// functions in Node.js applications (every REST API request/response cycle). +// This script exercises the JSON parser and serializer with: +// - Small objects (API responses, config) +// - Medium objects (paginated lists, user profiles) +// - Large objects (analytics payloads, data exports) +// - Nested structures (deep objects, arrays of objects) +// - Various value types (strings, numbers, booleans, null, arrays, objects) +// - Edge cases (unicode, escaped characters, large numbers, empty objects) +// - Realistic patterns: parse → transform → stringify pipeline +// +// This exercises: V8 JSON parser, V8 JSON serializer, string allocation, +// property access patterns, array iteration, GC pressure from allocations. + +const DURATION_MS = parseInt(process.env.PGO_TRAINING_DURATION, 10) || 15_000; +const ITERATIONS_PER_BATCH = 500; + +// Realistic JSON payloads matching common API shapes + +// 1. Small config/health check (~100 bytes) +const SMALL_PAYLOADS = [ + '{"status":"ok","uptime":12345,"version":"1.0.0"}', + '{"id":42,"name":"test","active":true,"score":98.5}', + '{"error":null,"data":{"key":"value"},"meta":{}}', + '{"token":"abc123def456","expires":1700000000}', + '{"success":true,"count":0,"items":[]}', +]; + +// 2. Medium user/product objects (~1-5 KB) +function generateUserPayload(count) { + const users = []; + for (let i = 0; i < count; i++) { + users.push({ + id: `usr_${i.toString(36).padStart(8, '0')}`, + email: `user${i}@company.example.com`, + name: { first: `First${i}`, last: `Last${i}` }, + role: ['admin', 'editor', 'viewer', 'member'][i % 4], + permissions: ['read', 'write', 'delete', 'admin'].slice(0, (i % 4) + 1), + settings: { + theme: i % 2 === 0 ? 'dark' : 'light', + language: ['en', 'es', 'fr', 'de', 'ja'][i % 5], + notifications: { email: true, push: i % 3 !== 0, sms: false }, + timezone: 'America/New_York', + }, + metadata: { + createdAt: '2024-01-15T08:30:00.000Z', + updatedAt: '2024-12-01T14:22:33.456Z', + lastLogin: '2024-12-15T09:45:00.000Z', + loginCount: 100 + i * 7, + }, + }); + } + return JSON.stringify({ data: users, total: count, page: 1, perPage: count }); +} + +// 3. Large analytics/event payloads (~50-200 KB) +function generateEventPayload(count) { + const events = []; + for (let i = 0; i < count; i++) { + events.push({ + id: `evt_${Date.now()}_${i}`, + type: [ + 'page_view', + 'click', + 'form_submit', + 'api_call', + 'error', + 'purchase', + ][i % 6], + timestamp: new Date(Date.now() - i * 60000).toISOString(), + session: `sess_${Math.floor(i / 10)}`, + user: i % 5 === 0 ? null : `usr_${i % 100}`, + properties: { + url: `https://example.com/page/${i % 20}?ref=dashboard&utm_source=email`, + title: `Page Title ${i % 20} — Application Dashboard`, + referrer: i % 3 === 0 ? 'https://google.com/search?q=test' : '', + duration: Math.round(Math.random() * 30000), + viewport: { width: 1920, height: 1080 }, + device: { + type: ['desktop', 'mobile', 'tablet'][i % 3], + os: ['Windows 11', 'macOS 14', 'iOS 17', 'Android 14'][i % 4], + browser: ['Chrome 120', 'Firefox 121', 'Safari 17'][i % 3], + }, + }, + context: { + ip: `10.${i % 256}.${(i * 3) % 256}.${(i * 7) % 256}`, + locale: ['en-US', 'en-GB', 'es-ES', 'fr-FR', 'de-DE'][i % 5], + campaign: + i % 10 === 0 ? + { name: 'holiday_sale', medium: 'email', source: 'mailchimp' } : + null, + }, + }); + } + return JSON.stringify({ + events, + batch_id: `batch_${Date.now()}`, + sent_at: new Date().toISOString(), + }); +} + +// 4. Deeply nested structure (config files, GraphQL responses) +function generateNestedPayload(depth, breadth) { + function nest(d) { + if (d === 0) return { value: 'leaf', count: 42, tags: ['a', 'b'] }; + const obj = {}; + for (let i = 0; i < breadth; i++) { + obj[`level_${d}_key_${i}`] = nest(d - 1); + } + return obj; + } + return JSON.stringify({ root: nest(depth), _meta: { depth, breadth } }); +} + +// 5. Array-heavy payload (table data, CSV-like) +function generateTablePayload(rows, cols) { + const headers = Array.from({ length: cols }, (_, i) => `column_${i}`); + const data = []; + for (let r = 0; r < rows; r++) { + const row = {}; + for (let c = 0; c < cols; c++) { + row[headers[c]] = + c % 3 === 0 ? r * c : c % 3 === 1 ? `val_${r}_${c}` : r % 2 === 0; + } + data.push(row); + } + return JSON.stringify({ headers, data, rowCount: rows }); +} + +// 6. Unicode-heavy payload (i18n content) +const UNICODE_PAYLOAD = JSON.stringify({ + messages: { + en: { greeting: 'Hello, World!', farewell: 'Goodbye!' }, + ja: { greeting: 'こんにちは世界!', farewell: 'さようなら!' }, + ko: { greeting: '안녕하세요 세계!', farewell: '안녕히 가세요!' }, + zh: { greeting: '你好世界!', farewell: '再见!' }, + ar: { greeting: 'مرحبا بالعالم!', farewell: 'مع السلامة!' }, + ru: { greeting: 'Привет мир!', farewell: 'До свидания!' }, + de: { greeting: 'Hallo Welt!', farewell: 'Auf Wiedersehen!' }, + emoji: { greeting: '👋🌍✨', farewell: '👋😢💫' }, + }, + descriptions: Array.from( + { length: 50 }, + (_, i) => + `Item ${i}: Ünîcödé tëst with spëcîal chars — «quotes» "double" 'single' & ampersand \\ backslash / slash`, + ), +}); + +// Pre-generate payloads as strings +const mediumPayload10 = generateUserPayload(10); +const mediumPayload50 = generateUserPayload(50); +const largePayload100 = generateEventPayload(100); +const largePayload500 = generateEventPayload(500); +const nestedPayload = generateNestedPayload(5, 3); +const tablePayload = generateTablePayload(200, 15); + +// All payloads weighted by real-world frequency +const PAYLOADS = [ + // Small payloads (health checks, simple responses) - most frequent + ...SMALL_PAYLOADS.map((p) => ({ json: p, weight: 5 })), + // Medium payloads (typical API responses) + { json: mediumPayload10, weight: 8 }, + { json: mediumPayload50, weight: 6 }, + // Large payloads (analytics, batch operations) + { json: largePayload100, weight: 3 }, + { json: largePayload500, weight: 1 }, + // Nested payloads (config, GraphQL) + { json: nestedPayload, weight: 2 }, + // Table payloads (data grids, reports) + { json: tablePayload, weight: 2 }, + // Unicode payloads (i18n) + { json: UNICODE_PAYLOAD, weight: 2 }, +]; + +const weightedPayloads = []; +for (const p of PAYLOADS) { + for (let i = 0; i < p.weight; i++) { + weightedPayloads.push(p.json); + } +} + +// Workload 1: Parse → access properties → stringify (REST API middleware pattern) +function workloadParseTransformStringify(jsonStr) { + const obj = JSON.parse(jsonStr); + + // Typical middleware transforms + if (obj.data && Array.isArray(obj.data)) { + // Add computed field (common API pattern) + for (const item of obj.data) { + item._computed = + typeof item.id === 'string' ? item.id.toUpperCase() : String(item.id); + } + } + if (obj.events && Array.isArray(obj.events)) { + // Filter/transform (analytics pipeline) + obj.events = obj.events.filter((e) => e.type !== 'error'); + obj.filteredCount = obj.events.length; + } + + return JSON.stringify(obj); +} + +// Workload 2: Parse → extract subset → stringify (GraphQL resolver pattern) +function workloadSelectiveSerialize(jsonStr) { + const obj = JSON.parse(jsonStr); + const subset = {}; + + // Pick only requested fields (like GraphQL field selection) + for (const key of Object.keys(obj)) { + if (typeof obj[key] !== 'object' || obj[key] === null) { + subset[key] = obj[key]; + } else if (Array.isArray(obj[key]) && obj[key].length > 0) { + subset[key] = obj[key].slice(0, 5).map((item) => { + if (typeof item === 'object' && item !== null) { + const { id, name, type, email } = item; + return { id, name, type, email }; + } + return item; + }); + } + } + + return JSON.stringify(subset); +} + +// Workload 3: Repeated parse/stringify of same shape (template response caching pattern) +function workloadRepeatedShapes() { + const results = []; + for (let i = 0; i < 100; i++) { + const obj = { + id: i, + name: `Item ${i}`, + description: `Description for item ${i} with some additional text`, + price: (i * 1.5).toFixed(2), + inStock: i % 3 !== 0, + categories: ['cat1', 'cat2'], + ratings: { average: 4.5, count: i * 10 }, + }; + results.push(JSON.stringify(obj)); + } + // Parse them all back + return results.map((s) => JSON.parse(s)); +} + +// Workload 4: JSON.parse with reviver / JSON.stringify with replacer +function workloadReviverReplacer(jsonStr) { + // Parse with date reviver (common pattern) + const dateReviver = (key, value) => { + if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T/.test(value)) { + return new Date(value); + } + return value; + }; + const obj = JSON.parse(jsonStr, dateReviver); + + // Stringify with replacer to exclude nulls (sanitization) + const nullRemover = (key, value) => (value === null ? undefined : value); + return JSON.stringify(obj, nullRemover); +} + +// Workload 5: Build large JSON incrementally (logging, audit trail) +function workloadIncrementalBuild() { + const entries = []; + for (let i = 0; i < 200; i++) { + entries.push({ + level: ['info', 'warn', 'error', 'debug'][i % 4], + message: `Log entry ${i}: Operation completed successfully with result code ${i * 3}`, + timestamp: Date.now() - i * 1000, + context: { requestId: `req_${i}`, userId: `user_${i % 20}` }, + }); + } + const logBatch = JSON.stringify({ entries, count: entries.length }); + // Verify round-trip + const parsed = JSON.parse(logBatch); + return parsed.count; +} + +async function main() { + console.log('[pgo-json] Starting JSON processing workload...'); + const startTime = Date.now(); + let totalOps = 0; + let batchNum = 0; + + while (Date.now() - startTime < DURATION_MS) { + batchNum++; + + // Workload 1: Parse-transform-stringify (highest weight — most common) + for (let i = 0; i < ITERATIONS_PER_BATCH; i++) { + const payload = weightedPayloads[i % weightedPayloads.length]; + workloadParseTransformStringify(payload); + totalOps++; + } + + // Workload 2: Selective serialization + for (let i = 0; i < Math.floor(ITERATIONS_PER_BATCH / 2); i++) { + const payload = weightedPayloads[i % weightedPayloads.length]; + workloadSelectiveSerialize(payload); + totalOps++; + } + + // Workload 3: Repeated shapes (every 3rd batch) + if (batchNum % 3 === 0) { + workloadRepeatedShapes(); + totalOps += 200; // 100 stringify + 100 parse + } + + // Workload 4: Reviver/replacer (every 2nd batch) + if (batchNum % 2 === 0) { + for (let i = 0; i < 50; i++) { + const payload = weightedPayloads[i % weightedPayloads.length]; + workloadReviverReplacer(payload); + totalOps++; + } + } + + // Workload 5: Incremental build (every 5th batch) + if (batchNum % 5 === 0) { + workloadIncrementalBuild(); + totalOps += 201; // 200 items + 1 round-trip + } + + // Yield to event loop periodically (realistic for servers) + if (batchNum % 10 === 0) { + await new Promise((resolve) => setImmediate(resolve)); + } + } + + const elapsed = (Date.now() - startTime) / 1000; + console.log( + `[pgo-json] Completed ${totalOps} JSON operations in ${elapsed.toFixed(1)}s (${(totalOps / elapsed).toFixed(0)} ops/s)`, + ); +} + +main().catch((err) => { + console.error('[pgo-json] Error:', err); + process.exit(1); +}); diff --git a/tools/pgo/pgo-module-loading.js b/tools/pgo/pgo-module-loading.js new file mode 100644 index 000000000000..ffb11706ba91 --- /dev/null +++ b/tools/pgo/pgo-module-loading.js @@ -0,0 +1,719 @@ +'use strict'; + +/* eslint-disable no-void */ + +// PGO Training Script: Module Loading and Startup +// +// Module loading (require/import) is one of Node.js's most performance-critical +// paths, especially for: +// - Application startup time (serverless cold starts, CLI tools) +// - require() resolution algorithm (stat cascade, package.json parsing) +// - ESM vs CJS loading (import() dynamic imports) +// - Circular dependency resolution +// - Built-in module loading +// - JSON module loading (package.json, config files) +// +// This exercises: module resolver (fs.stat/readFile cascade), V8 script +// compilation, source code parsing, JSON parsing, path resolution, +// module wrapper function, exports/require machinery. + +const path = require('path'); +const fs = require('fs'); +const os = require('os'); +const vm = require('vm'); +const Module = require('module'); + +const DURATION_MS = parseInt(process.env.PGO_TRAINING_DURATION, 10) || 15_000; +const TEMP_DIR = path.join( + os.tmpdir(), + `node-pgo-module-${process.pid}-${Date.now()}`, +); + +function setup() { + fs.mkdirSync(TEMP_DIR, { recursive: true }); + + // Create a realistic module tree + // node_modules/ + // express/ + // package.json + // index.js + // lib/router.js, lib/request.js, lib/response.js + // lodash/ + // package.json + // lodash.js + // config/ + // package.json + // index.js + // src/ + // index.js, utils.js, helpers.js, constants.js + // models/user.js, models/product.js + // middleware/auth.js, middleware/logger.js + + const dirs = [ + 'node_modules/express/lib', + 'node_modules/lodash', + 'node_modules/config', + 'node_modules/debug', + 'node_modules/body-parser', + 'src/models', + 'src/middleware', + 'src/routes', + 'src/utils', + 'lib', + ]; + + for (const dir of dirs) { + fs.mkdirSync(path.join(TEMP_DIR, dir), { recursive: true }); + } + + // Express-like module + writeFile( + 'node_modules/express/package.json', + JSON.stringify({ + name: 'express', + version: '4.18.2', + main: 'index.js', + }), + ); + writeFile( + 'node_modules/express/index.js', + ` + 'use strict'; + const router = require('./lib/router'); + const request = require('./lib/request'); + const response = require('./lib/response'); + function createApp() { + const app = { routes: [], use(fn) { this.routes.push(fn); return this; } }; + Object.assign(app, router, request, response); + return app; + } + module.exports = createApp; + module.exports.Router = router.Router; + module.exports.static = function(root) { return function(req, res, next) { next(); }; }; + `, + ); + writeFile( + 'node_modules/express/lib/router.js', + ` + 'use strict'; + class Router { constructor() { this.stack = []; } route(path) { return this; } } + exports.Router = function() { return new Router(); }; + exports.handle = function(req, res) {}; + exports.param = function(name, fn) {}; + `, + ); + writeFile( + 'node_modules/express/lib/request.js', + ` + 'use strict'; + exports.get = function(field) { return ''; }; + exports.accepts = function() { return true; }; + exports.is = function(type) { return type; }; + `, + ); + writeFile( + 'node_modules/express/lib/response.js', + ` + 'use strict'; + exports.send = function(body) { return this; }; + exports.json = function(obj) { return this; }; + exports.status = function(code) { return this; }; + `, + ); + + // Lodash-like module + writeFile( + 'node_modules/lodash/package.json', + JSON.stringify({ + name: 'lodash', + version: '4.17.21', + main: 'lodash.js', + }), + ); + writeFile( + 'node_modules/lodash/lodash.js', + ` + 'use strict'; + const _ = {}; + _.map = (arr, fn) => arr.map(fn); + _.filter = (arr, fn) => arr.filter(fn); + _.reduce = (arr, fn, init) => arr.reduce(fn, init); + _.get = (obj, path, def) => { const keys = path.split('.'); let val = obj; for (const k of keys) { val = val?.[k]; } return val ?? def; }; + _.set = (obj, path, val) => { const keys = path.split('.'); let cur = obj; for (let i = 0; i < keys.length - 1; i++) { cur = cur[keys[i]] ??= {}; } cur[keys[keys.length-1]] = val; return obj; }; + _.cloneDeep = (obj) => JSON.parse(JSON.stringify(obj)); + _.debounce = (fn, wait) => { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), wait); }; }; + _.chunk = (arr, size) => { const res = []; for (let i = 0; i < arr.length; i += size) res.push(arr.slice(i, i + size)); return res; }; + _.flatten = (arr) => arr.flat(); + _.uniq = (arr) => [...new Set(arr)]; + module.exports = _; + `, + ); + + // Config module + writeFile( + 'node_modules/config/package.json', + JSON.stringify({ + name: 'config', + version: '3.3.9', + main: 'index.js', + }), + ); + writeFile( + 'node_modules/config/index.js', + ` + 'use strict'; + const config = { db: { host: 'localhost', port: 5432 }, app: { port: 3000 } }; + module.exports = { get(key) { return key.split('.').reduce((o, k) => o?.[k], config); }, has(key) { return this.get(key) !== undefined; } }; + `, + ); + + // Debug module + writeFile( + 'node_modules/debug/package.json', + JSON.stringify({ + name: 'debug', + version: '4.3.4', + main: 'index.js', + }), + ); + writeFile( + 'node_modules/debug/index.js', + ` + 'use strict'; + module.exports = function(namespace) { + return function(...args) { /* noop in production */ }; + }; + `, + ); + + // Body-parser module + writeFile( + 'node_modules/body-parser/package.json', + JSON.stringify({ + name: 'body-parser', + version: '1.20.2', + main: 'index.js', + }), + ); + writeFile( + 'node_modules/body-parser/index.js', + ` + 'use strict'; + exports.json = function(options) { return function(req, res, next) { next(); }; }; + exports.urlencoded = function(options) { return function(req, res, next) { next(); }; }; + exports.raw = function(options) { return function(req, res, next) { next(); }; }; + `, + ); + + // Application source files + writeFile( + 'src/index.js', + ` + 'use strict'; + const express = require('express'); + const bodyParser = require('body-parser'); + const debug = require('debug'); + const config = require('config'); + const { authenticate } = require('./middleware/auth'); + const { logger } = require('./middleware/logger'); + const userRoutes = require('./routes/users'); + const { formatDate, generateId } = require('./utils/helpers'); + const { ROLES, STATUS } = require('./utils/constants'); + module.exports = { express, bodyParser, debug, config, authenticate, logger, userRoutes, formatDate, generateId, ROLES, STATUS }; + `, + ); + + writeFile( + 'src/utils/helpers.js', + ` + 'use strict'; + const crypto = require('crypto'); + exports.formatDate = (d) => new Date(d).toISOString(); + exports.generateId = () => crypto.randomUUID(); + exports.sanitize = (str) => str.replace(/[<>&"']/g, ''); + exports.paginate = (arr, page, size) => arr.slice((page - 1) * size, page * size); + `, + ); + + writeFile( + 'src/utils/constants.js', + ` + 'use strict'; + exports.ROLES = Object.freeze({ ADMIN: 'admin', USER: 'user', GUEST: 'guest' }); + exports.STATUS = Object.freeze({ ACTIVE: 'active', INACTIVE: 'inactive', PENDING: 'pending' }); + exports.LIMITS = Object.freeze({ MAX_PAGE_SIZE: 100, MAX_UPLOAD: 10 * 1024 * 1024 }); + `, + ); + + writeFile( + 'src/models/user.js', + ` + 'use strict'; + const { generateId } = require('../utils/helpers'); + const { ROLES, STATUS } = require('../utils/constants'); + class User { constructor(data) { this.id = generateId(); this.role = ROLES.USER; this.status = STATUS.PENDING; Object.assign(this, data); } toJSON() { return { id: this.id, name: this.name, role: this.role }; } } + module.exports = User; + `, + ); + + writeFile( + 'src/models/product.js', + ` + 'use strict'; + const { generateId } = require('../utils/helpers'); + class Product { constructor(data) { this.id = generateId(); Object.assign(this, data); } toJSON() { return { id: this.id, name: this.name, price: this.price }; } } + module.exports = Product; + `, + ); + + writeFile( + 'src/middleware/auth.js', + ` + 'use strict'; + const crypto = require('crypto'); + exports.authenticate = function(req, res, next) { const token = req?.headers?.authorization; return !!token; }; + exports.authorize = function(...roles) { return function(req, res, next) { return roles.length > 0; }; }; + `, + ); + + writeFile( + 'src/middleware/logger.js', + ` + 'use strict'; + exports.logger = function(req, res, next) { + const start = Date.now(); + return { duration: Date.now() - start, method: req?.method, url: req?.url }; + }; + `, + ); + + writeFile( + 'src/routes/users.js', + ` + 'use strict'; + const User = require('../models/user'); + const { paginate } = require('../utils/helpers'); + const { authenticate } = require('../middleware/auth'); + exports.getUsers = function(page, size) { return paginate([], page, size); }; + exports.createUser = function(data) { return new User(data); }; + exports.getUser = function(id) { return null; }; + `, + ); + + // ESM modules + writeFile( + 'src/esm-entry.mjs', + ` + import { createRequire } from 'module'; + import { fileURLToPath } from 'url'; + import { dirname, join } from 'path'; + const __filename = fileURLToPath(import.meta.url); + const __dirname = dirname(__filename); + const require = createRequire(import.meta.url); + export const config = { loaded: true, dir: __dirname }; + export function greet(name) { return \`Hello, \${name}!\`; } + export default { config, greet }; + `, + ); + + // JSON file (loaded as module) + writeFile( + 'config/default.json', + JSON.stringify( + { + server: { port: 3000, host: '0.0.0.0' }, + database: { + url: 'postgres://localhost:5432/myapp', + pool: { min: 2, max: 10 }, + }, + redis: { url: 'redis://localhost:6379' }, + jwt: { secret: 'test-secret', expiresIn: '1h' }, + logging: { level: 'info' }, + }, + null, + 2, + ), + ); + + // package.json at root + writeFile( + 'package.json', + JSON.stringify( + { + name: 'pgo-test-app', + version: '1.0.0', + main: 'src/index.js', + dependencies: { + 'express': '^4.18.0', + 'lodash': '^4.17.0', + 'config': '^3.3.0', + 'debug': '^4.3.0', + 'body-parser': '^1.20.0', + }, + }, + null, + 2, + ), + ); +} + +function writeFile(relPath, content) { + const fullPath = path.join(TEMP_DIR, relPath); + fs.mkdirSync(path.dirname(fullPath), { recursive: true }); + fs.writeFileSync(fullPath, content); +} + +function cleanup() { + try { + fs.rmSync(TEMP_DIR, { recursive: true, force: true }); + } catch { + // best effort + } +} + +// Workload 1: require() with full resolution (CJS — the dominant pattern) +function workloadCJSRequire(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + // Clear module cache to force re-resolution + const keys = Object.keys(require.cache).filter((k) => + k.startsWith(TEMP_DIR), + ); + for (const key of keys) { + delete require.cache[key]; + } + + // Require the full app (cascading dependencies) + require(path.join(TEMP_DIR, 'src', 'index.js')); + ops++; + + // Require individual modules + require(path.join(TEMP_DIR, 'node_modules', 'lodash', 'lodash.js')); + require(path.join(TEMP_DIR, 'src', 'models', 'user.js')); + require(path.join(TEMP_DIR, 'src', 'models', 'product.js')); + ops += 3; + + // JSON require (package.json resolution) + delete require.cache[path.join(TEMP_DIR, 'package.json')]; + require(path.join(TEMP_DIR, 'package.json')); + delete require.cache[path.join(TEMP_DIR, 'config', 'default.json')]; + require(path.join(TEMP_DIR, 'config', 'default.json')); + ops += 2; + } + return ops; +} + +// Workload 2: Built-in module loading (no resolution needed, but exercises native binding) +function workloadBuiltinRequire(iterations) { + let ops = 0; + const builtins = [ + 'fs', + 'path', + 'http', + 'https', + 'crypto', + 'os', + 'url', + 'util', + 'events', + 'stream', + 'buffer', + 'net', + 'dns', + 'zlib', + 'child_process', + 'querystring', + 'string_decoder', + 'timers', + 'assert', + 'tls', + 'fs/promises', + 'stream/promises', + 'timers/promises', + 'node:fs', + 'node:path', + 'node:http', + 'node:crypto', + 'node:os', + ]; + + for (let i = 0; i < iterations; i++) { + for (const mod of builtins) { + require(mod); + } + ops += builtins.length; + } + return ops; +} + +// Workload 3: Module.createRequire and resolution +function workloadModuleResolution(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + // createRequire (used in ESM ↔ CJS interop) + const customRequire = Module.createRequire( + path.join(TEMP_DIR, 'src', 'index.js'), + ); + + // Resolve module paths (this is the hot path in require()) + try { + customRequire.resolve('express'); + } catch { + // expected + } + try { + customRequire.resolve('lodash'); + } catch { + // expected + } + try { + customRequire.resolve('./models/user'); + } catch { + // expected + } + try { + customRequire.resolve('../package.json'); + } catch { + // expected + } + ops += 4; + + // Module._resolveFilename (internal but exercises the same path) + try { + Module._resolveFilename('fs'); + } catch { + // expected + } + try { + Module._resolveFilename('path'); + } catch { + // expected + } + ops += 2; + + // Module.builtinModules + void Module.builtinModules; + ops++; + } + return ops; +} + +// Workload 4: vm.Script compilation (V8 script compilation path) +function workloadVMCompilation(iterations) { + let ops = 0; + + const scripts = [ + // Simple expression + 'const x = 1 + 2; x;', + // Function definition + 'function add(a, b) { return a + b; } add(1, 2);', + // Object manipulation + 'const obj = { a: 1, b: { c: [1, 2, 3] } }; JSON.stringify(obj);', + // Loop + 'let sum = 0; for (let i = 0; i < 1000; i++) sum += i; sum;', + // Async-like pattern + 'const p = Promise.resolve(42); p.then(v => v * 2);', + // Class definition (modern JS) + `class Foo { constructor(x) { this.x = x; } get value() { return this.x; } } + const f = new Foo(42); f.value;`, + // Destructuring + spread + 'const { a, b, ...rest } = { a: 1, b: 2, c: 3, d: 4 }; [a, b, ...Object.values(rest)];', + // Map/Set + 'const m = new Map([[1,"a"],[2,"b"]]); const s = new Set([1,2,3]); m.size + s.size;', + // Regex + 'const re = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/; re.test("test@example.com");', + // Template literals + // eslint-disable-next-line no-template-curly-in-string + 'const name = "World"; const greeting = `Hello, ${name}! Today is ${new Date().toISOString()}`; greeting;', + ]; + + for (let i = 0; i < iterations; i++) { + for (const code of scripts) { + const script = new vm.Script(code, { + filename: `script-${i}.js`, + produceCachedData: i % 5 === 0, // Some with code caching + }); + + const context = vm.createContext({ + JSON, + Date, + Promise, + Map, + Set, + console, + }); + script.runInContext(context, { timeout: 1000 }); + ops++; + } + } + return ops; +} + +// Workload 5: Dynamic import() (ESM loading — growing usage) +async function workloadDynamicImport(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + // Dynamic import of built-in modules (common in ESM code) + await import('node:fs'); + await import('node:path'); + await import('node:crypto'); + await import('node:os'); + await import('node:util'); + await import('node:url'); + await import('node:events'); + await import('node:stream'); + ops += 8; + } + return ops; +} + +// Workload 6: Module._compile simulation (exercises V8 compilation) +function workloadCompilePatterns(iterations) { + let ops = 0; + + // Source code patterns that exercise different V8 compilation paths + const sourcePatterns = [ + // Arrow functions (very common in modern JS) + 'module.exports = {\n' + + Array.from( + { length: 20 }, + (_, i) => ` fn${i}: (x) => x * ${i + 1},`, + ).join('\n') + + '\n};', + + // async/await (extremely common in server code) + `module.exports = async function(data) { + const result = await Promise.resolve(data); + const items = await Promise.all( + Array.from({length: 10}, (_, i) => Promise.resolve(i * 2)) + ); + return { result, items, total: items.reduce((a,b) => a+b, 0) }; + };`, + + // try/catch with specific error types + `module.exports = function(input) { + try { + const data = JSON.parse(input); + if (!data.id) throw new TypeError('Missing id'); + if (data.age < 0) throw new RangeError('Invalid age'); + return data; + } catch (err) { + if (err instanceof SyntaxError) return { error: 'Invalid JSON' }; + if (err instanceof TypeError) return { error: err.message }; + throw err; + } + };`, + + // Generator function (used in Koa, some ORMs) + `module.exports = function* paginate(items, pageSize) { + for (let i = 0; i < items.length; i += pageSize) { + yield items.slice(i, i + pageSize); + } + };`, + + // Proxy/Reflect (used in Vue.js reactivity, ORMs) + `module.exports = function createReactive(target) { + return new Proxy(target, { + get(obj, prop) { return Reflect.get(obj, prop); }, + set(obj, prop, value) { return Reflect.set(obj, prop, value); }, + has(obj, prop) { return Reflect.has(obj, prop); }, + }); + };`, + ]; + + for (let i = 0; i < iterations; i++) { + for (const source of sourcePatterns) { + const script = new vm.Script( + `(function(exports, require, module, __filename, __dirname) { ${source} })`, + { filename: `compile-${i}.js` }, + ); + const context = vm.createContext({ + JSON, + Promise, + Array, + Object, + Map, + Set, + Proxy, + Reflect, + TypeError, + RangeError, + SyntaxError, + Error, + }); + script.runInContext(context); + ops++; + } + } + return ops; +} + +async function main() { + console.log('[pgo-module-loading] Starting module loading workload...'); + + setup(); + const startTime = Date.now(); + let totalOps = 0; + let round = 0; + + const remaining = () => DURATION_MS - (Date.now() - startTime); + + try { + while (remaining() > 0) { + round++; + const scale = Math.max(0.1, remaining() / DURATION_MS); + const iterScale = (base) => Math.max(1, Math.floor(base * scale)); + + // CJS require (the most common module operation) + if (round === 1) + console.log('[pgo-module-loading] Running CJS require...'); + totalOps += workloadCJSRequire(iterScale(100)); + if (remaining() <= 0) break; + + // Built-in module loading + if (round === 1) + console.log('[pgo-module-loading] Running built-in require...'); + totalOps += workloadBuiltinRequire(iterScale(200)); + if (remaining() <= 0) break; + + // Module resolution + if (round === 1) + console.log('[pgo-module-loading] Running module resolution...'); + totalOps += workloadModuleResolution(iterScale(200)); + if (remaining() <= 0) break; + + // VM compilation + if (round === 1) + console.log('[pgo-module-loading] Running VM compilation...'); + totalOps += workloadVMCompilation(iterScale(50)); + if (remaining() <= 0) break; + + // Compilation patterns + if (round === 1) + console.log('[pgo-module-loading] Running compile patterns...'); + totalOps += workloadCompilePatterns(iterScale(100)); + if (remaining() <= 0) break; + + // Dynamic import + if (round === 1) + console.log('[pgo-module-loading] Running dynamic import...'); + totalOps += await workloadDynamicImport(iterScale(50)); + } + + const elapsed = (Date.now() - startTime) / 1000; + console.log( + `[pgo-module-loading] Completed ${totalOps} ops in ${elapsed.toFixed(1)}s (${(totalOps / elapsed).toFixed(0)} ops/s) [${round} rounds]`, + ); + } finally { + cleanup(); + } +} + +main().catch((err) => { + console.error('[pgo-module-loading] Error:', err); + cleanup(); + process.exit(1); +}); diff --git a/tools/pgo/pgo-net.js b/tools/pgo/pgo-net.js new file mode 100644 index 000000000000..7f98fbd7723a --- /dev/null +++ b/tools/pgo/pgo-net.js @@ -0,0 +1,443 @@ +'use strict'; + +/* eslint-disable no-void */ + +// PGO Training Script: Network (TCP) and DNS +// +// Exercises the core networking primitives used by every HTTP server/client: +// - TCP server/client (the foundation of HTTP) +// - DNS resolution (every outbound connection) +// - Connection pooling patterns (keep-alive, max sockets) +// - Various data transfer patterns (small messages, large payloads, streaming) +// - Unix domain sockets / named pipes on Windows (IPC) +// +// This exercises: libuv TCP/pipe handles, DNS resolver (c-ares), +// socket state machine, Buffer transfers, EventEmitter for net events. + +const net = require('net'); +const dns = require('dns'); +const os = require('os'); +const path = require('path'); +const crypto = require('crypto'); + +const DURATION_MS = parseInt(process.env.PGO_TRAINING_DURATION, 10) || 15_000; +const PORT_TCP = 0; // OS-assigned + +// Test payloads simulating real protocols +const SMALL_MSG = Buffer.from('{"type":"ping","ts":1234567890}\n'); +const MEDIUM_MSG = Buffer.from( + JSON.stringify({ + type: 'data', + payload: Array.from({ length: 100 }, (_, i) => ({ + key: `item_${i}`, + value: crypto.randomBytes(16).toString('hex'), + })), + }) + '\n', +); +const LARGE_MSG = crypto.randomBytes(64 * 1024); + +// Workload 1: TCP echo server with concurrent clients +async function workloadTCPEcho(duration) { + let totalOps = 0; + + const server = net.createServer((socket) => { + socket.on('data', (data) => { + // Echo back with a small transformation (realistic: add header/length prefix) + const response = Buffer.concat([Buffer.from(`${data.length}:`), data]); + socket.write(response); + }); + socket.on('error', () => {}); + }); + + await new Promise((resolve) => server.listen(PORT_TCP, '127.0.0.1', resolve)); + const port = server.address().port; + + const endTime = Date.now() + duration; + + async function runClient() { + let ops = 0; + while (Date.now() < endTime) { + await new Promise((resolve) => { + const client = net.createConnection({ port, host: '127.0.0.1' }, () => { + let msgsSent = 0; + const maxMsgs = 50; + + function sendNext() { + if (msgsSent >= maxMsgs || Date.now() >= endTime) { + client.end(); + return; + } + // Vary message sizes (realistic: mostly small, some medium, rare large) + const r = Math.random(); + const msg = r < 0.7 ? SMALL_MSG : r < 0.95 ? MEDIUM_MSG : LARGE_MSG; + client.write(msg); + msgsSent++; + ops++; + } + + client.on('data', () => { + sendNext(); + }); + sendNext(); + }); + + client.on('end', resolve); + client.on('error', () => resolve()); + client.setTimeout(2000, () => { + client.destroy(); + resolve(); + }); + }); + } + return ops; + } + + const clients = Array.from({ length: 10 }, () => runClient()); + const results = await Promise.all(clients); + totalOps = results.reduce((a, b) => a + b, 0); + + server.close(); + return totalOps; +} + +// Workload 2: TCP request/response (HTTP-like pattern without HTTP overhead) +async function workloadTCPRequestResponse(duration) { + let totalOps = 0; + + const server = net.createServer((socket) => { + let buffer = ''; + socket.on('data', (data) => { + buffer += data.toString(); + // Simple line-delimited protocol (like Redis, memcached) + const lines = buffer.split('\n'); + buffer = lines.pop() || ''; + + for (const line of lines) { + if (!line) continue; + try { + const req = JSON.parse(line); + let response; + + switch (req.cmd) { + case 'GET': + response = { + status: 'ok', + key: req.key, + value: 'cached_value_' + req.key, + }; + break; + case 'SET': + response = { status: 'ok', key: req.key }; + break; + case 'DEL': + response = { status: 'ok', deleted: 1 }; + break; + case 'MGET': + response = { + status: 'ok', + values: req.keys.map((k) => 'val_' + k), + }; + break; + default: + response = { status: 'error', message: 'Unknown command' }; + } + socket.write(JSON.stringify(response) + '\n'); + } catch { + socket.write('{"status":"error","message":"Parse error"}\n'); + } + } + }); + socket.on('error', () => {}); + }); + + await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve)); + const port = server.address().port; + + const endTime = Date.now() + duration; + + async function runClient() { + let ops = 0; + while (Date.now() < endTime) { + await new Promise((resolve) => { + const client = net.createConnection({ port, host: '127.0.0.1' }, () => { + let pending = 0; + const maxOps = 100; + + function sendNext() { + if (pending >= maxOps || Date.now() >= endTime) { + client.end(); + return; + } + + const commands = [ + { cmd: 'GET', key: `user:${pending}` }, + { + cmd: 'SET', + key: `session:${pending}`, + value: crypto.randomUUID(), + }, + { cmd: 'MGET', keys: ['key1', 'key2', 'key3'] }, + { cmd: 'DEL', key: `temp:${pending}` }, + ]; + const cmd = commands[pending % commands.length]; + client.write(JSON.stringify(cmd) + '\n'); + pending++; + ops++; + } + + client.on('data', () => { + sendNext(); + }); + sendNext(); + }); + + client.on('end', resolve); + client.on('error', () => resolve()); + client.setTimeout(2000, () => { + client.destroy(); + resolve(); + }); + }); + } + return ops; + } + + const clients = Array.from({ length: 8 }, () => runClient()); + const results = await Promise.all(clients); + totalOps = results.reduce((a, b) => a + b, 0); + + server.close(); + return totalOps; +} + +// Workload 3: Named pipe / IPC (very common on Windows - VS Code, build tools) +async function workloadIPC(duration) { + let totalOps = 0; + const pipePath = + process.platform === 'win32' ? + `\\\\.\\pipe\\node-pgo-${process.pid}-${Date.now()}` : + path.join(os.tmpdir(), `node-pgo-ipc-${process.pid}.sock`); + + const server = net.createServer((socket) => { + socket.on('data', (data) => { + // IPC protocol: length-prefixed messages + const msg = JSON.parse(data.toString()); + const response = { + id: msg.id, + result: msg.method === 'eval' ? 'ok' : 'unknown', + data: { processed: true, timestamp: Date.now() }, + }; + const buf = Buffer.from(JSON.stringify(response)); + socket.write(buf); + }); + socket.on('error', () => {}); + }); + + await new Promise((resolve) => server.listen(pipePath, resolve)); + + const endTime = Date.now() + duration; + + async function runClient() { + let ops = 0; + while (Date.now() < endTime) { + await new Promise((resolve) => { + const client = net.createConnection(pipePath, () => { + let count = 0; + const maxMsgs = 50; + + function sendNext() { + if (count >= maxMsgs || Date.now() >= endTime) { + client.end(); + return; + } + const msg = { + id: count, + method: ['eval', 'complete', 'lint', 'format'][count % 4], + params: { file: `src/file${count}.ts`, line: count * 2 }, + }; + client.write(JSON.stringify(msg)); + count++; + ops++; + } + + client.on('data', () => sendNext()); + sendNext(); + }); + + client.on('end', resolve); + client.on('error', () => resolve()); + client.setTimeout(2000, () => { + client.destroy(); + resolve(); + }); + }); + } + return ops; + } + + const clients = Array.from({ length: 4 }, () => runClient()); + const results = await Promise.all(clients); + totalOps = results.reduce((a, b) => a + b, 0); + + server.close(); + // Cleanup socket file on Unix + if (process.platform !== 'win32') { + try { + require('fs').unlinkSync(pipePath); + } catch { + // best effort + } + } + return totalOps; +} + +// Workload 4: DNS resolution (every HTTP client connection does this) +async function workloadDNS(iterations) { + let ops = 0; + + // Use localhost and standard DNS patterns + const hosts = ['localhost', '127.0.0.1', '::1']; + + for (let i = 0; i < iterations; i++) { + // dns.lookup (uses OS resolver — libuv thread pool) + for (const host of hosts) { + try { + await new Promise((resolve, reject) => { + dns.lookup(host, (err, address) => { + if (err) reject(err); + else resolve(address); + }); + }); + ops++; + } catch { + ops++; + } + } + + // dns.lookup with options (IPv4/IPv6 preference) + try { + await new Promise((resolve, reject) => { + dns.lookup('localhost', { family: 4 }, (err, address) => { + if (err) reject(err); + else resolve(address); + }); + }); + ops++; + } catch { + ops++; + } + + // dns.lookupService (reverse lookup) + try { + await new Promise((resolve, reject) => { + dns.lookupService('127.0.0.1', 80, (err, hostname, service) => { + if (err) reject(err); + else resolve({ hostname, service }); + }); + }); + ops++; + } catch { + ops++; + } + + // net.isIP / net.isIPv4 / net.isIPv6 (validation in every request) + net.isIP('192.168.1.1'); + net.isIP('::1'); + net.isIP('not-an-ip'); + net.isIPv4('192.168.1.1'); + net.isIPv6('::1'); + net.isIPv6('fe80::1%eth0'); + ops += 6; + } + return ops; +} + +// Workload 5: Socket options and state transitions +async function workloadSocketOps(duration) { + let totalOps = 0; + + const server = net.createServer((socket) => { + // Exercise socket properties (common in logging, monitoring) + void socket.remoteAddress; + void socket.remotePort; + void socket.localAddress; + void socket.localPort; + void socket.bytesRead; + void socket.bytesWritten; + void socket.readyState; + + socket.setNoDelay(true); + socket.setKeepAlive(true, 1000); + + socket.on('data', (data) => { + socket.write(data); + }); + socket.on('error', () => {}); + }); + + await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve)); + const port = server.address().port; + + const endTime = Date.now() + duration; + + // Rapid connect/disconnect (connection churn — load balancer pattern) + while (Date.now() < endTime) { + await new Promise((resolve) => { + const client = net.createConnection({ port, host: '127.0.0.1' }, () => { + client.setNoDelay(true); + client.write('ping'); + }); + client.on('data', () => { + totalOps++; + client.end(); + }); + client.on('end', resolve); + client.on('error', () => resolve()); + client.setTimeout(1000, () => { + client.destroy(); + resolve(); + }); + }); + } + + server.close(); + return totalOps; +} + +async function main() { + console.log('[pgo-net] Starting network workload...'); + const startTime = Date.now(); + let totalOps = 0; + + const timeBudget = (fraction) => Math.floor(DURATION_MS * fraction); + + // TCP echo (data transfer throughput) + console.log('[pgo-net] Running TCP echo...'); + totalOps += await workloadTCPEcho(timeBudget(0.25)); + + // TCP request/response (protocol handling) + console.log('[pgo-net] Running TCP request/response...'); + totalOps += await workloadTCPRequestResponse(timeBudget(0.25)); + + // IPC / Named pipes + console.log('[pgo-net] Running IPC...'); + totalOps += await workloadIPC(timeBudget(0.15)); + + // DNS resolution + console.log('[pgo-net] Running DNS...'); + totalOps += await workloadDNS(100); + + // Socket operations + console.log('[pgo-net] Running socket ops...'); + totalOps += await workloadSocketOps(timeBudget(0.15)); + + const elapsed = (Date.now() - startTime) / 1000; + console.log( + `[pgo-net] Completed ${totalOps} net operations in ${elapsed.toFixed(1)}s (${(totalOps / elapsed).toFixed(0)} ops/s)`, + ); +} + +main().catch((err) => { + console.error('[pgo-net] Error:', err); + process.exit(1); +}); diff --git a/tools/pgo/pgo-run-all.js b/tools/pgo/pgo-run-all.js new file mode 100644 index 000000000000..b654d2a88bce --- /dev/null +++ b/tools/pgo/pgo-run-all.js @@ -0,0 +1,339 @@ +'use strict'; + +// PGO Training Orchestrator: Runs All PGO Training Workloads +// +// This script orchestrates the execution of all PGO training workloads +// sequentially. It is designed to be run against a PGO-instrumented + +// Node.js build to generate profile data (.profraw files on Clang/Clang-CL, +// .gcda files on GCC). +// +// Usage: +// node tools/pgo/pgo-run-all.js [--duration=] [--scripts=] +// +// Options: +// --duration= Duration per script in seconds (default: 15) +// --scripts= Comma-separated list of scripts to run (default: all) +// e.g. --scripts=http-server,json,crypto +// --sequential Run scripts one at a time (default, safest for PGO) +// --verbose Show detailed output from each script +// +// The scripts are ordered by their importance to real-world Node.js usage: +// 1. HTTP Server (~60% of Node.js usage is web servers) +// 2. JSON Processing (every REST API request/response) +// 3. Crypto/TLS (every HTTPS connection) +// 4. Streams/Buffers (all I/O goes through these) +// 5. File System (config loading, static serving, build tools) +// 6. Async Patterns (Promise/async-await is the concurrency model) +// 7. URL/String (URL parsing in every request, string ops everywhere) +// 8. Compression (HTTP response compression) +// 9. Net/DNS (underlying TCP/DNS for all networking) +// 10. Module Loading (startup, require() resolution) +// 11. Child/Workers (build tools, process managers) + +const { fork } = require('child_process'); +const path = require('path'); +const fs = require('fs'); + +const SCRIPT_DIR = __dirname; + +// Training scripts in order of real-world importance +const ALL_SCRIPTS = [ + { + name: 'http-server', + file: 'pgo-http-server.js', + desc: 'HTTP server with JSON APIs, static content, routing', + }, + { + name: 'json', + file: 'pgo-json.js', + desc: 'JSON parse/stringify with realistic payloads', + }, + { + name: 'crypto', + file: 'pgo-crypto.js', + desc: 'Hashing, HMAC, AES-GCM, RSA/ECDSA, random, PBKDF2', + }, + { + name: 'streams-buffers', + file: 'pgo-streams-buffers.js', + desc: 'Buffer creation/encoding, stream pipes, transforms', + }, + { + name: 'fs', + file: 'pgo-fs.js', + desc: 'File read/write, stat, readdir, streams, path ops', + }, + { + name: 'async-patterns', + file: 'pgo-async-patterns.js', + desc: 'Promises, EventEmitter, timers, AbortController, ALS', + }, + { + name: 'url-string', + file: 'pgo-url-string.js', + desc: 'URL parsing, regex, string ops, TextEncoder, util', + }, + { + name: 'compression', + file: 'pgo-compression.js', + desc: 'Gzip, deflate, brotli compress/decompress', + }, + { + name: 'net', + file: 'pgo-net.js', + desc: 'TCP server/client, IPC, DNS resolution', + }, + { + name: 'module-loading', + file: 'pgo-module-loading.js', + desc: 'CJS require, ESM import, VM compilation', + }, + { + name: 'child-workers', + file: 'pgo-child-workers.js', + desc: 'Worker thread messaging, SharedArrayBuffer, inline eval', + }, +]; + +function parseArgs() { + const args = { + duration: 15, + scripts: null, + verbose: false, + }; + + for (const arg of process.argv.slice(2)) { + if (arg.startsWith('--duration=')) { + args.duration = parseInt(arg.split('=')[1], 10); + } else if (arg.startsWith('--scripts=')) { + args.scripts = arg + .split('=')[1] + .split(',') + .map((s) => s.trim()); + } else if (arg === '--verbose') { + args.verbose = true; + } else if (arg === '--help' || arg === '-h') { + console.log(` +PGO Training Orchestrator for Node.js + +Usage: node tools/pgo/pgo-run-all.js [options] + +Options: + --duration= Duration per script (default: 15) + --scripts= Comma-separated script names (default: all) + --verbose Show script output + --help Show this help + +Available scripts: +${ALL_SCRIPTS.map((s) => ` ${s.name.padEnd(20)} ${s.desc}`).join('\n')} + +Example: + node tools/pgo/pgo-run-all.js --duration=20 --verbose + node tools/pgo/pgo-run-all.js --scripts=http-server,json,crypto --duration=30 +`); + process.exit(0); + } + } + + return args; +} + +function runScript(scriptPath, duration, verbose) { + return new Promise((resolve) => { + const env = { + ...process.env, + PGO_TRAINING_DURATION: String(duration * 1000), + }; + const child = fork(scriptPath, [], { + stdio: verbose ? 'inherit' : ['ignore', 'pipe', 'pipe', 'ipc'], + env, + }); + + let output = ''; + if (!verbose && child.stdout) { + child.stdout.on('data', (data) => { + output += data.toString(); + }); + } + if (!verbose && child.stderr) { + child.stderr.on('data', (data) => { + output += data.toString(); + }); + } + + // Safety timeout: kill if script runs too long + const timeout = setTimeout( + () => { + console.log(' [TIMEOUT] Killing script...'); + child.kill('SIGTERM'); + setTimeout(() => child.kill('SIGKILL'), 5000); + }, + (duration + 30) * 1000, + ); + + child.on('exit', (code) => { + clearTimeout(timeout); + if (code !== 0 && code !== null) { + // Extract last line of output for summary + const lastLine = output.trim().split('\n').pop() || ''; + console.log(` [WARNING] Exited with code ${code}: ${lastLine}`); + } + resolve({ code, output }); + }); + + child.on('error', (err) => { + clearTimeout(timeout); + console.log(` [ERROR] ${err.message}`); + resolve({ code: -1, output: err.message }); + }); + }); +} + +async function main() { + const args = parseArgs(); + + // Select scripts + let scripts = ALL_SCRIPTS; + if (args.scripts) { + scripts = args.scripts.map((name) => { + const found = ALL_SCRIPTS.find((s) => s.name === name); + if (!found) { + console.error(`Unknown script: ${name}`); + console.error( + `Available: ${ALL_SCRIPTS.map((s) => s.name).join(', ')}`, + ); + process.exit(1); + } + return found; + }); + } + + const totalTime = scripts.length * args.duration; + + console.log( + '╔══════════════════════════════════════════════════════════════╗', + ); + console.log('║ Node.js PGO Training Workload Runner ║'); + console.log( + '╠══════════════════════════════════════════════════════════════╣', + ); + console.log(`║ Scripts: ${String(scripts.length).padEnd(48)}║`); + console.log( + `║ Duration: ${String(args.duration + 's per script').padEnd(48)}║`, + ); + console.log(`║ Total: ~${String(totalTime + 's estimated').padEnd(47)}║`); + console.log(`║ Node: ${process.version.padEnd(48)}║`); + console.log( + `║ Arch: ${(process.arch + ' / ' + process.platform).padEnd(48)}║`, + ); + console.log( + '╚══════════════════════════════════════════════════════════════╝', + ); + console.log(''); + + const startTime = Date.now(); + const results = []; + + for (let i = 0; i < scripts.length; i++) { + const script = scripts[i]; + const scriptPath = path.join(SCRIPT_DIR, script.file); + const num = `[${i + 1}/${scripts.length}]`; + + console.log(`${num} Running: ${script.name}`); + console.log(` ${script.desc}`); + + const scriptStart = Date.now(); + const result = await runScript(scriptPath, args.duration, args.verbose); + const elapsed = ((Date.now() - scriptStart) / 1000).toFixed(1); + + const status = result.code === 0 ? 'OK' : `FAIL(${result.code})`; + console.log(` Completed in ${elapsed}s [${status}]`); + + // Extract ops/s from output if available + if (!args.verbose && result.output) { + const match = result.output.match(/(\d+) ops\/s|(\d+) req\/s/); + if (match) { + console.log(` Throughput: ${match[0]}`); + } + } + console.log(''); + + results.push({ + name: script.name, + elapsed: parseFloat(elapsed), + code: result.code, + }); + } + + const totalElapsed = ((Date.now() - startTime) / 1000).toFixed(1); + const passed = results.filter((r) => r.code === 0).length; + const failed = results.filter((r) => r.code !== 0).length; + + console.log( + '════════════════════════════════════════════════════════════════', + ); + console.log(`PGO Training Complete: ${totalElapsed}s total`); + console.log( + ` ${passed} passed, ${failed} failed out of ${results.length} scripts`, + ); + + if (failed > 0) { + console.log( + ` Failed: ${results + .filter((r) => r.code !== 0) + .map((r) => r.name) + .join(', ')}`, + ); + } + + // Scan for .profraw files to verify profile data was collected + const profrawDir = process.env.LLVM_PROFILE_FILE ? + path.dirname(process.env.LLVM_PROFILE_FILE.replace(/%[mp]/g, '_')) : + process.cwd(); + let profrawFiles = []; + try { + profrawFiles = fs + .readdirSync(profrawDir) + .filter((f) => f.endsWith('.profraw')); + } catch { + // Directory may not exist if LLVM_PROFILE_FILE points elsewhere + } + + console.log(''); + if (profrawFiles.length > 0) { + let totalSize = 0; + for (const f of profrawFiles) { + try { + totalSize += fs.statSync(path.join(profrawDir, f)).size; + } catch { + // Ignore stat errors + } + } + const sizeMB = (totalSize / (1024 * 1024)).toFixed(1); + console.log( + `Profile data: ${profrawFiles.length} .profraw file(s), ${sizeMB} MB total`, + ); + console.log(` Location: ${profrawDir}`); + } else { + console.log('WARNING: No .profraw files found in ' + profrawDir); + console.log( + ' Ensure LLVM_PROFILE_FILE is set and the binary was built with -fprofile-generate', + ); + } + + console.log(''); + console.log( + 'Profile data should now be available for PGO-optimized rebuild.', + ); + console.log( + '════════════════════════════════════════════════════════════════', + ); + + process.exit(failed > 0 ? 1 : 0); +} + +main().catch((err) => { + console.error('PGO Orchestrator error:', err); + process.exit(1); +}); diff --git a/tools/pgo/pgo-streams-buffers.js b/tools/pgo/pgo-streams-buffers.js new file mode 100644 index 000000000000..6eb970fd97bf --- /dev/null +++ b/tools/pgo/pgo-streams-buffers.js @@ -0,0 +1,579 @@ +'use strict'; + +/* eslint-disable no-void */ + +// PGO Training Script: Streams and Buffers +// +// Buffers and Streams are the backbone of all I/O in Node.js. +// This script exercises: +// - Buffer creation (from, alloc, allocUnsafe — most frequent allocations) +// - Buffer encoding conversion (utf8, base64, hex, latin1 — every HTTP body) +// - Buffer copy, slice, concat, compare, indexOf (data processing) +// - Readable streams (HTTP request bodies, file reads) +// - Writable streams (HTTP responses, file writes) +// - Transform streams (compression, encryption, data pipelines) +// - Pipe chains (the core streaming pattern) +// - Object mode streams (ORMs, data processing libraries) +// - Async iteration over streams (modern pattern) +// +// This exercises: Buffer C++ implementation, stream state machine, +// back-pressure handling, highWaterMark management, GC pressure. + +const { Readable, Writable, Transform, PassThrough } = require('stream'); +const { pipeline: pipelinePromise } = require('stream/promises'); +const { Buffer } = require('buffer'); +const crypto = require('crypto'); + +const DURATION_MS = parseInt(process.env.PGO_TRAINING_DURATION, 10) || 15_000; + +// ============== BUFFER WORKLOADS ============== + +// Workload 1: Buffer creation (the most frequent allocation in Node.js) +function workloadBufferCreation(iterations) { + let ops = 0; + const str = + 'Hello, World! This is a test string for buffer creation benchmarks.'; + const arr = Array.from({ length: 64 }, (_, i) => i); + const uint8 = new Uint8Array(64); + const ab = new ArrayBuffer(64); + + for (let i = 0; i < iterations; i++) { + // Buffer.from string (most common — every HTTP body, every JSON parse input) + Buffer.from(str); + Buffer.from(str, 'utf8'); + Buffer.from(str, 'ascii'); + Buffer.from(str, 'latin1'); + ops += 4; + + // Buffer.from with various source types + Buffer.from(arr); + Buffer.from(uint8); + Buffer.from(ab); + Buffer.from(Buffer.alloc(64)); + ops += 4; + + // Buffer.alloc (zeroed — safe allocation) + Buffer.alloc(16); + Buffer.alloc(256); + Buffer.alloc(4096); + Buffer.alloc(64, 0xff); + ops += 4; + + // Buffer.allocUnsafe (fast allocation — used in hot paths) + Buffer.allocUnsafe(16); + Buffer.allocUnsafe(256); + Buffer.allocUnsafe(4096); + Buffer.allocUnsafe(65536); + ops += 4; + + // Buffer.concat (building response bodies) + const chunks = [ + Buffer.from('chunk1'), + Buffer.from('chunk2'), + Buffer.from('chunk3'), + ]; + Buffer.concat(chunks); + ops++; + } + return ops; +} + +// Workload 2: Buffer encoding/decoding (every HTTP interaction) +function workloadBufferEncoding(iterations) { + let ops = 0; + const testData = crypto.randomBytes(1024); + const testString = + 'The quick brown fox jumps over the lazy dog. 日本語テスト 🎉'; + const base64Data = testData.toString('base64'); + const hexData = testData.toString('hex'); + const base64urlData = testData.toString('base64url'); + + for (let i = 0; i < iterations; i++) { + // UTF-8 encode/decode (dominant encoding for web) + const utf8Buf = Buffer.from(testString, 'utf8'); + utf8Buf.toString('utf8'); + ops += 2; + + // Base64 encode/decode (binary data in JSON, data URIs, email attachments) + testData.toString('base64'); + Buffer.from(base64Data, 'base64'); + ops += 2; + + // Base64url (JWT tokens) + testData.toString('base64url'); + Buffer.from(base64urlData, 'base64url'); + ops += 2; + + // Hex encode/decode (crypto hashes, color codes, debugging) + testData.toString('hex'); + Buffer.from(hexData, 'hex'); + ops += 2; + + // ASCII/Latin1 (HTTP headers, protocol parsing) + Buffer.from( + 'HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n', + 'ascii', + ); + Buffer.from('Set-Cookie: session=abc123; Path=/; HttpOnly', 'latin1'); + ops += 2; + + // Buffer.byteLength (Content-Length header computation) + Buffer.byteLength(testString, 'utf8'); + Buffer.byteLength(base64Data, 'base64'); + Buffer.byteLength('simple ascii text'); + ops += 3; + } + return ops; +} + +// Workload 3: Buffer operations (data processing patterns) +function workloadBufferOps(iterations) { + let ops = 0; + const buf1 = crypto.randomBytes(1024); + const buf2 = crypto.randomBytes(1024); + const needle = Buffer.from('test'); + + for (let i = 0; i < iterations; i++) { + // Buffer.compare (sorting, binary search) + Buffer.compare(buf1, buf2); + buf1.compare(buf2, 0, 100, 0, 100); + ops += 2; + + // Buffer.equals + buf1.equals(buf2); + buf1.equals(buf1); + ops += 2; + + // slice/subarray (zero-copy views — extremely common) + buf1.subarray(0, 256); + buf1.subarray(256, 512); + buf1.subarray(512); + ops += 3; + + // copy (building protocol messages) + const dest = Buffer.allocUnsafe(2048); + buf1.copy(dest, 0); + buf2.copy(dest, 1024); + ops += 2; + + // indexOf / includes (searching in binary data, parsers) + buf1.indexOf(needle); + buf1.includes(65); // ASCII 'A' + buf1.lastIndexOf(0); + ops += 3; + + // fill (clearing sensitive data, initializing) + const fillBuf = Buffer.allocUnsafe(256); + fillBuf.fill(0); + fillBuf.fill('abc'); + ops += 2; + + // Read/write numeric values (protocol parsing, binary formats) + buf1.readUInt32BE(0); + buf1.readUInt32LE(0); + buf1.readInt16BE(4); + buf1.readFloatLE(8); + buf1.readDoubleBE(16); + dest.writeUInt32BE(i, 0); + dest.writeInt16LE(i % 32768, 4); + dest.writeFloatLE(i * 1.5, 8); + ops += 8; + + // swap (endianness conversion) + const swapBuf = Buffer.from(buf1.subarray(0, 64)); + swapBuf.swap16(); + swapBuf.swap32(); + ops += 2; + } + return ops; +} + +// ============== STREAM WORKLOADS ============== + +// Workload 4: Readable → Writable pipe (canonical throughput pattern) +async function workloadPipeChain(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + const chunkCount = 1000; + const chunkSize = 1024; + + await new Promise((resolve) => { + let pushed = 0; + const source = new Readable({ + read() { + if (pushed >= chunkCount) { + this.push(null); + return; + } + this.push(crypto.randomBytes(chunkSize)); + pushed++; + }, + }); + + const sink = new Writable({ + write(chunk, encoding, callback) { + callback(); + }, + }); + + sink.on('finish', () => { + ops += chunkCount; + resolve(); + }); + source.pipe(sink); + }); + } + return ops; +} + +// Workload 5: Transform streams (compression/encryption pattern) +async function workloadTransform(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + await new Promise((resolve) => { + let pushed = 0; + const chunkCount = 500; + const source = new Readable({ + read() { + if (pushed >= chunkCount) { + this.push(null); + return; + } + this.push( + Buffer.from( + `{"id":${pushed},"data":"${crypto.randomBytes(32).toString('hex')}"}\n`, + ), + ); + pushed++; + }, + }); + + // Transform: parse JSON line by line (NDJSON processing pattern) + const transformer = new Transform({ + transform(chunk, encoding, callback) { + const lines = chunk.toString().split('\n').filter(Boolean); + for (const line of lines) { + try { + const obj = JSON.parse(line); + obj.processed = true; + obj.timestamp = Date.now(); + this.push(JSON.stringify(obj) + '\n'); + } catch { + /* skip invalid */ + } + } + callback(); + }, + }); + + const sink = new Writable({ + write(chunk, encoding, callback) { + callback(); + }, + }); + + sink.on('finish', () => { + ops += chunkCount; + resolve(); + }); + source.pipe(transformer).pipe(sink); + }); + } + return ops; +} + +// Workload 6: Object mode streams (database query result processing) +async function workloadObjectMode(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + await new Promise((resolve) => { + let pushed = 0; + const objCount = 200; + + const source = new Readable({ + objectMode: true, + read() { + if (pushed >= objCount) { + this.push(null); + return; + } + this.push({ + id: pushed, + name: `Record ${pushed}`, + value: Math.random() * 1000, + tags: ['tag1', 'tag2'], + metadata: { created: Date.now(), source: 'db' }, + }); + pushed++; + }, + }); + + // Transform: filter + map (like a database cursor) + const filter = new Transform({ + objectMode: true, + transform(obj, encoding, callback) { + if (obj.value > 100) { + callback(null, { + ...obj, + value: Math.round(obj.value * 100) / 100, + qualified: true, + }); + } else { + callback(); + } + }, + }); + + const results = []; + const collect = new Writable({ + objectMode: true, + write(obj, encoding, callback) { + results.push(obj); + callback(); + }, + }); + + collect.on('finish', () => { + ops += objCount; + resolve(); + }); + source.pipe(filter).pipe(collect); + }); + } + return ops; +} + +// Workload 7: Async iteration over streams (modern Node.js pattern) +async function workloadAsyncIteration(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + let pushed = 0; + const chunkCount = 500; + + const source = new Readable({ + read() { + if (pushed >= chunkCount) { + this.push(null); + return; + } + this.push( + Buffer.from( + `Line ${pushed}: ${crypto.randomBytes(20).toString('hex')}\n`, + ), + ); + pushed++; + }, + }); + + let lines = 0; + for await (const chunk of source) { + lines += chunk.toString().split('\n').filter(Boolean).length; + } + ops += lines; + } + return ops; +} + +// Workload 8: pipeline() with error handling (production pattern) +async function workloadPipeline(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + let pushed = 0; + const chunkCount = 300; + + const source = new Readable({ + read() { + if (pushed >= chunkCount) { + this.push(null); + return; + } + this.push(crypto.randomBytes(512)); + pushed++; + }, + }); + + const uppercase = new Transform({ + transform(chunk, encoding, callback) { + callback(null, chunk.toString('hex').toUpperCase()); + }, + }); + + let bytes = 0; + const sink = new Writable({ + write(chunk, encoding, callback) { + bytes += chunk.length; + callback(); + }, + }); + + await pipelinePromise(source, uppercase, sink); + ops += chunkCount; + void bytes; + } + return ops; +} + +// Workload 9: PassThrough / Duplex (proxy patterns, tee) +async function workloadPassThrough(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + let pushed = 0; + const chunkCount = 200; + + const source = new Readable({ + read() { + if (pushed >= chunkCount) { + this.push(null); + return; + } + this.push(crypto.randomBytes(256)); + pushed++; + }, + }); + + // Tee pattern: split stream to two destinations + const pt1 = new PassThrough(); + const pt2 = new PassThrough(); + + let bytes1 = 0; + let bytes2 = 0; + const sink1 = new Writable({ + write(chunk, encoding, callback) { + bytes1 += chunk.length; + callback(); + }, + }); + const sink2 = new Writable({ + write(chunk, encoding, callback) { + bytes2 += chunk.length; + callback(); + }, + }); + + source.pipe(pt1).pipe(sink1); + source.pipe(pt2).pipe(sink2); + + await Promise.all([ + new Promise((r) => sink1.on('finish', r)), + new Promise((r) => sink2.on('finish', r)), + ]); + ops += chunkCount * 2; + void bytes1; + void bytes2; + } + return ops; +} + +// Workload 10: Readable.from() with generators (modern data source pattern) +async function workloadReadableFrom(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + // From array + const arr = Array.from({ length: 100 }, (_, j) => `item-${j}\n`); + const stream1 = Readable.from(arr); + let data1 = ''; + for await (const chunk of stream1) { + data1 += chunk; + } + ops += 100; + void data1; + + // From async generator (database cursor simulation) + async function* generateRows() { + for (let j = 0; j < 100; j++) { + yield JSON.stringify({ row: j, value: Math.random() }) + '\n'; + } + } + + const stream2 = Readable.from(generateRows()); + let data2 = ''; + for await (const chunk of stream2) { + data2 += chunk; + } + ops += 100; + void data2; + } + return ops; +} + +async function main() { + console.log('[pgo-streams-buffers] Starting streams & buffers workload...'); + const startTime = Date.now(); + let totalOps = 0; + let round = 0; + + const remaining = () => DURATION_MS - (Date.now() - startTime); + + while (remaining() > 0) { + round++; + const scale = Math.max(0.1, remaining() / DURATION_MS); + const iterScale = (base) => Math.max(1, Math.floor(base * scale)); + + // Buffer workloads (sync, fast — exercise C++ bindings extensively) + if (round === 1) + console.log('[pgo-streams-buffers] Running buffer creation...'); + totalOps += workloadBufferCreation(iterScale(2000)); + if (remaining() <= 0) break; + + if (round === 1) + console.log('[pgo-streams-buffers] Running buffer encoding...'); + totalOps += workloadBufferEncoding(iterScale(1000)); + if (remaining() <= 0) break; + + if (round === 1) + console.log('[pgo-streams-buffers] Running buffer operations...'); + totalOps += workloadBufferOps(iterScale(1000)); + if (remaining() <= 0) break; + + // Stream workloads (async, exercise event loop + back-pressure) + if (round === 1) + console.log('[pgo-streams-buffers] Running pipe chains...'); + totalOps += await workloadPipeChain(iterScale(5)); + if (remaining() <= 0) break; + + if (round === 1) + console.log('[pgo-streams-buffers] Running transform streams...'); + totalOps += await workloadTransform(iterScale(5)); + if (remaining() <= 0) break; + + if (round === 1) + console.log('[pgo-streams-buffers] Running object mode streams...'); + totalOps += await workloadObjectMode(iterScale(10)); + if (remaining() <= 0) break; + + if (round === 1) + console.log('[pgo-streams-buffers] Running async iteration...'); + totalOps += await workloadAsyncIteration(iterScale(5)); + if (remaining() <= 0) break; + + if (round === 1) console.log('[pgo-streams-buffers] Running pipeline()...'); + totalOps += await workloadPipeline(iterScale(5)); + if (remaining() <= 0) break; + + if (round === 1) + console.log('[pgo-streams-buffers] Running PassThrough...'); + totalOps += await workloadPassThrough(iterScale(5)); + if (remaining() <= 0) break; + + if (round === 1) + console.log('[pgo-streams-buffers] Running Readable.from()...'); + totalOps += await workloadReadableFrom(iterScale(10)); + } + + const elapsed = (Date.now() - startTime) / 1000; + console.log( + `[pgo-streams-buffers] Completed ${totalOps} ops in ${elapsed.toFixed(1)}s (${(totalOps / elapsed).toFixed(0)} ops/s) [${round} rounds]`, + ); +} + +main().catch((err) => { + console.error('[pgo-streams-buffers] Error:', err); + process.exit(1); +}); diff --git a/tools/pgo/pgo-url-string.js b/tools/pgo/pgo-url-string.js new file mode 100644 index 000000000000..87fb22060894 --- /dev/null +++ b/tools/pgo/pgo-url-string.js @@ -0,0 +1,566 @@ +'use strict'; + +/* eslint-disable no-void */ + +// PGO Training Script: URL Parsing and String Operations +// +// URL parsing and string manipulation are pervasive in Node.js web apps: +// - WHATWG URL parsing (every HTTP request in modern code) +// - Legacy url.parse (still heavily used in existing codebases) +// - URLSearchParams (query string handling in every API) +// - Regex matching (routing, validation, sanitization) +// - String operations (template rendering, concatenation, encoding) +// - TextEncoder/TextDecoder (Web API string encoding) +// - querystring module (legacy but still widely used) +// - util.format, util.inspect (logging, debugging) +// +// This exercises: V8 string internals (one-byte/two-byte, cons, sliced), +// Ada URL parser (C++), regex JIT, TextEncoder/Decoder C++ implementation. + +const url = require('url'); +const { URL, URLSearchParams } = url; +const querystring = require('querystring'); +const util = require('util'); +const { TextEncoder, TextDecoder } = util; + +const DURATION_MS = parseInt(process.env.PGO_TRAINING_DURATION, 10) || 15_000; + +// Realistic URLs from web applications +const TEST_URLS = [ + 'https://api.example.com/v2/users?page=1&limit=50&sort=name&order=asc', + 'https://www.example.com/products/category/electronics?brand=apple&min_price=100&max_price=2000&in_stock=true', + 'http://localhost:3000/api/auth/login', + 'https://cdn.example.com/assets/images/hero-banner-2024.webp?w=1920&h=1080&q=85', + 'https://user:pass@db.example.com:5432/myapp?ssl=true&pool=10', + 'wss://realtime.example.com/ws/v1?token=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0', + 'https://example.com/path/to/resource#section-2', + 'https://search.example.com/q?query=node.js+performance+optimization&lang=en&safe=on', + 'https://api.example.com/v3/organizations/org-123/projects/proj-456/deployments/deploy-789/logs?since=2024-01-01T00:00:00Z&until=2024-12-31T23:59:59Z&level=error', + 'https://example.com/path%20with%20spaces/file%23name.html?key=value%26more', + 'https://xn--nxasmq6b.example.com/internationalized', // IDN + 'file:///C:/Users/user/Documents/project/index.html', + 'https://api.github.com/repos/nodejs/node/commits?sha=main&per_page=30', + 'https://registry.npmjs.org/@types/node/-/node-20.10.0.tgz', + 'http://[::1]:8080/ipv6-local', + 'data:text/html;base64,PGh0bWw+PC9odG1sPg==', +]; + +// Workload 1: WHATWG URL parsing (modern standard — every HTTP request) +function workloadWHATWGURL(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + for (const urlStr of TEST_URLS) { + try { + const parsed = new URL(urlStr); + + // Access all properties (common in routing/logging) + void parsed.href; + void parsed.origin; + void parsed.protocol; + void parsed.hostname; + void parsed.port; + void parsed.pathname; + void parsed.search; + void parsed.hash; + void parsed.username; + void parsed.password; + ops++; + + // Modify URL (redirect, base URL construction) + const modified = new URL(urlStr); + modified.pathname = '/new-path'; + modified.searchParams.set('modified', 'true'); + modified.toString(); + ops++; + + // URL.canParse (validation) + URL.canParse(urlStr); + URL.canParse('not-a-url'); + ops++; + } catch { + ops++; + } + } + } + return ops; +} + +// Workload 2: URLSearchParams (query string handling) +function workloadURLSearchParams(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + // Create from string + const params1 = new URLSearchParams( + 'page=1&limit=50&sort=name&order=asc&fields=id,name,email', + ); + params1.get('page'); + params1.get('limit'); + params1.getAll('fields'); + params1.has('sort'); + ops++; + + // Create from object (common API pattern) + const params2 = new URLSearchParams({ + q: 'node.js performance', + lang: 'en', + page: '1', + format: 'json', + }); + params2.toString(); + ops++; + + // Create from entries (Map-like) + const params3 = new URLSearchParams([ + ['key1', 'value1'], + ['key2', 'value2'], + ['key1', 'value3'], + ]); + params3.getAll('key1'); + ops++; + + // Iterate (common for logging, forwarding) + for (const entry of params1) { + void entry; + } + ops++; + + // Modify (adding/removing filters in API clients) + params1.set('page', '2'); + params1.append('filter', 'active'); + params1.append('filter', 'verified'); + params1.delete('order'); + params1.sort(); + params1.toString(); + ops++; + + // Complex real-world query strings + const complexQuery = new URLSearchParams( + 'filters[status]=active&filters[role][]=admin&filters[role][]=editor&' + + 'sort=-createdAt&fields=id,name,email,role&page[number]=1&page[size]=25&' + + 'include=profile,permissions&meta=true', + ); + for (const entry of complexQuery) { + void entry; + } + complexQuery.toString(); + ops++; + } + return ops; +} + +// Workload 3: Legacy url.parse (still very common in existing code) +function workloadLegacyURL(iterations) { + let ops = 0; + + for (let i = 0; i < iterations; i++) { + for (const urlStr of TEST_URLS) { + try { + // url.parse (Express's req.url handling) + const parsed = url.parse(urlStr, true); // true = parse query string + void parsed.pathname; + void parsed.query; + void parsed.hostname; + void parsed.protocol; + ops++; + + // url.format (building URLs) + url.format({ + protocol: 'https', + hostname: 'api.example.com', + pathname: `/v2/users/${i}`, + query: { fields: 'id,name', format: 'json' }, + }); + ops++; + + // url.resolve (relative URL resolution) + url.resolve('https://example.com/base/', './relative/path'); + url.resolve('https://example.com/base/path', '../other/path'); + ops++; + } catch { + ops++; + } + } + } + return ops; +} + +// Workload 4: querystring module (legacy but still heavily used) +function workloadQuerystring(iterations) { + let ops = 0; + + const testQueries = [ + 'name=John+Doe&age=30&city=New+York', + 'key1=val1&key2=val2&key3=val3&key4=val4&key5=val5', + 'q=search+term&page=1&per_page=20&sort=relevance', + 'data=%7B%22key%22%3A%22value%22%7D', + 'tags=node&tags=javascript&tags=performance', + ]; + + for (let i = 0; i < iterations; i++) { + for (const qs of testQueries) { + // Parse + const parsed = querystring.parse(qs); + ops++; + + // Stringify + querystring.stringify(parsed); + ops++; + } + + // Encode/decode + querystring.escape('Hello World! <>&"'); + querystring.unescape('Hello%20World%21%20%3C%3E%26%22'); + ops += 2; + + // Stringify with custom separator (some APIs use ; instead of &) + querystring.stringify({ a: 1, b: 2, c: 3 }, ';', ':'); + ops++; + } + return ops; +} + +// Workload 5: String operations (templating, manipulation) +function workloadStringOps(iterations) { + let ops = 0; + + const template = 'Hello, {{name}}! You have {{count}} new {{type}} messages.'; + const strings = [ + 'the quick brown fox jumps over the lazy dog', + 'UPPERCASE STRING TO CONVERT', + ' whitespace string with extra spaces ', + 'CamelCaseString_with_mixed_SEPARATORS-and-dashes', + 'path/to/some/file.extension.backup.2024', + ]; + + for (let i = 0; i < iterations; i++) { + // Template replacement (Mustache/Handlebars-like pattern) + template.replace(/\{\{(\w+)\}\}/g, (match, key) => { + const values = { name: 'User', count: '5', type: 'unread' }; + return values[key] || match; + }); + ops++; + + for (const str of strings) { + // Case conversion (header normalization, camelCase conversion) + str.toLowerCase(); + str.toUpperCase(); + ops += 2; + + // Trim (input sanitization) + str.trim(); + str.trimStart(); + str.trimEnd(); + ops += 3; + + // Split/join (CSV processing, path parsing) + str.split(/[\s_-]+/).join(' '); + str.split('.').join('/'); + ops += 2; + + // Include/startsWith/endsWith (routing, MIME detection) + str.includes('fox'); + str.startsWith('the'); + str.endsWith('dog'); + str.indexOf('the'); + str.lastIndexOf('the'); + ops += 5; + + // Slice/substring (truncation, preview generation) + str.slice(0, 20); + str.substring(5, 15); + ops += 2; + + // Replace (sanitization, normalization) + str.replace(/[^a-zA-Z0-9]/g, '_'); + str.replaceAll(' ', '-'); + ops += 2; + + // padStart/padEnd (formatting) + String(i).padStart(6, '0'); + str.slice(0, 10).padEnd(20, '.'); + ops += 2; + + // Repeat (indentation generation) + ' '.repeat(Math.min(i % 10, 5)); + ops++; + } + + // String concatenation patterns + let result = ''; + for (let j = 0; j < 100; j++) { + result += `item_${j},`; + } + ops++; + void result; + + // Template literal (most common string building pattern) + const items = Array.from( + { length: 20 }, + (_, j) => ` "${j}": "value_${j}"`, + ); + const json = `{\n${items.join(',\n')}\n}`; + ops++; + void json; + + // String.fromCharCode / codePointAt (encoding) + for (let j = 32; j < 127; j++) { + String.fromCharCode(j); + } + 'Hello! 日本語'.codePointAt(0); + ops++; + } + return ops; +} + +// Workload 6: Regular expressions (routing, validation, parsing) +function workloadRegex(iterations) { + let ops = 0; + + // Pre-compiled regexes (real-world patterns) + const emailRe = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/; + const uuidRe = + /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; + const ipv4Re = /^(\d{1,3}\.){3}\d{1,3}$/; + const routeRe = + /^\/api\/v(\d+)\/(users|products|orders)(?:\/([a-zA-Z0-9_-]+))?$/; + const htmlTagRe = /<([a-z]+)([^>]*)>(.*?)<\/\1>/gi; + const semverRe = + /^v?(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9.]+))?(?:\+([a-zA-Z0-9.]+))?$/; + const dateRe = /^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z?)?$/; + const csvRe = /(?:^|,)("(?:[^"]*(?:""[^"]*)*)"|[^,]*)/g; + + const testStrings = { + emails: ['test@example.com', 'invalid@', 'user+tag@domain.co.uk', 'nope'], + uuids: [ + '550e8400-e29b-41d4-a716-446655440000', + 'not-a-uuid', + '550E8400-E29B-41D4-A716-446655440000', + ], + ips: ['192.168.1.1', '10.0.0.0', '999.999.999.999', 'not.an.ip'], + routes: [ + '/api/v2/users', + '/api/v1/products/abc-123', + '/api/v3/orders/', + '/other/path', + ], + html: [ + '
Hello
', + '

Text

', + 'Content', + ], + semver: ['v1.2.3', '2.0.0-beta.1', '1.0.0+build.123', '1.2', 'not-semver'], + dates: [ + '2024-01-15', + '2024-01-15T10:30:00Z', + '2024-01-15T10:30:00.123Z', + 'not-a-date', + ], + csv: [ + '"John","Doe",30', + '"Jane ""J"" Doe","Smith",25', + 'simple,values,here', + ], + }; + + for (let i = 0; i < iterations; i++) { + // Email validation (form submission, user registration) + for (const email of testStrings.emails) { + emailRe.test(email); + ops++; + } + + // UUID validation (API parameters) + for (const uuid of testStrings.uuids) { + uuidRe.test(uuid); + ops++; + } + + // IP validation (rate limiting, geo-blocking) + for (const ip of testStrings.ips) { + ipv4Re.test(ip); + ops++; + } + + // Route matching (URL routing in Express/Fastify) + for (const route of testStrings.routes) { + const match = routeRe.exec(route); + if (match) { + void match[1]; + void match[2]; + void match[3]; + } + ops++; + } + + // HTML tag parsing (template engines, sanitization) + for (const html of testStrings.html) { + html.replace(htmlTagRe, (match, tag, attrs, content) => content); + ops++; + } + + // Semver parsing (package resolution) + for (const ver of testStrings.semver) { + semverRe.test(ver); + ops++; + } + + // Date validation (API input) + for (const date of testStrings.dates) { + dateRe.test(date); + ops++; + } + + // CSV parsing (data import) + for (const csv of testStrings.csv) { + void [...csv.matchAll(csvRe)]; + ops++; + } + } + return ops; +} + +// Workload 7: TextEncoder/TextDecoder (Web API compatibility) +function workloadTextEncoding(iterations) { + let ops = 0; + const encoder = new TextEncoder(); + const decoder = new TextDecoder('utf-8'); + const testStrings = [ + 'Hello, World!', + 'The quick brown fox jumps over the lazy dog', + '日本語テスト Unicode text with émojis 🎉', + 'A'.repeat(1000), + Array.from({ length: 100 }, (_, i) => `line ${i}`).join('\n'), + ]; + + for (let i = 0; i < iterations; i++) { + for (const str of testStrings) { + // Encode (string → Uint8Array) + const encoded = encoder.encode(str); + ops++; + + // Decode (Uint8Array → string) + decoder.decode(encoded); + ops++; + + // encodeInto (reuse buffer — more efficient) + const dest = new Uint8Array(str.length * 3); + encoder.encodeInto(str, dest); + ops++; + } + } + return ops; +} + +// Workload 8: util.format and util.inspect (logging — extremely common) +function workloadUtilFormat(iterations) { + let ops = 0; + + const testObjects = [ + { simple: 'object', count: 42 }, + { nested: { deep: { value: [1, 2, 3] } }, fn: () => {} }, + new Map([['key', 'value']]), + new Set([1, 2, 3]), + new Error('test error'), + Buffer.from('test'), + /regex/gi, + new Date(), + ]; + + for (let i = 0; i < iterations; i++) { + // util.format (console.log uses this internally) + util.format('Request %s %s completed in %dms', 'GET', '/api/users', 42.5); + util.format('User %j logged in', { id: 1, name: 'test' }); + util.format('Values: %o %O', { a: 1 }, { b: 2 }); + ops += 3; + + // util.inspect (debug output, REPL) + for (const obj of testObjects) { + util.inspect(obj, { depth: 3, colors: false, maxArrayLength: 10 }); + ops++; + } + + // util.types (type checking) + util.types.isDate(new Date()); + util.types.isRegExp(/test/); + util.types.isSet(new Set()); + util.types.isMap(new Map()); + util.types.isPromise(Promise.resolve()); + ops += 5; + + // util.deprecate (module system pattern) + util.deprecate(() => {}, 'Use newAPI instead'); + ops++; + } + return ops; +} + +async function main() { + console.log('[pgo-url-string] Starting URL & string workload...'); + const startTime = Date.now(); + let totalOps = 0; + let round = 0; + + const remaining = () => DURATION_MS - (Date.now() - startTime); + + while (remaining() > 0) { + round++; + const scale = Math.max(0.1, remaining() / DURATION_MS); + const iterScale = (base) => Math.max(1, Math.floor(base * scale)); + + // WHATWG URL (highest priority — modern web standard) + if (round === 1) + console.log('[pgo-url-string] Running WHATWG URL parsing...'); + totalOps += workloadWHATWGURL(iterScale(300)); + if (remaining() <= 0) break; + + // URLSearchParams + if (round === 1) console.log('[pgo-url-string] Running URLSearchParams...'); + totalOps += workloadURLSearchParams(iterScale(500)); + if (remaining() <= 0) break; + + // Legacy URL + if (round === 1) + console.log('[pgo-url-string] Running legacy url.parse...'); + totalOps += workloadLegacyURL(iterScale(200)); + if (remaining() <= 0) break; + + // Querystring + if (round === 1) console.log('[pgo-url-string] Running querystring...'); + totalOps += workloadQuerystring(iterScale(500)); + if (remaining() <= 0) break; + + // String operations + if (round === 1) + console.log('[pgo-url-string] Running string operations...'); + totalOps += workloadStringOps(iterScale(300)); + if (remaining() <= 0) break; + + // Regex + if (round === 1) console.log('[pgo-url-string] Running regex patterns...'); + totalOps += workloadRegex(iterScale(500)); + if (remaining() <= 0) break; + + // TextEncoder/Decoder + if (round === 1) + console.log('[pgo-url-string] Running TextEncoder/Decoder...'); + totalOps += workloadTextEncoding(iterScale(500)); + if (remaining() <= 0) break; + + // util.format/inspect + if (round === 1) + console.log('[pgo-url-string] Running util.format/inspect...'); + totalOps += workloadUtilFormat(iterScale(200)); + } + + const elapsed = (Date.now() - startTime) / 1000; + console.log( + `[pgo-url-string] Completed ${totalOps} ops in ${elapsed.toFixed(1)}s (${(totalOps / elapsed).toFixed(0)} ops/s) [${round} rounds]`, + ); +} + +main().catch((err) => { + console.error('[pgo-url-string] Error:', err); + process.exit(1); +}); diff --git a/typings/globals.d.ts b/typings/globals.d.ts index 83fcec8e19a5..e64b8e6d89fc 100644 --- a/typings/globals.d.ts +++ b/typings/globals.d.ts @@ -5,8 +5,10 @@ import { BufferBinding } from './internalBinding/buffer'; import { CJSLexerBinding } from './internalBinding/cjs_lexer'; import { ConfigBinding } from './internalBinding/config'; import { ConstantsBinding } from './internalBinding/constants'; +import { CredentialsBinding } from './internalBinding/credentials'; import { CryptoBinding } from './internalBinding/crypto'; import { DebugBinding } from './internalBinding/debug'; +import { DiagnosticsChannelBinding } from './internalBinding/diagnostics_channel'; import { EncodingBinding } from './internalBinding/encoding_binding'; import { FsBinding } from './internalBinding/fs'; import { FsDirBinding } from './internalBinding/fs_dir'; @@ -14,6 +16,7 @@ import { HeapUtilsBinding } from './internalBinding/heap_utils'; import { HttpParserBinding } from './internalBinding/http_parser'; import { ICUBinding } from './internalBinding/icu'; import { InspectorBinding } from './internalBinding/inspector'; +import { InternalOnlyV8Binding } from './internalBinding/internal_only_v8'; import { IPCSerdesBinding } from './internalBinding/ipc_serdes'; import { LocksBinding } from './internalBinding/locks'; import { MessagingBinding } from './internalBinding/messaging'; @@ -24,6 +27,7 @@ import { ProcessBinding } from './internalBinding/process'; import { ProcessWrapBinding } from './internalBinding/process_wrap'; import { SeaBinding } from './internalBinding/sea'; import { SerdesBinding } from './internalBinding/serdes'; +import { SignalWrapBinding } from './internalBinding/signal_wrap'; import { StringDecoderBinding } from './internalBinding/string_decoder'; import { SymbolsBinding } from './internalBinding/symbols'; import { TimersBinding } from './internalBinding/timers'; @@ -33,6 +37,7 @@ import { URLPatternBinding } from "./internalBinding/url_pattern"; import { UtilBinding } from './internalBinding/util'; import { UVBinding } from './internalBinding/uv'; import { WASIBinding } from './internalBinding/wasi'; +import { WatchdogBinding } from './internalBinding/watchdog'; import { WorkerBinding } from './internalBinding/worker'; import { ZlibBinding } from './internalBinding/zlib'; @@ -44,8 +49,10 @@ interface InternalBindingMap { cjs_lexer: CJSLexerBinding; config: ConfigBinding; constants: ConstantsBinding; + credentials: CredentialsBinding; crypto: CryptoBinding; debug: DebugBinding; + diagnostics_channel: DiagnosticsChannelBinding; encoding_binding: EncodingBinding; fs: FsBinding; fs_dir: FsDirBinding; @@ -53,6 +60,7 @@ interface InternalBindingMap { http_parser: HttpParserBinding; icu: ICUBinding; inspector: InspectorBinding; + internal_only_v8: InternalOnlyV8Binding; ipc_serdes: IPCSerdesBinding; locks: LocksBinding; messaging: MessagingBinding; @@ -63,6 +71,7 @@ interface InternalBindingMap { process_wrap: ProcessWrapBinding; sea: SeaBinding; serdes: SerdesBinding; + signal_wrap: SignalWrapBinding; string_decoder: StringDecoderBinding; symbols: SymbolsBinding; timers: TimersBinding; @@ -72,6 +81,7 @@ interface InternalBindingMap { util: UtilBinding; uv: UVBinding; wasi: WASIBinding; + watchdog: WatchdogBinding; worker: WorkerBinding; zlib: ZlibBinding; } diff --git a/typings/internalBinding/credentials.d.ts b/typings/internalBinding/credentials.d.ts new file mode 100644 index 000000000000..8880e7e38a6f --- /dev/null +++ b/typings/internalBinding/credentials.d.ts @@ -0,0 +1,18 @@ +export interface CredentialsBinding { + implementsPosixCredentials?: true; + safeGetenv(key: string): string | undefined; + getTempDir(): string | undefined; + + getuid?(): number; + geteuid?(): number; + getgid?(): number; + getegid?(): number; + getgroups?(): number[]; + + initgroups?(user: string | number, extraGroup: string | number): 0 | 1 | 2; + setegid?(id: string | number): 0 | 1; + seteuid?(id: string | number): 0 | 1; + setgid?(id: string | number): 0 | 1; + setuid?(id: string | number): 0 | 1; + setgroups?(groups: Array): number; +} diff --git a/typings/internalBinding/crypto.d.ts b/typings/internalBinding/crypto.d.ts index d91c5018ba68..03ea3e74c641 100644 --- a/typings/internalBinding/crypto.d.ts +++ b/typings/internalBinding/crypto.d.ts @@ -9,6 +9,7 @@ declare namespace InternalCryptoBinding { type KeyFormatRawPublic = 3; type KeyFormatRawPrivate = 4; type KeyFormatRawSeed = 5; + type KeyFormatStore = 6; type PublicKeyFormat = KeyFormatDER | KeyFormatPEM | KeyFormatJWK | KeyFormatRawPublic | undefined; type PrivateKeyFormat = @@ -18,7 +19,12 @@ declare namespace InternalCryptoBinding { type KeyEncoding = string | number | null | undefined; type KeyPassphrase = ByteSource | null | undefined; type NamedCurve = string | null | undefined; - type PreparedAsymmetricKeyData = KeyObjectHandle | ByteSource | JwkKey; + interface StorePrivateKeyData { + uri: string; + properties: string | null; + } + type PreparedAsymmetricKeyData = + KeyObjectHandle | ByteSource | JwkKey | StorePrivateKeyData; type PreparedSecretKeyData = KeyObjectHandle | ByteSource; type CryptoJobAsyncMode = 0; type CryptoJobSyncMode = 1; @@ -126,7 +132,7 @@ declare namespace InternalCryptoBinding { type PreparedAsymmetricKeyArgs = [ keyData: PreparedAsymmetricKeyData, - keyFormat: KeyFormat, + keyFormat: KeyFormat | KeyFormatStore, keyType: KeyEncoding, keyPassphrase: KeyPassphrase, keyNamedCurve: NamedCurve, @@ -862,6 +868,7 @@ export interface CryptoBinding { kKeyFormatRawPrivate: InternalCryptoBinding.KeyFormatRawPrivate; kKeyFormatRawPublic: InternalCryptoBinding.KeyFormatRawPublic; kKeyFormatRawSeed: InternalCryptoBinding.KeyFormatRawSeed; + kKeyFormatStore: InternalCryptoBinding.KeyFormatStore; kKeyTypePrivate: number; kKeyTypePublic: number; kKeyTypeSecret: number; diff --git a/typings/internalBinding/diagnostics_channel.d.ts b/typings/internalBinding/diagnostics_channel.d.ts new file mode 100644 index 000000000000..e6297d45ace0 --- /dev/null +++ b/typings/internalBinding/diagnostics_channel.d.ts @@ -0,0 +1,6 @@ +export interface DiagnosticsChannelBinding { + subscribers: Uint32Array; + linkNativeChannel( + callback: (name: string, index: number) => object | undefined, + ): void; +} diff --git a/typings/internalBinding/internal_only_v8.d.ts b/typings/internalBinding/internal_only_v8.d.ts new file mode 100644 index 000000000000..3f1108e38dbf --- /dev/null +++ b/typings/internalBinding/internal_only_v8.d.ts @@ -0,0 +1,3 @@ +export interface InternalOnlyV8Binding { + queryObjects(prototype: unknown): object[]; +} diff --git a/typings/internalBinding/signal_wrap.d.ts b/typings/internalBinding/signal_wrap.d.ts new file mode 100644 index 000000000000..4c6473cbee22 --- /dev/null +++ b/typings/internalBinding/signal_wrap.d.ts @@ -0,0 +1,16 @@ +declare namespace InternalSignalWrapBinding { + class Signal { + constructor(); + onsignal?: (signum: number) => void; + start(signum: number): number | undefined; + stop(): number; + close(callback?: () => void): void; + hasRef(): boolean; + ref(): void; + unref(): void; + } +} + +export interface SignalWrapBinding { + Signal: typeof InternalSignalWrapBinding.Signal; +} diff --git a/typings/internalBinding/watchdog.d.ts b/typings/internalBinding/watchdog.d.ts new file mode 100644 index 000000000000..917ee3b96d48 --- /dev/null +++ b/typings/internalBinding/watchdog.d.ts @@ -0,0 +1,15 @@ +declare namespace InternalWatchdogBinding { + class TraceSigintWatchdog { + constructor(); + start(): void; + stop(): void; + close(callback?: () => void): void; + hasRef(): boolean; + ref(): void; + unref(): void; + } +} + +export interface WatchdogBinding { + TraceSigintWatchdog: typeof InternalWatchdogBinding.TraceSigintWatchdog; +}