diff --git a/.clang-format b/.clang-format
index 32b8bd5cfd..b01602a2b9 100644
--- a/.clang-format
+++ b/.clang-format
@@ -599,8 +599,6 @@ TypeNames:
- "ossl_finish_mutate_cb"
- "OSSL_FIPS_IND"
- "OSSL_FIPS_IND_CHECK_CB"
- - "OSSL_FN_CTX"
- - "OSSL_FN_ULONG"
- "OSSL_FUNC"
- "OSSL_HANDSHAKE_STATE"
- "OSSL_HASH"
@@ -1377,6 +1375,7 @@ StatementMacros:
- "static_ASN1_SEQUENCE_END_cb"
- "static_ASN1_SEQUENCE_END_name"
- "static_ASN1_SEQUENCE_END_ref"
+ - "PROV_CIPHER_HW_aes_mode"
- "PROV_CIPHER_HW_aria_mode"
- "PROV_CIPHER_HW_camellia_mode"
- "PROV_CIPHER_HW_des_mode"
diff --git a/.github/workflows/avx512-sde.yml b/.github/workflows/avx512-sde.yml
new file mode 100644
index 0000000000..1b94df9922
--- /dev/null
+++ b/.github/workflows/avx512-sde.yml
@@ -0,0 +1,167 @@
+# Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
+# Copyright (c) 2026 Intel Corporation. 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
+
+# Run AVX512-specific tests under Intel SDE.
+#
+# GitHub Actions runners currently do not have AVX512 hardware.
+# Intel SDE emulates AVX512 instructions and spoofs CPUID,
+# so AVX512 code paths are exercised.
+#
+# To update Intel SDE: find the new mirror ID and file date from
+# https://www.intel.com/content/www/us/en/download/684897
+# and update the three env vars below.
+
+name: AVX512 tests via Intel SDE
+
+on:
+ schedule:
+ - cron: '30 02 * * *'
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+env:
+ SDE_VERSION: 10.8.0
+ SDE_DATE: 2026-03-15
+ SDE_MIRROR_ID: 915934
+
+jobs:
+ linux:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v6
+ with:
+ persist-credentials: false
+
+ - name: install NASM
+ run: sudo apt-get install -y nasm
+
+ - name: install Intel SDE
+ run: |
+ SDE_URL="https://downloadmirror.intel.com/${SDE_MIRROR_ID}/sde-external-${SDE_VERSION}-${SDE_DATE}-lin.tar.xz"
+ SDE_SHA256="50b320cd226acef7a491f5b321fc1be3c3c7984f9e27a456e64894b5b0979dd3"
+ curl -fsSL -o /tmp/sde.tar.xz "$SDE_URL"
+ echo "$SDE_SHA256 /tmp/sde.tar.xz" | sha256sum -c -
+ mkdir /tmp/sde
+ tar -xf /tmp/sde.tar.xz -C /tmp/sde/
+ sudo mv /tmp/sde/sde-external-${SDE_VERSION}-${SDE_DATE}-lin /opt/sde
+ echo "/opt/sde" >> "$GITHUB_PATH"
+
+ - name: config
+ run: |
+ ./config --banner=Configured --strict-warnings no-shared enable-fips
+
+ - name: build
+ run: make -j4
+
+ - name: show CPU and OpenSSL build info
+ run: |
+ cat /proc/cpuinfo | grep -m1 "model name"
+ sde64 -icx -- ./apps/openssl version -c
+
+ - name: ml_dsa_internal_test (AVX512 via SDE)
+ run: sde64 -icx -- ./test/ml_dsa_internal_test
+
+ - name: sha3_x4_internal_test (AVX512 via SDE)
+ run: sde64 -icx -- ./test/sha3_x4_internal_test
+
+ - name: fipsinstall (FIPS KAT via SDE)
+ run: sde64 -icx -- ./apps/openssl fipsinstall -module ./providers/fips.so -out /tmp/fipsmodule.cnf -provider_name fips
+
+ windows:
+ runs-on: windows-2022
+ env:
+ VCVARS: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
+ steps:
+ - uses: actions/checkout@v6
+ with:
+ persist-credentials: false
+
+ - name: install nasm
+ if: github.repository == 'openssl/openssl'
+ run: |
+ $installer = "nasm-3.01-installer-x64.exe"
+ Invoke-WebRequest -Uri "https://openssl-library.org/ci-deps/$installer" -OutFile $installer
+ $expected = (Get-Content "$env:GITHUB_WORKSPACE\.github\ci-deps.json" -Raw | ConvertFrom-Json).$installer
+ $actual = (Get-FileHash $installer -Algorithm SHA256).Hash
+ if ($actual -ne $expected) { throw "SHA256 mismatch for $installer (expected $expected, got $actual)" }
+ Start-Process -FilePath ".\$installer" -ArgumentList '/S' -Wait
+ "C:\Program Files\NASM" | Out-File -FilePath "$env:GITHUB_PATH" -Append
+ - name: install nasm (forks)
+ if: github.repository != 'openssl/openssl'
+ run: |
+ $installer = "nasm-3.01-installer-x64.exe"
+ Invoke-WebRequest -Uri "https://www.nasm.us/pub/nasm/releasebuilds/3.01/win64/$installer" -OutFile $installer
+ Start-Process -FilePath ".\$installer" -ArgumentList '/S' -Wait
+ "C:\Program Files\NASM" | Out-File -FilePath "$env:GITHUB_PATH" -Append
+
+ - name: install jom
+ if: github.repository == 'openssl/openssl'
+ run: |
+ mkdir C:\jom
+ Invoke-WebRequest -Uri "https://openssl-library.org/ci-deps/jom-1.1.7.exe" -OutFile C:\jom\jom.exe
+ $expected = (Get-Content "$env:GITHUB_WORKSPACE\.github\ci-deps.json" -Raw | ConvertFrom-Json).'jom-1.1.7.exe'
+ $actual = (Get-FileHash C:\jom\jom.exe -Algorithm SHA256).Hash
+ if ($actual -ne $expected) { throw "SHA256 mismatch for jom.exe (expected $expected, got $actual)" }
+ "C:\jom" | Out-File -FilePath "$env:GITHUB_PATH" -Append
+ - name: install jom (forks)
+ if: github.repository != 'openssl/openssl'
+ run: |
+ mkdir C:\jom
+ Invoke-WebRequest -Uri "https://download.qt.io/official_releases/jom/jom_1_1_7.zip" -OutFile C:\jom\jom.zip
+ Expand-Archive -Path C:\jom\jom.zip -DestinationPath C:\jom
+ "C:\jom" | Out-File -FilePath "$env:GITHUB_PATH" -Append
+
+ - name: install Intel SDE
+ run: |
+ $url = "https://downloadmirror.intel.com/$env:SDE_MIRROR_ID/sde-external-$env:SDE_VERSION-$env:SDE_DATE-win.tar.xz"
+ $expected = "176F87C80EB42BB91B73E1428F4A0FD067DF322F901F9B4359B20B86B92C2BAE"
+ curl.exe -fsSL -o sde-win.tar.xz $url
+ $actual = (Get-FileHash sde-win.tar.xz -Algorithm SHA256).Hash
+ if ($actual -ne $expected) { throw "SDE SHA256 mismatch: got $actual" }
+ & "C:\Program Files\7-Zip\7z.exe" x sde-win.tar.xz -so | & "C:\Program Files\7-Zip\7z.exe" x -si -ttar -o"C:\sde"
+ $sdeRoot = "C:\sde\sde-external-$env:SDE_VERSION-$env:SDE_DATE-win"
+ if (-not (Test-Path "$sdeRoot\sde.exe")) { throw "sde.exe not found in $sdeRoot" }
+ "$sdeRoot" | Out-File -FilePath $env:GITHUB_PATH -Append
+
+ - name: prepare build directory
+ run: mkdir _build
+
+ - name: config
+ working-directory: _build
+ shell: cmd
+ run: |
+ call "%VCVARS%"
+ perl ..\Configure --banner=Configured --strict-warnings no-shared enable-fips no-makedepend
+
+ - name: build
+ working-directory: _build
+ shell: cmd
+ run: |
+ call "%VCVARS%"
+ jom /j4 /S
+
+ - name: show CPU and OpenSSL build info
+ working-directory: _build
+ run: sde -icx -- apps\openssl.exe version -c
+
+ - name: ml_dsa_internal_test (AVX512 via SDE)
+ working-directory: _build
+ shell: cmd
+ run: sde -icx -- test\ml_dsa_internal_test.exe
+
+ - name: sha3_x4_internal_test (AVX512 via SDE)
+ working-directory: _build
+ shell: cmd
+ run: sde -icx -- test\sha3_x4_internal_test.exe
+
+ - name: fipsinstall (FIPS KAT via SDE)
+ working-directory: _build
+ shell: cmd
+ run: sde -icx -- apps\openssl.exe fipsinstall -module providers\fips.dll -out fipsmodule.cnf -provider_name fips
diff --git a/.github/workflows/ci-doc-changes.yml b/.github/workflows/ci-doc-changes.yml
new file mode 100644
index 0000000000..08919fc323
--- /dev/null
+++ b/.github/workflows/ci-doc-changes.yml
@@ -0,0 +1,125 @@
+# Copyright 2021-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
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+name: Documentation and Installability CI
+
+on: [pull_request, push]
+
+permissions:
+ contents: read
+
+env:
+ OSSL_RUN_CI_TESTS: 1
+
+jobs:
+ check_docs:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v6
+ with:
+ persist-credentials: false
+ - name: config
+ run: ./config --strict-warnings --banner=Configured enable-fips && perl configdata.pm --dump
+ - name: make build_generated
+ run: make -s build_generated
+ - name: make doc-nits
+ run: make doc-nits
+ - name: make help
+ run: make help
+ - name: make md-nits
+ run: |
+ sudo gem install mdl
+ make md-nits
+
+ # out-of-source-and-install checks multiple things at the same time:
+ # - That building, testing and installing works from an out-of-source
+ # build tree
+ # - That building, testing and installing works with a read-only source
+ # tree
+ out-of-readonly-source-and-install-ubuntu:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v6
+ with:
+ path: ./source
+ persist-credentials: false
+ - name: checkout fuzz/corpora submodule
+ run: git submodule update --init --depth 1 fuzz/corpora
+ working-directory: ./source
+ - name: make source read-only
+ run: chmod -R a-w ./source
+ - name: create build and install directories
+ run: |
+ mkdir ./build
+ mkdir ./install
+ - name: config
+ run: |
+ ../source/config --banner=Configured enable-demos enable-h3demo enable-fips enable-lms enable-quic enable-acvp-tests --strict-warnings --prefix=$(cd ../install; pwd)
+ perl configdata.pm --dump
+ working-directory: ./build
+ - name: make
+ run: make -s -j4
+ working-directory: ./build
+ - name: get cpu info
+ run: |
+ cat /proc/cpuinfo
+ ./util/opensslwrap.sh version -c
+ working-directory: ./build
+ - name: make test
+ run: ../source/.github/workflows/make-test
+ working-directory: ./build
+ - name: save artifacts
+ if: success() || failure()
+ uses: actions/upload-artifact@v5
+ with:
+ name: "ci@out-of-readonly-source-and-install-ubuntu"
+ path: build/artifacts.tar.gz
+ - name: make install
+ run: make install
+ working-directory: ./build
+
+ out-of-readonly-source-and-install-macos:
+ runs-on: macos-15
+ steps:
+ - uses: actions/checkout@v6
+ with:
+ path: ./source
+ persist-credentials: false
+ - name: checkout fuzz/corpora submodule
+ run: git submodule update --init --depth 1 fuzz/corpora
+ working-directory: ./source
+ - name: make source read-only
+ run: chmod -R a-w ./source
+ - name: create build and install directories
+ run: |
+ mkdir ./build
+ mkdir ./install
+ - name: config
+ run: |
+ ../source/config --banner=Configured enable-fips enable-lms enable-demos enable-h3demo enable-quic enable-acvp-tests --strict-warnings --prefix=$(cd ../install; pwd)
+ perl configdata.pm --dump
+ working-directory: ./build
+ - name: make
+ run: make -s -j4
+ working-directory: ./build
+ - name: get cpu info
+ run: |
+ sysctl machdep.cpu
+ ./util/opensslwrap.sh version -c
+ working-directory: ./build
+ - name: make test
+ run: ../source/.github/workflows/make-test
+ working-directory: ./build
+ - name: save artifacts
+ if: success() || failure()
+ uses: actions/upload-artifact@v5
+ with:
+ name: "ci@out-of-readonly-source-and-install-macos-15"
+ path: build/artifacts.tar.gz
+ - name: make install
+ run: make install
+ working-directory: ./build
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 8086c9207c..a80ea66b29 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -7,7 +7,25 @@
name: GitHub CI
-on: [pull_request, push]
+on:
+ pull_request:
+ paths-ignore:
+ - 'doc/**'
+ - '*.md'
+ - '*.pod'
+ - 'README*'
+ - 'funding.json'
+ - 'LICENSE.txt'
+ - 'VERSION.dat'
+ push:
+ paths-ignore:
+ - 'doc/**'
+ - '*.md'
+ - '*.pod'
+ - 'README*'
+ - 'funding.json'
+ - 'LICENSE.txt'
+ - 'VERSION.dat'
# for some reason, this does not work:
# variables:
@@ -45,25 +63,6 @@ jobs:
- name: git diff
run: git diff --exit-code
- check_docs:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v6
- with:
- persist-credentials: false
- - name: config
- run: ./config --strict-warnings --banner=Configured enable-fips && perl configdata.pm --dump
- - name: make build_generated
- run: make -s build_generated
- - name: make doc-nits
- run: make doc-nits
- - name: make help
- run: make help
- - name: make md-nits
- run: |
- sudo gem install mdl
- make md-nits
-
# This checks that we use ANSI C language syntax and semantics.
# We are not as strict with libraries, but rather adapt to what's
# expected to be available in a certain version of each platform.
@@ -88,12 +87,14 @@ jobs:
run: git submodule update --init --depth 1 fuzz/corpora
- name: localegen
run: sudo locale-gen tr_TR.UTF-8
+ - name: cmocka
+ run: sudo apt-get -y install libcmocka-dev
- name: fipsvendor
# Make one fips build use a customized FIPS vendor
run: echo "FIPS_VENDOR=CI" >> VERSION.dat
- name: config
# enable-quic is on by default, but we leave it here to check we're testing the explicit enable somewhere
- run: CC=gcc ./config --strict-warnings --banner=Configured enable-demos enable-h3demo enable-ec_explicit_curves enable-sslkeylog enable-fips enable-quic enable-lms && perl configdata.pm --dump
+ run: CC=gcc ./config --strict-warnings --banner=Configured enable-demos enable-h3demo enable-ec_explicit_curves enable-sslkeylog enable-fips enable-quic enable-lms enable-unit-tests && perl configdata.pm --dump
- name: make
run: make -s -j4
- name: get cpu info
@@ -460,6 +461,40 @@ jobs:
path: artifacts.tar.gz
if-no-files-found: ignore
+ fuzz_tests_mfail:
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ steps:
+ - uses: actions/checkout@v6
+ with:
+ persist-credentials: false
+ - name: checkout fuzz/corpora submodule
+ run: git submodule update --init --depth 1 fuzz/corpora
+ - name: Adjust ASLR for sanitizer
+ run: sudo sysctl -w vm.mmap_rnd_bits=28
+ - name: config
+ run: |
+ ./config --strict-warnings --banner=Configured --debug \
+ -DPEDANTIC -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION \
+ enable-asan enable-ec_explicit_curves enable-ubsan \
+ enable-rc5 enable-md2 enable-ec_nistp_64_gcc_128 \
+ enable-weak-ssl-ciphers enable-nextprotoneg
+ perl configdata.pm --dump
+ - name: make
+ run: make -s -j4
+ - name: make test (fuzz with mfail)
+ env:
+ OSSL_FUZZ_TEST_BUDGET: 1200
+ OSSL_FUZZ_TEST_JOBS: 4
+ run: .github/workflows/make-test OPENSSL_TEST_RAND_ORDER=0 TESTS="test_fuzz*"
+ - name: save artifacts
+ if: success() || failure()
+ uses: actions/upload-artifact@v5
+ with:
+ name: "ci@fuzz_tests_mfail"
+ path: artifacts.tar.gz
+ if-no-files-found: ignore
+
memory_sanitizer:
runs-on: ubuntu-latest
steps:
@@ -629,95 +664,6 @@ jobs:
name: "ci@legacy"
path: artifacts.tar.gz
- # out-of-source-and-install checks multiple things at the same time:
- # - That building, testing and installing works from an out-of-source
- # build tree
- # - That building, testing and installing works with a read-only source
- # tree
- out-of-readonly-source-and-install-ubuntu:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v6
- with:
- path: ./source
- persist-credentials: false
- - name: checkout fuzz/corpora submodule
- run: git submodule update --init --depth 1 fuzz/corpora
- working-directory: ./source
- - name: make source read-only
- run: chmod -R a-w ./source
- - name: create build and install directories
- run: |
- mkdir ./build
- mkdir ./install
- - name: config
- run: |
- ../source/config --banner=Configured enable-demos enable-h3demo enable-fips enable-lms enable-quic enable-acvp-tests --strict-warnings --prefix=$(cd ../install; pwd)
- perl configdata.pm --dump
- working-directory: ./build
- - name: make
- run: make -s -j4
- working-directory: ./build
- - name: get cpu info
- run: |
- cat /proc/cpuinfo
- ./util/opensslwrap.sh version -c
- working-directory: ./build
- - name: make test
- run: ../source/.github/workflows/make-test
- working-directory: ./build
- - name: save artifacts
- if: success() || failure()
- uses: actions/upload-artifact@v5
- with:
- name: "ci@out-of-readonly-source-and-install-ubuntu"
- path: build/artifacts.tar.gz
- - name: make install
- run: make install
- working-directory: ./build
-
- out-of-readonly-source-and-install-macos:
- runs-on: macos-15
- steps:
- - uses: actions/checkout@v6
- with:
- path: ./source
- persist-credentials: false
- - name: checkout fuzz/corpora submodule
- run: git submodule update --init --depth 1 fuzz/corpora
- working-directory: ./source
- - name: make source read-only
- run: chmod -R a-w ./source
- - name: create build and install directories
- run: |
- mkdir ./build
- mkdir ./install
- - name: config
- run: |
- ../source/config --banner=Configured enable-fips enable-lms enable-demos enable-h3demo enable-quic enable-acvp-tests --strict-warnings --prefix=$(cd ../install; pwd)
- perl configdata.pm --dump
- working-directory: ./build
- - name: make
- run: make -s -j4
- working-directory: ./build
- - name: get cpu info
- run: |
- sysctl machdep.cpu
- ./util/opensslwrap.sh version -c
- working-directory: ./build
- - name: make test
- run: ../source/.github/workflows/make-test
- working-directory: ./build
- - name: save artifacts
- if: success() || failure()
- uses: actions/upload-artifact@v5
- with:
- name: "ci@out-of-readonly-source-and-install-macos-15"
- path: build/artifacts.tar.gz
- - name: make install
- run: make install
- working-directory: ./build
-
external-tests-misc:
runs-on: ubuntu-latest
steps:
@@ -729,10 +675,6 @@ jobs:
run: |
sudo apt-get update
sudo apt-get -yq install bison gettext keyutils ldap-utils libldap2-dev libkeyutils-dev python3 python3-paste python3-pyrad slapd tcsh python3-virtualenv virtualenv python3-kdcproxy gdb libtls-dev wget gpg
- - name: install cpanm and Test2::V0 for gost_engine testing
- uses: perl-actions/install-with-cpanm@10d60f00b4073f484fc29d45bfbe2f776397ab3d # v1.7
- with:
- install: Test2::V0
- name: setup hostname workaround
run: sudo hostname localhost
- name: config
@@ -746,8 +688,9 @@ jobs:
run: |
cat /proc/cpuinfo
./util/opensslwrap.sh version -c
- - name: test external gost-engine
- run: make test TESTS="test_external_gost_engine"
+ - name: test failure when selecting non-existing test case
+ run: |
+ ! make test TESTS="test_external_gost_engine"
- name: test external krb5
run: make test TESTS="test_external_krb5"
- name: test external tlsfuzzer
diff --git a/.github/workflows/coveralls.yml b/.github/workflows/coveralls.yml
index 4c873babc8..34075a3566 100644
--- a/.github/workflows/coveralls.yml
+++ b/.github/workflows/coveralls.yml
@@ -47,10 +47,10 @@ jobs:
MATRIX=$(cat << EOF
[{
"branch": "master",
- "extra_config": "enable-fips enable-tfo enable-lms enable-crypto-mdebug enable-allocfail-tests"
+ "extra_config": "enable-fips enable-tfo enable-lms enable-crypto-mdebug enable-unit-tests"
}, {
"branch": "openssl-4.0",
- "extra_config": "enable-fips enable-tfo enable-lms enable-crypto-mdebug enable-allocfail-tests"
+ "extra_config": "enable-fips enable-tfo enable-lms enable-crypto-mdebug"
},{
"branch": "openssl-3.6",
"extra_config": "no-afalgeng enable-fips enable-tfo enable-lms"
@@ -93,7 +93,7 @@ jobs:
run: |
sudo apt-get update
sudo apt-get -yq install lcov
- sudo apt-get -yq install bison gettext keyutils ldap-utils libldap2-dev libkeyutils-dev python3 python3-paste python3-pyrad slapd tcsh python3-virtualenv virtualenv python3-kdcproxy
+ sudo apt-get -yq install bison gettext keyutils ldap-utils libcmocka-dev libldap2-dev libkeyutils-dev python3 python3-paste python3-pyrad slapd tcsh python3-virtualenv virtualenv python3-kdcproxy
- name: install Test2::V0 for gost_engine testing
uses: perl-actions/install-with-cpanm@10d60f00b4073f484fc29d45bfbe2f776397ab3d #v1.7
with:
diff --git a/.github/workflows/cross-compiles.yml b/.github/workflows/cross-compiles.yml
index efc498edf1..d0f5ff8284 100644
--- a/.github/workflows/cross-compiles.yml
+++ b/.github/workflows/cross-compiles.yml
@@ -7,13 +7,35 @@
name: Cross Compile
-on: [pull_request, push]
+on:
+ pull_request:
+ paths-ignore:
+ - 'doc/**'
+ - '*.md'
+ - '*.pod'
+ - 'README*'
+ - 'funding.json'
+ - 'LICENSE.txt'
+ - 'VERSION.dat'
+ push:
+ paths-ignore:
+ - 'doc/**'
+ - '*.md'
+ - '*.pod'
+ - 'README*'
+ - 'funding.json'
+ - 'LICENSE.txt'
+ - 'VERSION.dat'
permissions:
contents: read
jobs:
cross-compilation:
+ # Run the full test suite on push, and on pull requests labelled with
+ # 'extended tests'. Other pull requests only run the EVP tests.
+ env:
+ EXTENDED: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'extended tests') }}
strategy:
fail-fast: false
matrix:
@@ -211,19 +233,19 @@ jobs:
cat /proc/cpuinfo
QEMU_LD_PREFIX=/usr/${{ matrix.platform.arch }} ./util/opensslwrap.sh version -c
- name: make all tests
- if: github.event_name == 'push' && matrix.platform.tests == ''
+ if: env.EXTENDED == 'true' && matrix.platform.tests == ''
run: |
.github/workflows/make-test \
TESTS="-test_afalg" \
QEMU_LD_PREFIX=/usr/${{ matrix.platform.arch }}
- name: make some tests
- if: github.event_name == 'push' && matrix.platform.tests != 'none' && matrix.platform.tests != ''
+ if: env.EXTENDED == 'true' && matrix.platform.tests != 'none' && matrix.platform.tests != ''
run: |
.github/workflows/make-test \
TESTS="${{ matrix.platform.tests }} -test_afalg" \
QEMU_LD_PREFIX=/usr/${{ matrix.platform.arch }}
- name: make evp tests
- if: github.event_name == 'pull_request' && matrix.platform.tests != 'none'
+ if: env.EXTENDED != 'true' && matrix.platform.tests != 'none'
run: |
.github/workflows/make-test \
TESTS="test_evp*" \
diff --git a/.github/workflows/fips-checksums.yml b/.github/workflows/fips-checksums.yml
index f82a604ab7..5fd96b3159 100644
--- a/.github/workflows/fips-checksums.yml
+++ b/.github/workflows/fips-checksums.yml
@@ -6,7 +6,16 @@
# https://www.openssl.org/source/license.html
name: FIPS Check and ABIDIFF
-on: [pull_request]
+on:
+ pull_request:
+ paths-ignore:
+ - 'doc/**'
+ - '*.md'
+ - '*.pod'
+ - 'README*'
+ - 'funding.json'
+ - 'LICENSE.txt'
+ - 'VERSION.dat'
permissions:
contents: read
diff --git a/.github/workflows/make-release.yml b/.github/workflows/make-release.yml
deleted file mode 100644
index 746da6e059..0000000000
--- a/.github/workflows/make-release.yml
+++ /dev/null
@@ -1,48 +0,0 @@
-# Copyright 2021-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
-# in the file LICENSE in the source distribution or at
-# https://www.openssl.org/source/license.html
-
-name: "Make release"
-
-on:
- push:
- tags:
- - "openssl-*"
-
-permissions: {}
-
-jobs:
- release:
- runs-on: "releaser"
- steps:
- - name: "Checkout"
- uses: "actions/checkout@v6"
- with:
- fetch-depth: 1
- ref: ${{ github.ref_name }}
- github-server-url: "https://github.openssl.org/"
- repository: "openssl/openssl"
- token: ${{ secrets.GHE_TOKEN }}
- path: ${{ github.ref_name }}
- persist-credentials: false
- - name: "Prepare assets"
- env:
- SIGNING_KEY_UID: ${{ vars.signing_key_uid }}
- run: |
- cd "$GITHUB_REF_NAME"
- ./util/mktar.sh
- mkdir -p assets && mv "$GITHUB_REF_NAME.tar.gz" assets/ && cd assets
- openssl sha1 -r "$GITHUB_REF_NAME.tar.gz" > "$GITHUB_REF_NAME.tar.gz.sha1"
- openssl sha256 -r "$GITHUB_REF_NAME.tar.gz" > "$GITHUB_REF_NAME.tar.gz.sha256"
- gpg -u "$SIGNING_KEY_UID" -o "$GITHUB_REF_NAME.tar.gz.asc" -sba "$GITHUB_REF_NAME.tar.gz"
- - name: "Create release"
- env:
- GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
- run: |
- VERSION=$(echo "$GITHUB_REF_NAME" | cut -d "-" -f 2-)
- PRE_RELEASE=$([[ "$GITHUB_REF_NAME" =~ alpha|beta ]] && echo "-p" || echo "")
- NOTES=$(curl -s "https://api.openssl.org/release-metadata/news/?version=$VERSION&capture_title=False")
- gh release create "$GITHUB_REF_NAME" $PRE_RELEASE -t "OpenSSL $VERSION" -d --notes "$NOTES" -R "$GITHUB_REPOSITORY" "$GITHUB_REF_NAME/assets/"*
diff --git a/.github/workflows/perl-minimal-checker.yml b/.github/workflows/perl-minimal-checker.yml
index 9ca4e9b509..2606add5fb 100644
--- a/.github/workflows/perl-minimal-checker.yml
+++ b/.github/workflows/perl-minimal-checker.yml
@@ -7,7 +7,25 @@
# Jobs run per pull request submission
name: Perl-minimal-checker CI
-on: [pull_request, push]
+on:
+ pull_request:
+ paths-ignore:
+ - 'doc/**'
+ - '*.md'
+ - '*.pod'
+ - 'README*'
+ - 'funding.json'
+ - 'LICENSE.txt'
+ - 'VERSION.dat'
+ push:
+ paths-ignore:
+ - 'doc/**'
+ - '*.md'
+ - '*.pod'
+ - 'README*'
+ - 'funding.json'
+ - 'LICENSE.txt'
+ - 'VERSION.dat'
permissions:
contents: read
diff --git a/.github/workflows/prov-compat-label.yml b/.github/workflows/prov-compat-label.yml
index cf2b44e169..94334da8e5 100644
--- a/.github/workflows/prov-compat-label.yml
+++ b/.github/workflows/prov-compat-label.yml
@@ -10,7 +10,16 @@
name: Provider compatibility for PRs
-on: [pull_request]
+on:
+ pull_request:
+ paths-ignore:
+ - 'doc/**'
+ - '*.md'
+ - '*.pod'
+ - 'README*'
+ - 'funding.json'
+ - 'LICENSE.txt'
+ - 'VERSION.dat'
permissions:
contents: read
diff --git a/.github/workflows/riscv-more-cross-compiles.yml b/.github/workflows/riscv-more-cross-compiles.yml
index cac662b8d3..069495e0f6 100644
--- a/.github/workflows/riscv-more-cross-compiles.yml
+++ b/.github/workflows/riscv-more-cross-compiles.yml
@@ -10,6 +10,14 @@ name: Cross Compile for RISC-V Extensions
on:
pull_request:
types: [opened, reopened, edited, synchronize]
+ paths-ignore:
+ - 'doc/**'
+ - '*.md'
+ - '*.pod'
+ - 'README*'
+ - 'funding.json'
+ - 'LICENSE.txt'
+ - 'VERSION.dat'
push:
schedule:
- cron: '35 02 * * *'
diff --git a/.github/workflows/run-checker-ci.yml b/.github/workflows/run-checker-ci.yml
index 70d105e3f2..89186ff03c 100644
--- a/.github/workflows/run-checker-ci.yml
+++ b/.github/workflows/run-checker-ci.yml
@@ -7,7 +7,25 @@
# Jobs run per pull request submission
name: Run-checker CI
-on: [pull_request, push]
+on:
+ pull_request:
+ paths-ignore:
+ - 'doc/**'
+ - '*.md'
+ - '*.pod'
+ - 'README*'
+ - 'funding.json'
+ - 'LICENSE.txt'
+ - 'VERSION.dat'
+ push:
+ paths-ignore:
+ - 'doc/**'
+ - '*.md'
+ - '*.pod'
+ - 'README*'
+ - 'funding.json'
+ - 'LICENSE.txt'
+ - 'VERSION.dat'
permissions:
contents: read
diff --git a/.github/workflows/style-checks.yml b/.github/workflows/style-checks.yml
index b345ae5110..f4d251681d 100644
--- a/.github/workflows/style-checks.yml
+++ b/.github/workflows/style-checks.yml
@@ -7,7 +7,16 @@
name: Coding style validation
-on: [pull_request]
+on:
+ pull_request:
+ paths-ignore:
+ - 'doc/**'
+ - '*.md'
+ - '*.pod'
+ - 'README*'
+ - 'funding.json'
+ - 'LICENSE.txt'
+ - 'VERSION.dat'
jobs:
check-style:
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index dd513c658b..eb8649f741 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -7,7 +7,26 @@
name: Windows GitHub CI
-on: [pull_request, push]
+on:
+ pull_request:
+ paths-ignore:
+ - 'doc/**'
+ - '*.md'
+ - '*.pod'
+ - 'README*'
+ - 'funding.json'
+ - 'LICENSE.txt'
+ - 'VERSION.dat'
+ push:
+ paths-ignore:
+ - 'doc/**'
+ - '*.md'
+ - '*.pod'
+ - 'README*'
+ - 'funding.json'
+ - 'LICENSE.txt'
+ - 'VERSION.dat'
+
permissions:
contents: read
@@ -190,6 +209,59 @@ jobs:
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
nmake test VERBOSE_FAILURE=yes HARNESS_JOBS=4
+ unit-tests:
+ runs-on: windows-2022
+ steps:
+ - uses: actions/checkout@v6
+ with:
+ persist-credentials: false
+ - name: checkout fuzz/corpora submodule
+ run: git submodule update --init --depth 1 fuzz/corpora
+ - name: install jom
+ if: github.repository == 'openssl/openssl'
+ run: |
+ mkdir C:\jom
+ Invoke-WebRequest -Uri "https://openssl-library.org/ci-deps/jom-1.1.7.exe" -OutFile C:\jom\jom.exe
+ $expected = (Get-Content "$env:GITHUB_WORKSPACE\.github\ci-deps.json" -Raw | ConvertFrom-Json).'jom-1.1.7.exe'
+ $actual = (Get-FileHash C:\jom\jom.exe -Algorithm SHA256).Hash
+ if ($actual -ne $expected) { throw "SHA256 mismatch for jom.exe (expected $expected, got $actual)" }
+ "C:\jom" | Out-File -FilePath "$env:GITHUB_PATH" -Append
+ - name: install jom (forks)
+ if: github.repository != 'openssl/openssl'
+ run: |
+ mkdir C:\jom
+ Invoke-WebRequest -Uri "https://download.qt.io/official_releases/jom/jom_1_1_7.zip" -OutFile C:\jom\jom.zip
+ Expand-Archive -Path C:\jom\jom.zip -DestinationPath C:\jom
+ "C:\jom" | Out-File -FilePath "$env:GITHUB_PATH" -Append
+ - name: install cmocka and detours via vcpkg
+ shell: pwsh
+ run: |
+ & "$env:VCPKG_INSTALLATION_ROOT\vcpkg.exe" install cmocka:x64-windows-static-md detours:x64-windows-static-md
+ "VCPKG_INST=$env:VCPKG_INSTALLATION_ROOT\installed\x64-windows-static-md" | Out-File -FilePath $env:GITHUB_ENV -Append
+ - name: prepare the build directory
+ run: mkdir _build
+ - name: config
+ working-directory: _build
+ shell: cmd
+ run: |
+ call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
+ perl ..\Configure VC-WIN64A --banner=Configured --strict-warnings no-makedepend no-asm enable-unit-tests ^
+ --with-cmocka-include=%VCPKG_INST%\include --with-cmocka-lib=%VCPKG_INST%\lib ^
+ --with-detours-include=%VCPKG_INST%\include --with-detours-lib=%VCPKG_INST%\lib
+ perl configdata.pm --dump
+ - name: build
+ working-directory: _build
+ shell: cmd
+ run: |
+ call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
+ jom /j4 /S
+ - name: test
+ working-directory: _build
+ shell: cmd
+ run: |
+ call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
+ jom test VERBOSE=1 TESTS=test_unit
+
minimal:
runs-on: windows-2022
steps:
diff --git a/CHANGES.md b/CHANGES.md
index 3cdace8517..8d507e4f32 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -31,6 +31,58 @@ OpenSSL Releases
### Changes between 4.0 and 4.1 [xx XXX xxxx]
+ * Fixed TLS 1.3 external PSK connections being wrongly rejected when
+ the client sets a non-empty session ID context.
+
+ *Viktor Dukhovni*
+
+ * Fixed a TLS 1.3 server with no session ID context to accept external PSK
+ connections and to stop issuing unusable session tickets.
+
+ *Viktor Dukhovni*
+
+ * Added AVX512 optimized SHAKE x4 operations for ML-DSA on `x86_64`.
+
+ *Marcel Cornu and Tomasz Kantecki*
+
+ * EC key point format simplification.
+
+ The point conversion form (compressed, uncompressed, or hybrid)
+ is now a single value on the `EC_GROUP` and round-trips
+ unchanged through import and export of `EC_KEY` objects.
+
+ Freshly generated keys have their public point encoded in
+ uncompressed form. A `point-format` supplied at key generation
+ time via `OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT` is
+ validated (an invalid value is rejected) but otherwise ignored
+ on the generated key. EC parameter generation continues to
+ honour the requested form on the group's generator; imported
+ keys keep their form.
+
+ The `ec_point_formats` extension no longer affects TLS 1.2
+ X.509 certificate selection or acceptance. OpenSSL now
+ accepts an EC certificate in any point form it can decode,
+ and sends any EC certificate it has regardless of point form.
+ TLS 1.3 disregards the extension entirely.
+
+ The RFC 4492/8422 section 5.1.2 requirement that the peer's
+ point-format list contain "uncompressed" is now enforced on
+ both sides (previously client-only), and only when an ECC
+ TLS 1.2 ciphersuite is negotiated -- a missing "uncompressed"
+ is ignored under TLS 1.3 or with a non-ECC cipher.
+
+ *Viktor Dukhovni*
+
+ * Added unit tests setup activated via `enable-unit-tests` option. This works
+ only on platforms with ld `--wrap` support (Linux, BSD).
+
+ *Jakub Zelenka*
+
+ * Deprecated the `enable-unit-test` configure option and the
+ `SSL_test_functions()` function. Both will be removed in OpenSSL 5.0.
+
+ *Jakub Zelenka*
+
* Added -testmode option for `s_time` app.
*Jakub Zelenka*
@@ -41,7 +93,7 @@ OpenSSL Releases
*Adriano Sela Aviles*
* SubjectPublicKeyInfo blobs whose AlgorithmIdentifier uses id-RSAES-OAEP
- (NID_rsaesOaep, 1.2.840.113549.1.1.7) with a plain RSAPublicKey body
+ (`NID_rsaesOaep`, 1.2.840.113549.1.1.7) with a plain RSAPublicKey body
are now decoded as RSA keys. This is required for interoperability
with TPM 1.2 Endorsement Key certificates per TCG Credential Profiles
V1.2 section 3.2.7. The OAEP AlgorithmIdentifier parameters are not
@@ -64,6 +116,17 @@ OpenSSL Releases
*Jakub Zelenka*
+ * Windows-on-Itanium (VC-WIN64I) support was dropped - the Itanium
+ architecture has been discontinued and the platform is no longer
+ supported or tested.
+
+ *Bob Beck*
+
+ * Windows CE support was dropped - Windows CE has been unsupported since
+ 2018 and does not have a modern C99 toolchain.
+
+ *Bob Beck*
+
* Improved DTLS handshake robustness under UDP reordering by buffering and
replaying early ChangeCipherSpec (CCS) records at the expected state.
@@ -78,6 +141,14 @@ OpenSSL Releases
*Bob Beck*
+ * `ASN1_STRING_set()` and `ASN1_STRING_length()` have been
+ deprecated. The replacement functions `ASN1_STRING_set_data()` or
+ `ASN1_STRING_set_string()`, and `ASN1_STRING_length_ex()` should be
+ used in their place. This prepares the ASN1_STRING type to support
+ modern size_t length values in the future.
+
+ *Bob Beck*
+
* `EVP_CIPHER_CTX_get_num()` and `EVP_CIPHER_CTX_set_num()' have been deprecated.
Refer to ossl-migration-guide(7) for more info.
@@ -119,6 +190,12 @@ OpenSSL Releases
*Bob Beck*
+ * Fixed X.509 verification of certificate chains that use DSA signatures
+ with SHA-384 or SHA-512 by registering `dsa_with_SHA384` and
+ `dsa_with_SHA512` in the signature-algorithm cross-reference table.
+
+ *John Claus*
+
* Added AVX2 optimized ML-DSA NTT operations on `x86_64`.
*Marcel Cornu and Tomasz Kantecki*
@@ -194,6 +271,11 @@ OpenSSL Releases
*Timo Keller*
+ * Added `EVP_KDF_CTX_get0_kdf()` and `EVP_KDF_CTX_get1_kdf()` functions
+ as a replacement for the now deprecated `EVP_KDF_CTX_kdf()`.
+
+ *Leon Timmermans*
+
* Add `FIPS_mode()` as a convenience define to
`EVP_default_properties_is_fips_enabled(NULL)`, which is
shorthand to check whether the `fips=yes` property is currently enabled
@@ -1268,7 +1350,9 @@ OpenSSL 4.0
*Tomáš Mráz*
* Removed deprecated functions `ERR_get_state()`, `ERR_remove_state()`
- and `ERR_remove_thread_state()`. The `ERR_STATE` object is now always opaque.
+ and `ERR_remove_thread_state()`, as well as the `ERR_FLAG_MARK`,
+ `ERR_FLAG_CLEAR` and `ERR_NUM_ERRORS` macros. The `ERR_STATE` object is now
+ always opaque.
*Tomáš Mráz*
@@ -4091,7 +4175,7 @@ breaking changes, and mappings for the large list of deprecated functions.
* Fixed a bug in the function `OCSP_basic_verify` that verifies the signer
certificate on an OCSP response. The bug caused the function in the case
- where the (non-default) flag OCSP_NOCHECKS is used to return a postivie
+ where the (non-default) flag OCSP_NOCHECKS is used to return a positive
response (meaning a successful verification) even in the case where the
response signing certificate fails to verify.
@@ -19889,7 +19973,7 @@ s-cbc 3624.96k 5258.21k 5530.91k 5624.30k 5628.26k
The new configuration file reading functions are:
NCONF_new, NCONF_free, NCONF_load, NCONF_load_fp, NCONF_load_bio,
- NCONF_get_section, NCONF_get_string, NCONF_get_numbre
+ NCONF_get_section, NCONF_get_string, NCONF_get_number
NCONF_default, NCONF_WIN32
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3813c1e23d..8101e47114 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -80,7 +80,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):
@@ -93,12 +123,14 @@ 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]
- and compile without warnings.
+ 5. Code provided should follow our [coding style](STYLE.md) and
+ [documentation policy](DOCUMENTATION.md) and compile without warnings when
+ using a --strict-warnings configuration.
+
Consistent formatting is enforced by using `clang-format` with configuration
stored in [.clang-format](.clang-format). OpenSSL uses `WebKit` style.
You can configure git pre-commit to automatically reformat your code with
@@ -112,19 +144,16 @@ guidelines:
Clean builds via GitHub Actions are required. They are started automatically
whenever a PR is created or updated by committers.
- [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.
@@ -135,10 +164,10 @@ 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).
- 9. Once your Pull Request gets to the stage of being reviewed fixup commits
+10. Once your Pull Request gets to the stage of being reviewed fixup commits
should be used where possible. Fixup commits are squashed when the PR is
finally merged. Fixup commits are done in the following way:
@@ -161,11 +190,11 @@ guidelines:
git log
```
-10. If a Pull Request addresses an [issue](https://github.com/openssl/openssl/issues/)
+11. If a Pull Request addresses an [issue](https://github.com/openssl/openssl/issues/)
the commit should include the line:
```
- Fixes #XXXXX
+ Fixes: LINK
```
- where XXXXX is the issue number.
+ where LINK is the https link to the issue in github.
diff --git a/Configurations/10-main.conf b/Configurations/10-main.conf
index a497bcce4f..9c7261c3f2 100644
--- a/Configurations/10-main.conf
+++ b/Configurations/10-main.conf
@@ -61,70 +61,6 @@ sub vc_win32_info {
return $vc_win32_info;
}
-my $vc_wince_info = {};
-sub vc_wince_info {
- unless (%$vc_wince_info) {
- # sanity check
- $die->('%OSVERSION% is not defined') if (!defined(env('OSVERSION')));
- $die->('%PLATFORM% is not defined') if (!defined(env('PLATFORM')));
- $die->('%TARGETCPU% is not defined') if (!defined(env('TARGETCPU')));
-
- #
- # Idea behind this is to mimic flags set by eVC++ IDE...
- #
- my $wcevers = env('OSVERSION'); # WCENNN
- my $wcevernum;
- my $wceverdotnum;
- if ($wcevers =~ /^WCE([1-9])([0-9]{2})$/) {
- $wcevernum = "$1$2";
- $wceverdotnum = "$1.$2";
- } else {
- $die->('%OSVERSION% value is insane');
- $wcevernum = "{unknown}";
- $wceverdotnum = "{unknown}";
- }
- my $wcecdefs = "-D_WIN32_WCE=$wcevernum -DUNDER_CE=$wcevernum"; # -D_WIN32_WCE=NNN
- my $wcelflag = "/subsystem:windowsce,$wceverdotnum"; # ...,N.NN
-
- my $wceplatf = env('PLATFORM');
-
- $wceplatf =~ tr/a-z0-9 /A-Z0-9_/;
- $wcecdefs .= " -DWCE_PLATFORM_$wceplatf";
-
- my $wcetgt = env('TARGETCPU'); # just shorter name...
- SWITCH: for($wcetgt) {
- /^X86/ && do { $wcecdefs.=" -Dx86 -D_X86_ -D_i386_ -Di_386_";
- $wcelflag.=" /machine:X86"; last; };
- /^ARMV4[IT]/ && do { $wcecdefs.=" -DARM -D_ARM_ -D$wcetgt";
- $wcecdefs.=" -DTHUMB -D_THUMB_" if($wcetgt=~/T$/);
- $wcecdefs.=" -QRarch4T -QRinterwork-return";
- $wcelflag.=" /machine:THUMB"; last; };
- /^ARM/ && do { $wcecdefs.=" -DARM -D_ARM_ -D$wcetgt";
- $wcelflag.=" /machine:ARM"; last; };
- /^MIPSIV/ && do { $wcecdefs.=" -DMIPS -D_MIPS_ -DR4000 -D$wcetgt";
- $wcecdefs.=" -D_MIPS64 -QMmips4 -QMn32";
- $wcelflag.=" /machine:MIPSFPU"; last; };
- /^MIPS16/ && do { $wcecdefs.=" -DMIPS -D_MIPS_ -DR4000 -D$wcetgt";
- $wcecdefs.=" -DMIPSII -QMmips16";
- $wcelflag.=" /machine:MIPS16"; last; };
- /^MIPSII/ && do { $wcecdefs.=" -DMIPS -D_MIPS_ -DR4000 -D$wcetgt";
- $wcecdefs.=" -QMmips2";
- $wcelflag.=" /machine:MIPS"; last; };
- /^R4[0-9]{3}/ && do { $wcecdefs.=" -DMIPS -D_MIPS_ -DR4000";
- $wcelflag.=" /machine:MIPS"; last; };
- /^SH[0-9]/ && do { $wcecdefs.=" -D$wcetgt -D_${wcetgt}_ -DSHx";
- $wcecdefs.=" -Qsh4" if ($wcetgt =~ /^SH4/);
- $wcelflag.=" /machine:$wcetgt"; last; };
- { $wcecdefs.=" -D$wcetgt -D_${wcetgt}_";
- $wcelflag.=" /machine:$wcetgt"; last; };
- }
-
- $vc_wince_info = { cppflags => $wcecdefs,
- lflags => $wcelflag };
- }
- return $vc_wince_info;
-}
-
# Helper functions for the VMS configs
my $vms_info = {};
sub vms_info {
@@ -970,7 +906,6 @@ my %targets = (
perlasm_scheme => 'void',
},
"linux64-sparcv9" => {
- # GCC 3.1 is a requirement
inherit_from => [ "linux-generic64" ],
cflags => add("-m64 -mcpu=ultrasparc"),
cxxflags => add("-m64 -mcpu=ultrasparc"),
@@ -1499,7 +1434,7 @@ my %targets = (
#### Visual C targets
#
-# Win64 targets, WIN64I denotes IA-64/Itanium and WIN64A - AMD64
+# Win64 target, WIN64A denotes AMD64
#
# Note about /wd4090, disable warning C4090. This warning returns false
# positives in some situations. Disabling it altogether masks both
@@ -1607,17 +1542,6 @@ my %targets = (
}),
bn_ops => add("SIXTY_FOUR_BIT"),
},
- "VC-WIN64I" => {
- inherit_from => [ "VC-WIN64-common" ],
- AS => "ias",
- ASFLAGS => "-d debug",
- asoutflag => "-o ",
- sys_id => "WIN64I",
- uplink_arch => 'ia64',
- asm_arch => 'ia64',
- perlasm_scheme => "ias",
- multilib => "-ia64",
- },
"VC-WIN64A" => {
inherit_from => [ "VC-WIN64-common" ],
AS => sub { vc_win64a_info()->{AS} },
@@ -1645,53 +1569,6 @@ my %targets = (
# some installation path heuristics in windows-makefile.tmpl...
build_scheme => add("VC-WOW", { separator => undef }),
},
- "VC-CE" => {
- inherit_from => [ "VC-common" ],
- CFLAGS => add(picker(debug => "/Od",
- release => "/O1i")),
- CPPDEFINES => picker(debug => [ "DEBUG", "_DEBUG" ]),
- LDFLAGS => add("/nologo /opt:ref"),
- cflags =>
- combine('/GF /Gy',
- sub { vc_wince_info()->{cflags}; },
- sub { `cl 2>&1` =~ /Version ([0-9]+)\./ && $1>=14
- ? ($disabled{shared} ? " /MT" : ($disabled{"static-vcruntime"} ? " /MD" : ""))
- : " /MC"; }),
- cppflags => sub { vc_wince_info()->{cppflags}; },
- lib_defines => add("NO_CHMOD", "OPENSSL_SMALL_FOOTPRINT"),
- lib_cppflags => sub { vc_wince_info()->{cppflags}; },
- includes =>
- add(combine(sub { defined(env('WCECOMPAT'))
- ? '$(WCECOMPAT)/include' : (); },
- sub { defined(env('PORTSDK_LIBPATH'))
- ? '$(PORTSDK_LIBPATH)/../../include'
- : (); })),
- lflags => add(combine(sub { vc_wince_info()->{lflags}; },
- sub { defined(env('PORTSDK_LIBPATH'))
- ? "/entry:mainCRTstartup" : (); })),
- sys_id => "WINCE",
- bn_ops => add("BN_LLONG"),
- ex_libs => add(sub {
- my @ex_libs = ();
- push @ex_libs, 'ws2.lib' unless $disabled{sock};
- push @ex_libs, 'crypt32.lib';
- if (defined(env('WCECOMPAT'))) {
- my $x = '$(WCECOMPAT)/lib';
- if (-f "$x/env('TARGETCPU')/wcecompatex.lib") {
- $x .= '/$(TARGETCPU)/wcecompatex.lib';
- } else {
- $x .= '/wcecompatex.lib';
- }
- push @ex_libs, $x;
- }
- push @ex_libs, '$(PORTSDK_LIBPATH)/portlib.lib'
- if (defined(env('PORTSDK_LIBPATH')));
- push @ex_libs, '/nodefaultlib coredll.lib corelibc.lib'
- if (env('TARGETCPU') =~ /^X86|^ARMV4[IT]/);
- return join(" ", @ex_libs);
- }),
- },
-
#### MinGW
"mingw-common" => {
inherit_from => [ 'BASE_unix' ],
@@ -1703,7 +1580,7 @@ my %targets = (
cppflags => combine("-DUNICODE -D_UNICODE -DWIN32_LEAN_AND_MEAN",
threads("-D_MT")),
lib_cppflags => "-DL_ENDIAN",
- ex_libs => add("-lws2_32 -lgdi32 -lcrypt32"),
+ ex_libs => add("-lws2_32 -lgdi32 -lcrypt32 -lbcrypt"),
thread_scheme => "winthreads",
dso_scheme => "win32",
shared_target => "mingw-shared",
diff --git a/Configurations/unix-Makefile.tmpl b/Configurations/unix-Makefile.tmpl
index de345a5e8a..3f9d04b6d0 100644
--- a/Configurations/unix-Makefile.tmpl
+++ b/Configurations/unix-Makefile.tmpl
@@ -11,6 +11,7 @@
our $makedepcmd = platform->makedepcmd();
sub windowsdll { $config{target} =~ /^(?:Cygwin|mingw)/ }
+ sub run_on_windows { $^O =~ /^(?:cygwin|msys|MSWin32)/ }
# Shared AIX support is special. We put libcrypto[64].so.ver into
# libcrypto.a and use libcrypto_a.a as static one, unless using
@@ -503,6 +504,9 @@ BIN_LDFLAGS={- join(' ', $target{bin_lflags} || (),
'$(CNF_LDFLAGS)', '$(LDFLAGS)') -}
BIN_EX_LIBS=$(CNF_EX_LIBS) $(EX_LIBS)
+CMOCKA_LIBS={- $config{cmocka_libs} // '' -}
+DETOURS_LIBS={- $config{detours_libs} // '' -}
+
# CPPFLAGS_Q is used for one thing only: to build up buildinf.h
CPPFLAGS_Q={- $cppflags1 =~ s|([\\"])|\\$1|g;
$cppflags2 =~ s|([\\"])|\\$1|g;
@@ -656,8 +660,8 @@ clean: libclean ## Clean the workspace, keep the configuration
-o -path './python-ecdsa' \
-o -path './tlsfuzzer' \
-o -path './tlslite-ng' \
- -o -path './wycheproof' \
- -prune \) \
+ -o -path './wycheproof' \) \
+ -prune \
-o \! -type d \
\( -name '*{- platform->depext() -}' \
-o -name '*{- platform->objext() -}' \
@@ -1579,12 +1583,24 @@ EOF
my $section = $1;
my $name = uc basename($args{src}, ".$section");
my $pod = $gen0;
- return <<"EOF";
+
+ if ($config{manpage_format} eq "mdoc") {
+ return <<"EOF";
+$args{src}: $pod
+ pod2mdoc -n $name -s $section\$(MANSUFFIX) \\
+ -d \$(RELEASE_DATE) \\
+ $pod >\$\@
+EOF
+ } elsif ($config{manpage_format} eq "roff") {
+ return <<"EOF";
$args{src}: $pod
pod2man --name=$name --section=$section\$(MANSUFFIX) --center=OpenSSL \\
--date=\$(RELEASE_DATE) --release=\$(VERSION) \\
$pod >\$\@
EOF
+ } else {
+ die "Unhandled manpage format: $config{manpage_format}";
+ }
} elsif (platform->isdef($args{src})) {
#
# Linker script-ish generator
@@ -1895,13 +1911,27 @@ $import: $full
EOF
}
}
- $recipe .= <<"EOF";
+ if (!run_on_windows()) {
+ $recipe .= <<"EOF";
$full: $fulldeps
\$(CC) \$(LIB_CFLAGS) $linkflags\$(LIB_LDFLAGS)$shared_soname$shared_imp \\
-o $full$shared_def \\
$fullobjs \\
$linklibs \$(LIB_EX_LIBS)
EOF
+ } else {
+ $recipe .= <<"EOF";
+$full: $fulldeps
+ \$(file >\$@.lst, \\
+ $fullobjs \\
+ )
+ \$(CC) \$(LIB_CFLAGS) $linkflags\$(LIB_LDFLAGS)$shared_soname$shared_imp \\
+ -o $full$shared_def \\
+ @\$@.lst \\
+ $linklibs \$(LIB_EX_LIBS)
+ rm -f \$@.lst
+EOF
+ }
if (windowsdll()) {
$recipe .= <<"EOF";
rm -f apps/$full
@@ -2006,6 +2036,15 @@ EOF
push @linkdirs, $d unless grep { $d eq $_ } @linkdirs;
}
}
+ my $wrapflags = '';
+ if (defined $unified_info{wraps}->{$args{bin}}) {
+ $wrapflags = ' ' . join(' ',
+ map { "-Wl,--wrap=$_" }
+ @{$unified_info{wraps}->{$args{bin}}});
+ }
+ my $utlibs = $unified_info{unit_test_libs}->{$args{bin}};
+ $utlibs = $utlibs ne '' ? ' ' . $utlibs : '' if defined $utlibs;
+ $utlibs //= '';
my $linkflags = join("", map { $_." " } @linkdirs);
my $linklibs = join("", map { $_." " } @linklibs);
my $cmd = '$(CC)';
@@ -2023,10 +2062,10 @@ EOF
return <<"EOF";
$bin: $deps
rm -f $bin
- \$\${LDCMD:-$cmd} $cmdflags $linkflags\$(BIN_LDFLAGS) \\
+ \$\${LDCMD:-$cmd} $cmdflags $linkflags\$(BIN_LDFLAGS)$wrapflags \\
-o $bin \\
$objs \\
- $linklibs\$(BIN_EX_LIBS)
+ $linklibs\$(BIN_EX_LIBS)$utlibs
EOF
}
sub in2script {
diff --git a/Configurations/windows-makefile.tmpl b/Configurations/windows-makefile.tmpl
index 16fed4670d..a7f2b6652b 100644
--- a/Configurations/windows-makefile.tmpl
+++ b/Configurations/windows-makefile.tmpl
@@ -380,6 +380,9 @@ BIN_LDFLAGS={- join(' ', $target{bin_lflags} || (),
'$(CNF_LDFLAGS)', '$(LDFLAGS)') -}
BIN_EX_LIBS=$(CNF_EX_LIBS) $(EX_LIBS)
+CMOCKA_LIBS={- $config{cmocka_libs} // '' -}
+DETOURS_LIBS={- $config{detours_libs} // '' -}
+
# CPPFLAGS_Q is used for one thing only: to build up buildinf.h
CPPFLAGS_Q={- $cppflags1 =~ s|([\\"])|\\$1|g;
$cppflags2 =~ s|([\\"])|\\$1|g;
@@ -1001,11 +1004,14 @@ EOF
my $ress = join($target{ld_resp_delim}, @ress);
my $linklibs = join("", map { "$_$target{ld_resp_delim}" } @deps);
my $deps = join(" ", @objs, @ress, @deps);
+ my $utlibs = $unified_info{unit_test_libs}->{$args{bin}};
+ $utlibs = (defined $utlibs && $utlibs ne '')
+ ? "$utlibs$target{ld_resp_delim}" : '';
return <<"EOF";
$bin: $deps
IF EXIST $bin.manifest DEL /F /Q $bin.manifest
\$(LD) \$(LDFLAGS) \$(BIN_LDFLAGS) @<<
-$objs$target{ld_resp_delim}\$(LDOUTFLAG)$bin$target{ldpostoutflag}$target{ld_resp_delim}$linklibs\$(BIN_EX_LIBS)$target{ldresflag}$target{ldresflag}$ress
+$objs$target{ld_resp_delim}\$(LDOUTFLAG)$bin$target{ldpostoutflag}$target{ld_resp_delim}$utlibs$linklibs\$(BIN_EX_LIBS)$target{ldresflag}$target{ldresflag}$ress
<<
IF EXIST $bin.manifest \\
\$(MT) \$(MTFLAGS) \$(MTINFLAG)$bin.manifest \$(MTOUTFLAG)$bin
diff --git a/Configure b/Configure
index 918a7c7cc0..75f1f6b67b 100755
--- a/Configure
+++ b/Configure
@@ -27,7 +27,7 @@ use OpenSSL::config;
my $orig_death_handler = $SIG{__DIE__};
$SIG{__DIE__} = \&death_handler;
-my $usage="Usage: Configure [no- ...] [enable- ...] [-Dxxx] [-lxxx] [-Lxxx] [-fxxx] [-Kxxx] [no-hw-xxx|no-hw] [[no-]threads] [[no-]thread-pool] [[no-]default-thread-pool] [[no-]shared] [[no-]zlib|zlib-dynamic] [no-asm] [no-egd] [sctp] [386] [--prefix=DIR] [--openssldir=OPENSSLDIR] [--with-xxx[=vvv]] [--config=FILE] [--help] os/compiler[:flags]\n";
+my $usage="Usage: Configure [no- ...] [enable- ...] [-Dxxx] [-lxxx] [-Lxxx] [-fxxx] [-Kxxx] [no-hw-xxx|no-hw] [[no-]threads] [[no-]thread-pool] [[no-]default-thread-pool] [[no-]shared] [[no-]zlib|zlib-dynamic] [no-asm] [no-egd] [sctp] [386] [--prefix=DIR] [--openssldir=OPENSSLDIR] [--with-xxx[=vvv]] [--config=FILE] [--manpage-format={roff,mdoc}] [--help] os/compiler[:flags]\n";
my $banner = <<"EOF";
@@ -295,6 +295,7 @@ my $dofile = abs2rel(catfile($srcdir, "util/dofile.pl"));
my $local_config_envname = 'OPENSSL_LOCAL_CONFIG_DIR';
+$config{manpage_format} = "roff";
$config{sourcedir} = abs2rel($srcdir, $blddir);
$config{builddir} = abs2rel($blddir, $blddir);
# echo -n 'holy hand grenade of antioch' | openssl sha256
@@ -577,6 +578,7 @@ my @disablables_features = (
"ubsan",
"ui-console",
"unit-test",
+ "unit-tests",
"uplink",
"weak-ssl-ciphers",
"zlib-dynamic",
@@ -654,6 +656,7 @@ our %disabled = ( # "what" => "comment"
"trace" => "default",
"ubsan" => "default",
"unit-test" => "default",
+ "unit-tests" => "default",
"weak-ssl-ciphers" => "default",
"zlib" => "default",
"zlib-dynamic" => "default",
@@ -723,7 +726,7 @@ my @disable_cascades = (
"stdio" => [ "apps", "egd" ],
"apps" => [ "tests" ],
- "tests" => [ "external-tests" ],
+ "tests" => [ "external-tests", "unit-tests" ],
"comp" => [ "zlib", "brotli", "zstd" ],
"sm3" => [ "sm2" ],
sub { !$disabled{"unit-test"} } => [ "heartbeats" ],
@@ -1042,6 +1045,10 @@ while (@argvcopy)
{
$config{build_type} = "release";
}
+ elsif (/^--manpage-format=(mdoc|roff)$/)
+ {
+ $config{manpage_format}="$1";
+ }
elsif (/^--pgo$/)
{
$config{build_type} = "pgo";
@@ -1115,6 +1122,22 @@ while (@argvcopy)
{
$withargs{fuzzer_include}=$1;
}
+ elsif (/^--with-cmocka-lib=(.*)$/)
+ {
+ $withargs{cmocka_lib}=$1;
+ }
+ elsif (/^--with-cmocka-include=(.*)$/)
+ {
+ $withargs{cmocka_include}=$1;
+ }
+ elsif (/^--with-detours-lib=(.*)$/)
+ {
+ $withargs{detours_lib}=$1;
+ }
+ elsif (/^--with-detours-include=(.*)$/)
+ {
+ $withargs{detours_include}=$1;
+ }
elsif (/^--with-rand-seed=(.*)$/)
{
foreach my $x (split(m|,|, $1))
@@ -1671,8 +1694,13 @@ unless ($disabled{asan} || defined $detected_sanitizers{asan}) {
$config{target} =~ /^VC-/ ? "/fsanitize=address" : "-fsanitize=address";
}
+my %predefined_C = compiler_predefined($config{CROSS_COMPILE}.$config{CC});
+
unless ($disabled{ubsan} || defined $detected_sanitizers{ubsan}) {
push @{$config{cflags}}, "-fsanitize=undefined", "-fno-sanitize-recover=all", "-DPEDANTIC";
+ if ($predefined_C{__clang__}) {
+ push @{$config{cflags}}, "-fno-sanitize=function";
+ }
}
unless ($disabled{msan} || defined $detected_sanitizers{msan}) {
@@ -1752,7 +1780,6 @@ if ($target{sys_id} ne "")
push @{$config{openssl_sys_defines}}, "OPENSSL_SYS_$target{sys_id}";
}
-my %predefined_C = compiler_predefined($config{CROSS_COMPILE}.$config{CC});
my %predefined_CXX = $config{CXX}
? compiler_predefined($config{CROSS_COMPILE}.$config{CXX})
: ();
@@ -1913,6 +1940,29 @@ unless ($disabled{winstore}) {
push @{$config{openssl_other_defines}}, "OPENSSL_NO_KTLS" if ($disabled{ktls});
+# Keywords accepted in a build.info UNIT_TEST[] link set.
+my @unit_test_keywords = qw(cmocka detours);
+
+unless ($disabled{"unit-tests"}) {
+ if ($target =~ /^linux/ || $target =~ /^BSD/) {
+ $config{cmocka_includes} =
+ $withargs{cmocka_include} ? [$withargs{cmocka_include}] : [];
+ $config{cmocka_libs} = $withargs{cmocka_lib}
+ ? "-L$withargs{cmocka_lib} -lcmocka" : "-lcmocka";
+ } elsif ($target =~ /^VC-/) {
+ $config{cmocka_includes} =
+ $withargs{cmocka_include} ? [$withargs{cmocka_include}] : [];
+ $config{cmocka_libs} = $withargs{cmocka_lib}
+ ? "/LIBPATH:$withargs{cmocka_lib} cmocka.lib" : "cmocka.lib";
+ $config{detours_includes} =
+ $withargs{detours_include} ? [$withargs{detours_include}] : [];
+ $config{detours_libs} = $withargs{detours_lib}
+ ? "/LIBPATH:$withargs{detours_lib} detours.lib" : "detours.lib";
+ } else {
+ disable('no-unit-test-support', 'unit-tests');
+ }
+}
+
# Get the extra flags used when building shared libraries and modules. We
# do this late because some of them depend on %disabled.
@@ -2137,6 +2187,8 @@ if ($builder eq "unified") {
my %includes = ();
my %defines = ();
my %depends = ();
+ my %unit_tests = ();
+ my %wraps = ();
my %generate = ();
my %imagedocs = ();
my %htmldocs = ();
@@ -2392,6 +2444,16 @@ if ($builder eq "unified") {
\$attributes{depends}, $+{ATTRIBS},
tokenize($expand_variables->($+{VALUE})))
if !@skip || $skip[$#skip] > 0; },
+ qr/^\s* UNIT_TEST ${index_re} \s* = \s* ${value_re} \s* $/x
+ => sub { $push_to->(\%unit_tests, $expand_variables->($+{INDEX}),
+ undef, undef,
+ tokenize($expand_variables->($+{VALUE})))
+ if !@skip || $skip[$#skip] > 0; },
+ qr/^\s* WRAP ${index_re} \s* = \s* ${value_re} \s* $/x
+ => sub { $push_to->(\%wraps, $expand_variables->($+{INDEX}),
+ undef, undef,
+ tokenize($expand_variables->($+{VALUE})))
+ if !@skip || $skip[$#skip] > 0; },
qr/^\s* GENERATE ${index_re} ${attribs_re} \s* = \s* ${value_re} \s* $/x
=> sub { $push_to->(\%generate, $expand_variables->($+{INDEX}),
\$attributes{generate}, $+{ATTRIBS},
@@ -2678,6 +2740,27 @@ if ($builder eq "unified") {
}
}
+ foreach my $dest (keys %wraps) {
+ my $ddest = cleanfile($buildd, $dest, $blddir);
+ foreach my $fn (@{$wraps{$dest}}) {
+ push @{$unified_info{wraps}->{$ddest}}, $fn;
+ }
+ }
+
+ foreach my $dest (keys %unit_tests) {
+ my $ddest = cleanfile($buildd, $dest, $blddir);
+ foreach my $kw (@{$unit_tests{$dest}}) {
+ die "***** Unknown keyword '$kw' in UNIT_TEST[$dest] at $sourced/$f\n"
+ unless grep { $_ eq $kw } @unit_test_keywords;
+ }
+ $unified_info{unit_tests}->{$ddest} =
+ [ @{$unit_tests{$dest}} ];
+ }
+ # WRAP implies cmocka unless an explicit UNIT_TEST set was given
+ foreach my $dest (keys %{$unified_info{wraps} // {}}) {
+ $unified_info{unit_tests}->{$dest} //= [ "cmocka" ];
+ }
+
foreach my $section (keys %imagedocs) {
foreach (@{$imagedocs{$section}}) {
my $imagedocs = cleanfile($buildd, $_, $blddir);
@@ -3010,6 +3093,28 @@ EOF
}
}
+# Attach cmocka (and, on Windows, Detours) include paths to unit tests,
+# based on each test's UNIT_TEST[] link set.
+if (!$disabled{"unit-tests"}) {
+ while (my ($dest, $libs) = each %{$unified_info{unit_tests} // {}}) {
+ my %want = map { $_ => 1 } @$libs;
+ push @{$unified_info{includes}->{$dest}}, @{$config{cmocka_includes}}
+ if $want{cmocka} && @{$config{cmocka_includes} // []};
+ push @{$unified_info{includes}->{$dest}}, @{$config{detours_includes}}
+ if $want{detours} && @{$config{detours_includes} // []};
+ }
+}
+
+if (!$disabled{"unit-tests"}) {
+ foreach my $dest (sort keys %{$unified_info{unit_tests} // {}}) {
+ my %want = map { $_ => 1 } @{$unified_info{unit_tests}->{$dest}};
+ my @resolved;
+ push @resolved, '$(CMOCKA_LIBS)' if $want{cmocka} && $config{cmocka_libs};
+ push @resolved, '$(DETOURS_LIBS)' if $want{detours} && $config{detours_libs};
+ $unified_info{unit_test_libs}->{$dest} = join(' ', @resolved);
+ }
+}
+
# For the schemes that need it, we provide the old *_obj configs
# from the *_asm_obj ones
foreach (grep /_(asm|aux)_src$/, keys %target) {
diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md
new file mode 100644
index 0000000000..05bbb8564c
--- /dev/null
+++ b/DOCUMENTATION.md
@@ -0,0 +1,194 @@
+OpenSSL Documentation Policy
+============================
+
+This document describes the code documentation and commenting requirements
+for the OpenSSL project.
+
+The project's documentation is about making the libraries and tools more
+accessible to our users and making the code more maintainable. This policy
+applies to new submissions; existing code does not uniformly conform to it
+and will be brought up to standard gradually.
+
+Any non-trivial change to existing code must bring the affected code into
+conformance with this policy as part of the same change. In particular,
+renaming or relocating functions, changes to public APIs, and any change
+that would render an existing POD page or in-source comment inaccurate
+require the corresponding documentation to be updated. This includes
+adding documentation that was previously absent where the change brings
+the affected code within the scope of this policy.
+
+The form and style of code comments themselves -- comment markers, layout,
+the use of `/**` and `/*-` blocks, doxygen markup, the structure of the
+sample multi-line comment, and similar -- are described in
+[STYLE.md](STYLE.md). This file describes what *must* be documented and
+where; [STYLE.md](STYLE.md) describes how code comments look.
+
+Command line commands and arguments
+-----------------------------------
+
+All new commands, as well as new or modified arguments to existing
+commands, must be documented in the `doc/man1` directory. This
+documentation is in POD format.
+
+Public symbols in the libraries
+-------------------------------
+
+All new public symbols must be documented in a POD manual page in the
+`doc/man3` directory. This includes types, macros, and functions.
+
+The allowed exceptions are:
+
+- guard macros preventing a header file being included twice
+- new symbols generated automatically via `make update` (errors, objects, etc.)
+
+Each public function's declaration in its public header must carry a
+doxygen comment block. The block's `@see` must include the function's
+own manual page (`name(3)`) and may include additional manual pages
+that a caller needs to use the function correctly. The doxygen block
+is a navigation aid pointing to the canonical reference documentation
+in the corresponding POD file; see [STYLE.md](STYLE.md) for the
+doxygen form.
+
+Overviews, conventions, et al
+-----------------------------
+
+Where additional user-facing information is required, it should be
+included in the `doc/man7` section. This includes, but is not limited to:
+
+- algorithm descriptions and parameters
+- architectural and subsystem overviews
+- user guides and tutorials
+- conventions and reference material (environment variables, glossary,
+ threading rules, file format conventions)
+
+Internal functions, structures, globals and macros
+--------------------------------------------------
+
+Internal functions, structures, globals and macros are non-public
+items declared in any header that is not part of the public API.
+These include items declared in:
+
+- `include/internal/` (shared across subsystems);
+- `include/crypto/` (cryptographic internals);
+- per-directory local headers (for example, `crypto/asn1/asn1_local.h`)
+ shared between source files in a single subdirectory.
+
+These should all be documented at the declaration site -- that is,
+in the header that declares them -- using a doxygen-style comment
+block. For functions, this places the comment at the prototype,
+where editor tooling (clangd and similar) can surface it to readers
+at every call site. The comment should describe the purpose and,
+for functions, the input and output arguments and the return value.
+See [STYLE.md](STYLE.md) for the doxygen conventions used by OpenSSL.
+
+For *trivial* items, where their operation is obvious from their
+implementation, the documentation requirement is not mandated. The
+following are generally representative of trivial items, however it is
+quite possible for any of these to be non-trivial in specific instances
+and therefore require documentation:
+
+- `OSSL_DISPATCH` tables
+- upref functions
+- free functions
+- simple getter/setter functions
+- wrappers for other functions (a function that calls a more recent
+ `_ex` variant or a group of functions that call a common internal
+ routine)
+
+For structures, each of the fields should be commented stating its
+purpose. Again, a *trivial* exception applies where the purpose is
+obvious. Some representative examples:
+
+- `OSSL_LIB_CTX *ctx;` where there is only one library context referenced
+ in the structure.
+- `struct *next;` in a linked list implementation.
+- `CRYPTO_REF_COUNT refcnt;`
+
+File-local items
+----------------
+
+These are functions, structures, globals, and macros that are local
+to a single C file: `static` functions, file-scope variables,
+structures, and macros defined inside a `.c` file with no declaration
+in any header.
+
+These should all be documented at the point of definition. Follow the
+same rules and exceptions as for internal items above. In some cases
+slightly more leniency with respect to *trivial* can be tolerated.
+
+Code comments
+-------------
+
+The form, style, and content guidance for code comments are described in
+[STYLE.md](STYLE.md). Comments are required at the points described in
+the internal and static sections above, subject to the *trivial*
+exception, and at the additional points described in
+[STYLE.md](STYLE.md).
+
+Assembly code
+-------------
+
+Assembly code should include a good description of the algorithm and
+approach being used. This should be followed by a performance comparison
+and then the assembly code itself. The assembly code should be well
+commented, but it is not necessary to comment every line. A comment
+describing each block of code suffices.
+
+For pure-assembly modules (`.s` files and the perlasm scripts that
+generate them), comments use the native syntax of the assembler or
+generator (typically `#`). Doxygen-style markup does not apply here;
+the algorithm description, performance comparison, and per-block
+comments described above are still required.
+
+For assembly that appears inline inside a C file (within an `asm()`
+statement, for example), the surrounding C function is documented
+with doxygen-style C comments as for any other C code; see
+[STYLE.md](STYLE.md). Comments inside the `asm()` body itself use
+plain C `/* */` comments.
+
+There are no *trivial* exceptions for assembly code.
+
+Configure options
+-----------------
+
+New options added to the configuration scripts must be documented in the
+[INSTALL.md](INSTALL.md) file.
+
+Changes and news
+----------------
+
+Significant modifications should be documented in the
+[CHANGES.md](CHANGES.md) file.
+
+Very significant features and changes should be documented in the
+[NEWS.md](NEWS.md) file.
+
+In both cases, the added note should be short and to the point, and
+should be written for users of the library, focusing on impact rather
+than implementation details.
+
+Automated sanity checking
+-------------------------
+
+The `make doc-nits` command should be run before submitting a pull
+request and any problems it locates must be addressed.
+
+Language
+--------
+
+The language used for documentation shall be *British English*.
+
+In general the language, abbreviations, layout and formatting should also
+correspond to the
+[LDP](https://openssl-library.org/policies/general/glossary/#ldp)
+guidelines.
+
+Common sense
+------------
+
+Comments and documentation are to improve readability and comprehension.
+Where the code is obvious, there is no need to include a comment.
+However, common sense applies: always err in favour of including more
+comments than less or none. Code that you have just written that is
+*obvious* will not necessarily be to someone else two years later. See
+[STYLE.md](STYLE.md) for the form and content of code comments.
diff --git a/INSTALL.md b/INSTALL.md
index b44e2705c0..5d132b49f0 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -169,13 +169,11 @@ issue the following commands to build OpenSSL.
$ nmake test
As mentioned in the [Choices](#choices) section, you need to pick one
-of the four Configure targets in the first command.
+of the Configure targets in the first command.
Most likely you will be using the `VC-WIN64A`/`VC-WIN64A-HYBRIDCRT` target for
64bit Windows binaries (AMD64) or `VC-WIN32`/`VC-WIN32-HYBRIDCRT` for 32bit
Windows binaries (X86).
-The other two options are `VC-WIN64I` (Intel IA64, Itanium) and
-`VC-CE` (Windows CE) are rather uncommon nowadays.
Installing OpenSSL
------------------
@@ -428,6 +426,22 @@ The names of the libraries are:
* brotlidec.lib
* brotlienc.lib
+### with-cmocka-include
+
+ --with-cmocka-include=DIR
+
+The directory for the location of the cmocka include file. This option is only
+necessary if [enable-unit-tests](#enable-unit-tests) is used and the include
+file is not already on the system include path.
+
+### with-cmocka-lib
+
+ --with-cmocka-lib=DIR
+
+The directory containing the cmocka library. This option is only necessary if
+[enable-unit-tests](#enable-unit-tests) is used and the library is not already
+on the system library path.
+
### with-zlib-include
--with-zlib-include=DIR
@@ -818,6 +832,12 @@ external test suites are currently supported:
See the file [test/README-external.md](test/README-external.md)
for further details.
+### enable-unit-tests
+
+Enable building and running unit tests.
+
+This works only on platforms supporting ld `--wrap` option like Linux and BSD.
+
### no-filenames
Don't compile in filename and line number information (e.g. for errors and
@@ -1095,10 +1115,12 @@ The User Interface console method enables text based console prompts.
### enable-unit-test
-Enable additional unit test APIs.
+Enable exposing SSL_test_functions for overwriting ssl_init_wbio_buffer.
This should not typically be used in production deployments.
+This option is deprecated and will be removed in OpenSSL 5.0.
+
### no-uplink
Don't build support for UPLINK interface.
@@ -1201,7 +1223,8 @@ Build without support for the specified algorithm.
The `ripemd` algorithm is deprecated and if used is synonymous with `rmd160`.
-### Compiler-specific options
+Compiler-specific options
+-------------------------
-Dxxx, -Ixxx, -Wp, -lxxx, -Lxxx, -Wl, -rpath, -R, -framework, -static
@@ -1232,7 +1255,17 @@ encoding.
Take note of the [Environment Variables](#environment-variables) documentation
below and how these flags interact with those variables.
-### Environment Variables
+Miscellaneous options
+---------------------
+
+### --manpage-format
+
+Specify a specific output manpage format. The supported output types are mandoc
+and *roff. The *roff output format is the default for legacy and portability
+reasons.
+
+Environment Variables
+---------------------
VAR=value
@@ -1309,10 +1342,18 @@ If `CC` is set, it is advisable to also set `CXX` to ensure both the C and C++
compiler are in the same "family". This becomes relevant with
`enable-external-tests` and `enable-buildtest-c++`.
-### Reconfigure
+Reconfigure
+-----------
- reconf
- reconfigure
+### Make targets
+
+ `$ make reconf`
+
+or
+
+ `$ make reconfigure`
+
+### Description
Reconfigure from earlier data.
@@ -1930,9 +1971,8 @@ on Cygwin, shared libraries are named `cygcrypto-1.1.dll` and `cygssl-1.1.dll`
with import libraries `libcrypto.dll.a` and `libssl.dll.a`.
On Windows build with MSVC or using MingW, shared libraries are named
-`libcrypto-1_1.dll` and `libssl-1_1.dll` for 32-bit Windows,
-`libcrypto-1_1-x64.dll` and `libssl-1_1-x64.dll` for 64-bit x86_64 Windows,
-and `libcrypto-1_1-ia64.dll` and `libssl-1_1-ia64.dll` for IA64 Windows.
+`libcrypto-1_1.dll` and `libssl-1_1.dll` for 32-bit Windows, and
+`libcrypto-1_1-x64.dll` and `libssl-1_1-x64.dll` for 64-bit x86_64 Windows.
With MSVC, the import libraries are named `libcrypto.lib` and `libssl.lib`,
while with MingW, they are named `libcrypto.dll.a` and `libssl.dll.a`.
diff --git a/NEWS.md b/NEWS.md
index 278ec1309d..239f195de0 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -31,6 +31,8 @@ OpenSSL 4.1
* API calls `CRYPTO_atomic_load_ptr`, `CRYPTO_atomic_store_ptr`, and
`CRYPTO_atomic_cmp_exch_ptr` have been added.
+ * Fixed verification of DSA certificates signed with SHA-384 or SHA-512.
+
OpenSSL 4.0
-----------
diff --git a/README.md b/README.md
index 28e2a5e51a..fcefc19923 100644
--- a/README.md
+++ b/README.md
@@ -49,7 +49,7 @@ The OpenSSL toolkit includes:
basis of the TLS implementation, but can also be used independently.
- **openssl**
- the OpenSSL command line tool, a swiss army knife for cryptographic tasks,
+ the OpenSSL command line tool, a Swiss Army knife for cryptographic tasks,
testing and analyzing. It can be used for
- creation of key parameters
- creation of X.509 certificates, CSRs and CRLs
@@ -150,11 +150,10 @@ The manual pages for the master branch and all current stable releases are
available online.
- [OpenSSL master](https://docs.openssl.org/master/)
+- [OpenSSL 4.0](https://docs.openssl.org/4.0/)
- [OpenSSL 3.6](https://docs.openssl.org/3.6/)
- [OpenSSL 3.5](https://docs.openssl.org/3.5/)
- [OpenSSL 3.4](https://docs.openssl.org/3.4/)
-- [OpenSSL 3.3](https://docs.openssl.org/3.3/)
-- [OpenSSL 3.2](https://docs.openssl.org/3.2/)
- [OpenSSL 3.0](https://docs.openssl.org/3.0/)
Demos
diff --git a/STYLE.md b/STYLE.md
new file mode 100644
index 0000000000..2bedc42a5a
--- /dev/null
+++ b/STYLE.md
@@ -0,0 +1,1133 @@
+OpenSSL Style Guide
+===================
+
+Applicability
+-------------
+
+New code in OpenSSL is expected to follow the conventions in this
+guide. Existing code does not uniformly comply and is being brought
+up to standard gradually; non-trivial changes to existing code
+should bring the affected area into compliance.
+
+When bringing an area into compliance as part of a larger change,
+do so in a separate commit -- typically one that lands first, so
+that the substantive change then operates on already-compliant
+code. Combining a compliance sweep with a behaviour change in one
+commit makes the diff hard to review and hard to revert.
+
+Do not bring code into compliance as part of a bug fix. Make the
+minimal change that fixes the bug. This holds for any bug fix, and
+especially for one that may be backported to a stable release
+branch -- and at the time of the fix you often cannot know whether
+it will be. Mixing compliance changes into a fix complicates
+backporting and makes the change larger than it needs to be. Leave
+any compliance work for a separate change.
+
+The language is C99 (ISO/IEC 9899:1999). More modern C versions
+are not yet supported on every platform OpenSSL targets and
+should be avoided.
+
+Formatting
+----------
+
+OpenSSL follows the
+[WebKit coding style for C code](https://webkit.org/code-style-guidelines/).
+In cases where the WebKit guide gives different rules for C and C++,
+OpenSSL uses the C variant.
+
+Whitespace, indentation, brace placement, line wrapping, alignment and
+the other mechanical aspects of formatting are enforced by `clang-format`
+using the [`.clang-format`](.clang-format) file at the top of this
+repository. The configuration is the WebKit C style with a small set
+of OpenSSL-specific customisations (notably the list of project
+typedefs, the `STACK_OF` / `LHASH_OF` type macros, and the list of
+statement-shaped macros).
+
+Run `clang-format` on your changes before submitting; the output of
+`clang-format` is deemed correct. See
+[CONTRIBUTING.md](CONTRIBUTING.md) for the tooling (`.pre-commit-config.yaml`,
+the `util/reformat-patches.sh` helper, and editor integrations).
+
+In rare situations it may be necessary to disable `clang-format` on a
+piece of code. This may be done with paired comments:
+
+```c
+/* clang-format off */
+I am doing something nasty here.
+Reviewers should be triggered.
+/* clang-format on */
+```
+
+This should be used sparingly, and should not be used if there is any
+other way to do what you are doing.
+
+Multi-line comment blocks have an additional clang-format opt-out
+via the `/**` and `/*-` markers; see [Comments](#comments).
+
+Naming
+------
+
+### Functions and variables
+
+A name describes what the identifier holds or what it does.
+Match the name to its role: a variable holding an `X509 *` is
+typically `cert`; one holding an `X509_STORE_CTX *` is typically
+`ctx`; a function that counts the number of active users is
+called `count_active_users()`, not `cntusr()`. Use whole words
+when there is no established short form, and reuse the same
+name across the codebase for the same concept rather than
+inventing synonyms.
+
+Names use lowercase with underscores (snake_case). For public
+functions, snake_case applies to the portion of the name after
+the uppercase subsystem prefix (see below). Do not begin a
+name with an underscore; identifiers starting with an
+underscore are reserved by the C standard in various contexts
+and can collide with toolchain or system identifiers.
+
+For variables, OpenSSL has well-established short forms that
+are fine to use without further qualification: `ctx`, `ptr`,
+`len`, `buf`, `cert`, `key`, `pkey`, `ret`, `tmp`, and similar.
+Use these in preference to longer forms; do not coin a new
+variant when one of these already covers the meaning. Use the
+suffix `_count` for a number of items, `_len` for a byte length,
+and `_size` for a size in bytes; do not invent variants like
+`num_X`, `X_length`, or `X_bytes` when one of these already
+applies.
+
+A variable that mirrors notation from a standard, RFC, paper,
+or other authoritative specification being implemented may use
+whatever name the spec uses (for example, `n`, `e`, `d` for RSA
+parameters, or `salt` and `info` for HKDF). Document the spec
+citation and which variables come from it in the function or
+file doxygen comment; see [Doxygen comments](#doxygen-comments)
+for the form.
+
+Outside spec-mirroring, single letters are appropriate only as
+loop counters (`i`, `j`, `k`).
+
+For functions, OpenSSL names follow a `PREFIX_[OBJECT_]action()`
+shape: an uppercase subsystem prefix; then, where the function
+operates on a particular object or context, that object -- usually
+the uppercase or mixed-case type name; then the action, in
+lowercase with underscores. Where the prefix already identifies
+the object, or the function is a general subsystem utility, there
+is no separate object element.
+Examples: `EVP_KDF_CTX_get0_kdf` (prefix `EVP`, object `KDF_CTX`,
+action `get0_kdf`), `EVP_PKEY_sign`, `OSSL_CMP_validate_msg`,
+`SSL_CTX_set_verify`; and, with no object element, `BIO_eof` and
+`CRYPTO_malloc`.
+
+This shape is aspirational and describes the direction for new
+code. Much of the existing API predates it and carries years of
+naming baggage, so it does not uniformly conform. Do not rename
+existing public functions to fit it -- that breaks the API.
+
+Public (API) functions use the uppercase subsystem prefix.
+Internal functions use the lowercase `ossl_` prefix unless they
+are static (i.e., local to the source file); static functions
+need no prefix.
+
+Functions that return a pointer disclose ownership of the
+returned value via a `0` or `1` suffix on the name:
+
+- `get0_X()` returns a non-owning pointer.
+- `get1_X()` returns an owning pointer; the caller is the new
+ owner, of either a fresh allocation or an up-ref.
+
+The same convention applies in reverse for setters and
+pushers that take a pointer:
+
+- `set0_X(obj, p)` and `push0_X(coll, p)` transfer ownership
+ of `p` to `obj` or `coll`.
+- `set1_X(obj, p)` and `push1_X(coll, p)` leave ownership
+ with the caller; the callee stores a copy or up-ref.
+
+Use these forms rather than a bare `get_` / `set_` / `push_`
+whenever a pointer crosses the API boundary.
+
+A function extended from an existing form takes an `_ex`
+suffix (`_ex2` for a second extension, `_ex3` for a third,
+and so on). See [Extending existing functions](#extending-existing-functions)
+for when to add an extended form and how to handle the
+parameter list.
+
+### Typedefs
+
+OpenSSL uses typedefs extensively. Struct typedefs are named in
+`ALL_CAPS_WITH_UNDERSCORES`, with a subsystem prefix, and the
+underlying struct tag is the lowercase form of the typedef name
+suffixed `_st`:
+
+```c
+typedef struct evp_pkey_st EVP_PKEY;
+```
+
+For more examples, look in ``.
+
+When a typedef'd enum is used (see [Structs and typedefs](#structs-and-typedefs)
+below for the policy on enums), the enum type name is lowercase
+and the values are uppercase.
+
+Function-pointer and callback typedefs use one of two
+suffixes:
+
+- `_cb` for typedefs that are user-supplied callbacks
+ (`X509_STORE_CTX_verify_cb`, `pem_password_cb`).
+- `_fn` for function pointers in an internal interface or
+ dispatch table (`OSSL_provider_init_fn`,
+ `X509_STORE_CTX_verify_fn`).
+
+When introducing a new type, consider that a bare or generic
+name may collide with system or third-party headers; OpenSSL
+has historically used unprefixed names like `X509` and these
+now collide with Windows headers in places. Prefix new type
+names (for example `EVP_PKEY`, `OSSL_PARAM`) to avoid this.
+
+### Macros and enum labels
+
+Macros and labels in enums should be named in
+`ALL_CAPS_WITH_UNDERSCORES`. This convention helps distinguish
+macros from functions and variables.
+
+```c
+#define OPENSSL_MAGIC_FOO 0x12345
+```
+
+Error reason codes follow a `SUBSYSTEM_R_REASON` pattern,
+where `_R_` is the infix marking the macro as an error reason:
+`X509_R_INVALID_TRUST`, `SSL_R_NO_SHARED_CIPHER`,
+`ERR_R_MALLOC_FAILURE`.
+
+Feature-disable macros follow `OPENSSL_NO_` -- for
+example, `OPENSSL_NO_SOCK` (no socket support),
+`OPENSSL_NO_RSA` (no RSA), `OPENSSL_NO_DEPRECATED__`
+(no APIs deprecated as of that version). When defined, the
+corresponding feature's headers and implementations are
+conditionally compiled out.
+
+Comments
+--------
+
+This section describes the form and style of code comments.
+[DOCUMENTATION.md](DOCUMENTATION.md) is the companion document that
+describes the policy: when a comment is required, the *trivial*
+exception, and the per-field commenting requirement on structures.
+
+Use the classic `/* ... */` comment markers. Do not use `// ...`
+markers.
+
+Comments should describe *what* the code does and *why*. Do not
+parrot the effect of each statement; well-written code is its own
+description of *how*. As the complexity of the code increases, the
+size and detail of comments should also increase. Err in favour of
+more comments rather than fewer: code that is *obvious* to you
+today will not necessarily be obvious to someone else two years
+later.
+
+### Multi-line comment blocks
+
+The preferred style for long (multi-line) comments is:
+
+```c
+/*-
+ * This is the preferred style for multi-line
+ * comments in the OpenSSL source code.
+ * Please use it consistently.
+ *
+ * Description: A column of asterisks on the left side,
+ * with beginning and ending almost-blank lines.
+ */
+```
+
+Both `/*-` and `/**` are recognised by the `CommentPragmas` setting
+in [`.clang-format`](.clang-format) and cause the block to be left
+exactly as written. Use `/*-` for plain prose comments whose layout
+you want to preserve, and `/**` for doxygen blocks (see below).
+
+### TODO and FIXME markers
+
+Use `/* TODO: */` to mark work that should be
+done later. Use `/* FIXME: */` to mark a known
+incorrectness, hack, or workaround that needs to be addressed. If
+a marker is worth adding, the underlying work is worth tracking:
+ensure a GitHub issue is opened for it and include the issue's
+full URL in the marker (e.g., `/* TODO:
+(https://github.com/openssl/openssl/issues/1234) */`). Use the URL
+form because OpenSSL has issue trackers in multiple repositories.
+
+### Doxygen comments
+
+OpenSSL code uses doxygen-style comments on functions, data
+structures, and macros to make the source easier to navigate and to
+translate into reference documentation. The internal-function,
+struct-field, and other in-source documentation requirements set out
+in [DOCUMENTATION.md](DOCUMENTATION.md) must be satisfied with
+doxygen-style comments using the conventions described below.
+
+Use the `@` form of doxygen markers (`@brief`, `@param`, `@returns`,
+`@file`, `@def`, `@struct`, and so on). Do not use the `\` form
+(`\brief`, `\param`, etc.).
+
+For the full set of recognised tags and their semantics, see the
+Doxygen manual: the [commands list](https://www.doxygen.nl/manual/commands.html)
+is the practical reference for what you can write inside a doxygen
+block; the chapter on
+[documenting the code](https://www.doxygen.nl/manual/docblocks.html)
+explains the block forms and where comments attach.
+
+The following sample illustrates the convention:
+
+```c
+/**
+ * @file doxysample.c
+ * This is a brief file description that you may add.
+ * Subsequent lines contain more detailed information about what you
+ * will find defined in this file. It is not currently required that
+ * you add a file description, but it is available if you like.
+ */
+
+/**
+ * @def MAX(x, y)
+ * Document a macro that returns the maximum of two inputs.
+ * @param x integer input value
+ * @param y integer input value
+ * @returns the maximum of x and y
+ */
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+
+/**
+ * @struct foo_st
+ * @brief Description of the foo_st struct.
+ * Optional more detailed description here.
+ */
+typedef struct foo_st {
+ int a; /**< Describe the a field here */
+ char b; /**< Describe the b field here */
+} FOO;
+
+/**
+ * @brief Describe the function ossl_add briefly.
+ * Add a more detailed description here, like sums two inputs and
+ * returns the result.
+ * @param a input integer to add
+ * @param b input integer to add
+ * @returns the sum of a and b
+ */
+int ossl_add(int a, int b);
+```
+
+#### Spec-mirroring variables
+
+When a function uses variable names taken from a specification
+(see [Functions and variables](#functions-and-variables) in the
+Naming section), the doxygen block cites the spec and identifies
+each spec-derived variable:
+
+```c
+/**
+ * @brief Transmogrify Calvin into Hobbes per RFC 31337 section 1.2.3.
+ *
+ * Variable naming follows the spec:
+ * - Calvin: input to be transmogrified
+ * - Hobbes: transmogrified output (caller-allocated)
+ *
+ * @param Calvin pointer to the input bytes to transmogrify
+ * @param Calvin_len the number of bytes available at Calvin
+ * @param Hobbes pointer to the caller-allocated output buffer
+ * @param Hobbes_len the number of bytes available at Hobbes
+ * @returns 1 on success, 0 on failure
+ * @see https://www.example.org/rfc/rfc31337.html#section-1.2.3
+ * @see https://calvinandhobbes.fandom.com/wiki/Transmogrifier
+ */
+int ossl_transmogrify(const uint8_t *Calvin, size_t Calvin_len,
+ uint8_t *Hobbes, size_t Hobbes_len);
+```
+
+#### Public functions: link the manual page
+
+Every public function declaration in a public header must carry a
+doxygen block that includes an `@see` referencing the function's
+manual page in the standard `name(3)` form. This in-source comment
+is a navigation aid; the canonical reference documentation lives in
+the POD file under `doc/man3/` (see [DOCUMENTATION.md](DOCUMENTATION.md)).
+
+The cross-reference is to the function name, not the POD file
+name; the build emits a man-page entry per function name, so
+`man X509_verify_cert` resolves regardless of which POD file
+currently documents it.
+
+```c
+/**
+ * @brief One-line summary of what the function does.
+ * @see X509_verify_cert(3)
+ */
+int X509_verify_cert(X509_STORE_CTX *ctx);
+```
+
+Additional `@see` entries may be added for any manual page a caller
+needs in order to use the function correctly, such as pages
+documenting argument types, the flag families that affect the
+function's behaviour, or closely related functions. List them
+comma-separated on a single `@see`, matching the form used in POD's
+`SEE ALSO` section:
+
+```c
+/**
+ * @brief One-line summary of what the function does.
+ * @see X509_verify_cert(3), X509_STORE_CTX_new(3),
+ * X509_VERIFY_PARAM_set_flags(3)
+ */
+int X509_verify_cert(X509_STORE_CTX *ctx);
+```
+
+The doxygen comment should not duplicate the POD content. Two
+copies of "what this function does" inevitably diverge; the POD is
+the source of truth. Keep the doxygen block to a short summary and
+the `@see` references.
+
+Structs and typedefs
+--------------------
+
+See [Typedefs](#typedefs) under Naming for naming conventions.
+
+Typedef'd enums are used much less often than struct typedefs;
+consider not using a typedef for an enum at all. A typedef'd
+enum hides the integer-ness of the type from the caller, which
+makes the implementation-defined underlying type easier to
+forget.
+
+Enum arguments to public functions are not permitted. C's `enum`
+underlying type is implementation-defined, and adding values to
+an enum can change its ABI; use `int` and document the allowed
+values instead.
+
+OpenSSL has historically made all struct definitions public, which
+caused problems with maintaining binary compatibility and adding
+features. New structs are opaque and expose only pointers in the
+API; the struct definition is placed in a local header file that
+is not exported. Legacy structs that are still part of the public
+ABI are exempt; do not add new public struct definitions.
+
+In practice, the opaque pattern is to forward-declare the typedef
+in the public header (`typedef struct foo_st FOO;`, with no struct
+body) and place the `struct foo_st { ... };` definition in a local
+header that is not exported. Callers see only the pointer type.
+
+Bitfield layout is implementation-defined and varies across
+compilers and ABIs. Where that layout is observable -- in structs
+that are part of the public ABI or that mirror a wire or file
+format -- avoid bitfields and use explicit shifts and masks on a
+regular integer instead.
+
+Flexible array members (C99 trailing `[]`) are permitted and
+preferred over the older `[1]` "struct hack" for variable-length
+trailing data. Remember that `sizeof(struct)` does not include the
+flexible member; allocate the trailing data explicitly when the
+struct is created.
+
+C99 designated initializers (`{ .field = value }`) are encouraged
+for struct initialisation, particularly where they make the field
+assignments self-documenting.
+
+A trailing comma in an initializer list is a layout hint to
+`clang-format`: with it the list is kept one element per line;
+without it the formatter may pack the list onto fewer lines.
+Most of the time you do not want a trailing comma; omit it
+unless you specifically want to lock the one-per-line layout
+(for example, in a multi-row table of values).
+
+Integers
+--------
+
+Prefer explicitly-sized integers over generic C ones where the
+size matters. To represent a byte use `uint8_t`, not
+`unsigned char`; for a two-byte field, `uint16_t` rather than
+`unsigned short`.
+
+Avoid `long` and `long long` specifically. `long` is 32 bits on
+64-bit Windows and 64 bits on 64-bit Linux; using it for "at
+least 32 bits" produces code that works inconsistently across
+platforms. Use `int32_t`, `int64_t`, `size_t`, or another
+`` type as appropriate.
+
+Sizes are `size_t`. When converting to or from `int` for legacy
+reasons, check for overflow and underflow.
+
+Add an integer literal suffix when the literal participates in a
+shift or appears in an expression involving a wider type --
+without a suffix the literal is `int`. Use `U` for unsigned
+semantics (`1U << 31`) and the `UINT8_C` through `UINT64_C`
+macros from `` for explicit widths (`UINT32_C(1) << 31`,
+`UINT64_C(1) << 63`). Avoid `UL` and `ULL`, for the same reason
+as `long` / `long long`: their widths vary by platform.
+
+Bit shifts should be performed on unsigned operands.
+Left-shifting a signed value is undefined behaviour when the
+operand is negative or when the result reaches the sign bit;
+right-shifting a signed negative value is implementation-defined.
+Combined with the literal-suffix rule above, shifts of constants
+typically take the form `UINT32_C(1) << n` or `(uint32_t)x << n`.
+
+In structs that are retained across the lifetime of a connection,
+new integer fields whose value range is known should use a smaller
+integer type (`uint8_t`, `uint16_t`) where doing so is
+straightforward. This reduces per-connection memory in server
+processes. Do not make code significantly more complex to achieve
+it, and continue to bounds-check at the struct boundary.
+
+This narrowing should not propagate to local variables or function
+parameters; those use the conventional integer types so callers
+are not forced to deal with narrow types.
+
+Do not retroactively narrow existing integer fields in legacy
+structs; this risks ABI breakage.
+
+When doing arithmetic, account for overflow.
+
+Use `int` with `0` / `1` for boolean values, both in public API
+and internal code. Do not introduce `` for new code;
+the public API convention is `int`, and using `bool` internally
+just to convert to `int` at the API boundary adds friction
+without enough benefit.
+
+Except in platform-specific code, do not use `ssize_t`; MSVC lacks
+it. Use `size_t` and signal errors out-of-band (see
+[Return values in new code](#return-values-in-new-code)).
+
+Preprocessor directives
+-----------------------
+
+Headers use traditional include guards in the `#if defined()`
+form rather than `#pragma once`, which is non-standard:
+
+```c
+#if !defined(OPENSSL_FOO_H)
+#define OPENSSL_FOO_H
+
+/* ... header contents ... */
+
+#endif /* defined(OPENSSL_FOO_H) */
+```
+
+Prefer `#if defined(FOO)` and `#if !defined(FOO)` to `#ifdef` and
+`#ifndef`. This allows logical operations when conditional
+compilation is dependent on more than one variable, without
+nesting multiple blocks.
+
+All `#endif` blocks must have a comment matching their `#if`:
+
+```c
+#if defined(OPENSSL_LINUX) && (!defined(OPENSSL_NO_HOOBLA) || !defined(OPENSSL_BULA))
+...
+#endif /* defined(OPENSSL_LINUX) && (!defined(OPENSSL_NO_HOOBLA) || !defined(OPENSSL_BULA)) */
+```
+
+Minimise the footprint of conditional compilation in source
+code: the more conditional code is concentrated and confined,
+the easier the unconditional flow is to read.
+
+Concentrate conditional compilation rather than dispersing it.
+Do not duplicate the same OS-dispatch ladder across the
+codebase:
+
+```c
+#if defined(OPENSSL_OS_FOO) || defined(OPENSSL_OS_BAR)
+ stuff the way foo or bar does it;
+#elif defined(OPENSSL_OS_BLAH) || defined(OPENSSL_OS_WOOF)
+ stuff the way blah or woof does it;
+#endif /* defined(OPENSSL_OS_FOO) || defined(OPENSSL_OS_BAR) */
+```
+
+For OS-dependent code in particular, put the directives inside
+a single function that wraps the OS-dependent work, so callers
+see a clean interface. When the OS-dependent implementations
+are large, put them in separate files (`stuff_foo.c`,
+`stuff_blah.c`) implementing a common function and select the
+appropriate file via the build process; this lets non-mainstream
+platforms add an implementation file without patching shared
+code.
+
+When a feature can be compiled out, prefer to provide a no-op
+stub implementation of its functions in the disabled case
+rather than wrapping every call site in `#if`. Callers then
+invoke the functions unconditionally and the compiler discards
+the stubs:
+
+```c
+#if defined(OPENSSL_NO_FOO)
+static ossl_inline int ossl_foo_init(void) { return 1; }
+static ossl_inline void ossl_foo_cleanup(void) { }
+#else
+int ossl_foo_init(void);
+void ossl_foo_cleanup(void);
+#endif /* defined(OPENSSL_NO_FOO) */
+```
+
+Macros and enums
+----------------
+
+**Just use a function, not a macro.** OpenSSL has historically
+used macros heavily to avoid function-call overhead, but modern
+compilers inline well; the trade-offs that justified that pattern
+no longer apply. Where a macro is genuinely unavoidable, the
+rules below apply.
+
+For the naming convention used for macros and enum labels, see the
+[Macros and enum labels](#macros-and-enum-labels) subsection of
+Naming above.
+
+Enums are preferred when defining several related constants.
+Enum arguments to public functions are not permitted, because
+C's `enum` underlying type is implementation-defined and adding
+values can change ABI; see
+[Structs and typedefs](#structs-and-typedefs) for the rule and
+the canonical alternative (use `int` and document the allowed
+values).
+
+Where the constants need a fixed underlying width (for ABI or
+wire-format reasons), use `#define` or `static const` with an
+explicit-width type from `` instead, since enum width
+is implementation-defined.
+
+### Avoid complex macros
+
+Avoid complex or clever macros: they are hard to read, debug, and
+maintain. Do not nest macros calling other macros.
+
+### Avoid function-like macros
+
+Prefer functions over function-like macros. Do not optimise for
+function-call overhead without first measuring with a function
+implementation; if the function is hot enough to need inlining,
+mark it `ossl_inline` rather than converting it to a macro.
+
+### Macro parenthesisation
+
+Always parenthesise arguments in function-like macros to prevent
+operator-precedence issues during expansion. Enclose the entire
+macro definition in parentheses if it expands to an expression, so
+the expansion evaluates correctly inside larger expressions. For
+example:
+
+```c
+#define BOB(blah) ((blah) + 42 - 23)
+```
+
+### Multi-statement macros
+
+Enclose multi-statement macros in a `do { } while (0)` block. Do
+not include a semicolon at the end, and do not use bare braces
+(which fail when followed by `else`). For example:
+
+```c
+/* This is bad. */
+#define KERMIT(x) muppet((x)); frog((x)); green((x))
+if (something)
+ KERMIT(bob);
+else /* This now breaks. */
+
+/* This is also bad, because now you have to omit the semicolon. */
+#define KERMIT(x) { muppet((x)); frog((x)); green((x)) }
+if (something)
+ KERMIT(bob) /* No semicolon. */
+else
+
+/* This works. */
+#define KERMIT(x) do { muppet((x)); frog((x)); green((x)) } while (0)
+if (something)
+ KERMIT(bob);
+else
+
+/*
+ * But just use a function -- now we know that x is an integer that
+ * has something to do with frogginess and we gain some type safety.
+ */
+static void kermit(int frogginess)
+{
+ muppet(frogginess);
+ frog(frogginess);
+ green(frogginess);
+}
+if (something)
+ kermit(bob);
+else
+```
+
+### Do not include files as multi-line macros
+
+Do not put code in a file and include it inline:
+
+```c
+ ...
+ printf("Yolo\n");
+#include "./abagfullofcode.inc"
+ printf("That was fun\n");
+ ...
+```
+
+Either make a function out of the code and call it, or put the code
+in place.
+
+### Be careful with macro arguments that have side effects
+
+Be careful when writing a function-like macro that could be called
+with arguments that have side effects. Because a macro may expand an
+argument more than once, a side-effecting argument (`n++`, a function
+call, a volatile access) can then be evaluated more than once, with
+unexpected results:
+
+```c
+#define SQUARE(x) ((x) * (x))
+
+int n = 1;
+int result = SQUARE(n++); /* expands to ((n++) * (n++)) -- evaluates twice */
+```
+
+Where it can reasonably be avoided, prefer a form that expands each
+argument exactly once -- a function, or an `ossl_inline` function
+for a fixed type. If there is any doubt that your function-like
+macro could be called with arguments that have side effects, treat
+that as a sign to follow the advice in
+[Avoid function-like macros](#avoid-function-like-macros) and make
+it a real function. Some macros cannot avoid it: a type-generic macro
+such as `MAX` must name each operand and so evaluates it more than
+once. When that is unavoidable, say so at the definition and avoid
+passing side-effecting expressions at the call site.
+
+### Avoid macros that depend on magic names
+
+Do not write macros that rely on a particular variable name being
+in scope at the call site:
+
+```c
+#define FOO(val) bar(index, (val)) /* requires `index' to exist */
+```
+
+This is confusing to the reader and prone to breakage from
+seemingly innocent changes.
+
+### Avoid macros that expand to l-values
+
+Do not write a macro that expands to something assignable:
+
+```c
+#define FIELD(p) (((struct foo *)(p))->field)
+
+FIELD(x) = y; /* legal C, but the macro hides the assignment */
+```
+
+Use an accessor function or expose the field directly through a
+typed pointer.
+
+### Avoid macros that affect control flow
+
+Do not write macros that `return`, `goto`, `break`, or `continue`
+out of their expansion. Such macros hide control flow from a
+reader at the call site, who sees what looks like a function
+call but which may exit the surrounding function or jump out of
+a loop:
+
+```c
+#define RETURN_IF_NULL(p) do { if ((p) == NULL) return -1; } while (0)
+
+int ossl_frobnicate(void *p)
+{
+ RETURN_IF_NULL(p); /* may return from ossl_frobnicate() -- not visible at the call site */
+ /* ... */
+}
+```
+
+### Avoid `#` and `##` in new code
+
+The stringification (`#`) and token-pasting (`##`) operators are
+forbidden in new code. Existing macros that use them (notably the
+`DECLARE_*` and `IMPLEMENT_*` macro families) are not retroactively
+changed; new code should achieve the same effect through
+functions.
+
+### Use variadic macros sparingly
+
+Variadic macros (`__VA_ARGS__`) are permitted but should be used
+sparingly: prefer a function or a small set of helper functions
+where possible. They are harder to reason about and debug than
+functions, and the rules around zero variadic arguments and
+`__VA_ARGS__` forwarding are subtle.
+
+Functions
+---------
+
+A function should do one thing and be short enough that a
+reader can hold its behaviour in their head while reading it.
+Length follows from complexity, not the other way around: a
+long but flat function (for example, a single switch dispatching
+to many cases) is fine; a short function with three levels of
+nested control flow is not.
+
+When complexity grows, factor out helpers with descriptive
+names. A large number of local variables is a signal that this
+factoring is overdue; consider splitting before reaching for a
+comment to explain the variables. Performance-critical helpers
+can be marked `inline`; see
+[Avoid function-like macros](#avoid-function-like-macros) for
+why this is preferable to a macro.
+
+In function prototypes, include parameter names alongside their
+types. C does not require this, but it carries useful information
+for the reader; the name in the prototype should match the name
+in the definition.
+
+### Functions with no arguments
+
+A function that takes no arguments must declare so explicitly
+with `void` in its parameter list: `int f(void);`, not
+`int f();`. The latter declares the parameter list as
+unspecified and prevents the compiler from checking calls.
+
+### Internal linkage
+
+Functions that are local to a single source file are declared
+`static`. Static functions need no `ossl_` prefix (see
+[Naming](#functions-and-variables) above) and do not appear in
+the symbol table of the resulting object file.
+
+### Parameter ordering
+
+In OpenSSL's API style, a context parameter (an `SSL_CTX *`,
+`EVP_PKEY_CTX *`, `OSSL_LIB_CTX *`, or similar) is the first
+parameter. The order of the remaining parameters is at the
+function's discretion but should be consistent with similar
+functions in the same subsystem.
+
+### `const`-correctness
+
+Pointer parameters that are not modified by the function should
+be declared `const`; likewise, pointer return values that the
+caller must not modify should be declared `const`. The
+return-side rule pairs with the `get0_X()` ownership convention:
+a non-owning pointer is typically a read-only view, while an
+owning pointer returned by `get1_X()` is non-`const` because the
+caller controls it. The `const` qualifier documents the contract,
+allows callers to pass or receive `const`-qualified data without
+casts, and lets the compiler catch accidental modification.
+
+### Return values in legacy code
+
+Historically, functions in OpenSSL can return values of many different
+kinds, and one of the most common is a value indicating whether the
+function succeeded or failed. Usually this is:
+
+- `1`: success
+- `0`: failure
+
+Other patterns appear in legacy code:
+
+- `-1` indicates a serious error (internal error or memory
+ allocation failure), and in some subsystems (BIO, SSL, etc.)
+ means "should retry"
+- `>= 1` indicates success with the value carrying additional
+ information; `<= 0` indicates failure with the value indicating
+ the reason
+
+Functions that return a computed value (not a success/failure
+indicator) are exempt.
+
+**Read the existing return-value contract carefully before
+modifying legacy code.** OpenSSL's legacy return-value
+conventions are not uniform -- a function may use values,
+overloadings, or semantics outside the patterns above -- and
+bugs have been introduced into OpenSSL when contributors
+assumed a function followed a familiar pattern when it did not.
+The contract is part of the API, not just a stylistic choice.
+
+### Return values in new code
+
+For new code, functions should return `int` with `1` on success
+and `0` on error. Do not overload the return value to both
+signal success/failure and output an integer. For example:
+
+```c
+/**
+ * @brief ossl_snuffle_thingamabob snuffles a thingamabob from bytes of input.
+ * If a valid thingamabob is snuffled, the result is stored in
+ * *out_thingamabob. On failure a snuffling error code is stored
+ * in *out_err.
+ * @param input pointer to the bytes to snuffle
+ * @param input_len the number of bytes available to snuffle from input
+ * @param out_err pointer to an integer to store an error code
+ * @param out_thingamabob pointer to a thingamabob to store the output
+ * @returns 1 if a thingamabob was snuffled and stored, 0 otherwise.
+ */
+int ossl_snuffle_thingamabob(const uint8_t *input, size_t input_len,
+ int *out_err, thingamabob *out_thingamabob);
+```
+
+If a function outputs a single pointer and no other values,
+return the pointer directly, with `NULL` on error.
+
+### Checking function arguments
+
+A public function must verify that its arguments are sensible
+and return its documented failure value if they are not.
+Typical checks include:
+
+- non-optional pointer arguments are not NULL;
+- numeric arguments are within their expected ranges.
+
+Public-API callers are outside the OpenSSL development envelope.
+The contract cannot be enforced through code review, so a NULL
+non-optional pointer or an out-of-range integer is a possibility
+that must be handled defensively at the boundary. Failing with a
+documented error code on the error stack is preferable to a
+SIGSEGV in the calling application's process.
+
+For NULL pointer arguments, the canonical pattern is:
+
+```c
+if (arg == NULL) {
+ ERR_raise(ERR_LIB_, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+}
+```
+
+Use the function's documented failure value in place of `0`
+where it differs (`NULL` for pointer-returning functions, `-1`
+for functions that may return `-1`, and so on).
+
+Internal functions must not repeat these checks. Their callers
+are us; the contract is enforceable in code review, and a NULL
+or out-of-range argument is a programmer error of the same
+character as the impossibilities discussed under
+[Assertions](#assertions). A runtime check at an internal call
+site is dead on any correct execution, and the untested branch
+is itself attack surface. Use `assert()` instead where you want
+to document an internal invariant.
+
+### Extending existing functions
+
+When an existing public function needs additional parameters,
+keep the original and add a new function with the same name plus
+an `_ex` suffix (`RAND_bytes_ex` extends `RAND_bytes`). Further
+extensions use `_ex2`, `_ex3`, and so on.
+
+The extended function preserves the existing parameters in their
+existing order. New parameters may be inserted at any position
+(they do not have to be at the end); parameters that are no
+longer needed may be removed.
+
+### Centralised exiting of functions
+
+When a function exits from multiple locations and some common
+work (such as cleanup) has to be done at every exit, use `goto`
+to a single exit label. Return directly when there is no cleanup
+to do. The rationale:
+
+- a single exit point is easier to read and follow;
+- it reduces excessive control structures and nesting;
+- it avoids errors caused by failing to update multiple exit
+ points when the code changes;
+- it lets the compiler avoid emitting redundant cleanup code.
+
+For example:
+
+```c
+int ossl_do_thing(const uint8_t *in, size_t in_len)
+{
+ int ret = 0;
+ uint8_t *buf = OPENSSL_malloc(in_len);
+
+ if (buf == NULL)
+ return 0;
+
+ if (!ossl_step1(in, in_len, buf))
+ goto out;
+ if (!ossl_step2(buf, in_len))
+ goto out;
+
+ ret = 1;
+out:
+ OPENSSL_free(buf);
+ return ret;
+}
+```
+
+Error reporting
+---------------
+
+OpenSSL surfaces errors through a per-thread error stack; see
+`ERR_raise(3)` for the calls and `include/openssl/err.h` for the
+available reason codes. This section describes the conventions
+for using them.
+
+Raise at the leaf. The function that detects the failure pushes
+the error; intermediate wrappers that propagate the failure
+value must not re-raise. Re-raising on each frame floods the
+stack with duplicates and obscures the originating condition.
+
+Use the `ERR_LIB_` corresponding to the function's
+home directory (`ERR_LIB_X509` in code under `crypto/x509/`, and
+so on). Use a cross-library reason (`ERR_R_PASSED_NULL_PARAMETER`,
+`ERR_R_MALLOC_FAILURE`, `ERR_R_INTERNAL_ERROR`, and others) for
+portable failure modes; use a `SUBSYSTEM_R_REASON`
+(`X509_R_INVALID_TRUST`, etc.) for domain-specific ones.
+
+Do not call `ERR_clear_error` at function entry; the error stack
+belongs to the caller, who may have pushed errors before
+invoking you that they intend to inspect.
+
+Use `ERR_set_mark` / `ERR_pop_to_mark` to suppress error-stack
+pollution from operations expected to fail sometimes (a
+speculative parse, a capability probe), leaving earlier errors
+intact.
+
+Allocating memory
+-----------------
+
+Use the `OPENSSL_malloc` family for general allocation; see
+`OPENSSL_malloc(3)` for the full set of calls. Do not mix these
+with the C standard library's `malloc()` / `free()` family;
+allocations made with one set must be released with the matching
+set, and OpenSSL can be built with custom allocator hooks that
+the C library does not know about.
+
+For arrays, use `OPENSSL_malloc_array()` and
+`OPENSSL_realloc_array()`, which take the element size and
+element count separately and check for integer overflow.
+
+Memory holding sensitive material (key bytes, plaintext,
+internal state of cryptographic primitives) must be cleansed
+before release. `OPENSSL_clear_free()` combines cleansing and
+freeing; `OPENSSL_cleanse()` wipes without freeing. For
+long-lived sensitive data, use the `OPENSSL_secure_malloc()`
+family (`OPENSSL_secure_malloc(3)`), which allocates from a
+separate non-pageable secure heap, and release with
+`OPENSSL_secure_clear_free()`.
+
+An API that owns internal state requires both an initialisation
+function to set it up and a completion function to release it.
+This is the standard constructor/destructor pair for opaque
+types; see [Structs and typedefs](#structs-and-typedefs).
+
+Processor-specific code
+-----------------------
+
+The only reason for processor-specific code in OpenSSL is
+performance. Every processor-specific path must have a
+platform-neutral pure-C implementation as a fallback, because
+not every target architecture or build configuration enables
+the processor-specific path. OpenSSL selects between
+implementations at runtime via the CPU-capability detection in
+`OPENSSL_cpuid_setup` and the `OPENSSL_*` capability flags;
+processor-specific code must integrate with this dispatch.
+
+Cryptographic primitives operating on secret data must execute
+in time independent of those secrets. Avoid secret-dependent
+branches, secret-indexed memory accesses, and variable-time
+arithmetic (such as variable-time multiplication or division)
+on words derived from secrets. Hand-coded asm is sometimes used
+specifically to force a particular sequence of constant-time
+operations that a compiler might otherwise rewrite.
+
+Short processor-specific operations are typically written as
+inline assembly. Use a `static inline` function when the asm
+constraints permit it. When the asm requires a compile-time
+constant operand (an `i` constraint), use a statement-expression
+macro instead, because a function parameter does not satisfy the
+immediate-constant constraint. When `asm()` has side effects the
+compiler cannot see, mark it `volatile`; do not mark `volatile`
+unnecessarily as that limits optimisation.
+
+When writing a single inline assembly statement containing
+multiple instructions, put each instruction on a separate line
+in a separate quoted string, and end each string except the
+last with `\n\t` to properly indent the next instruction in the
+assembly output:
+
+```c
+asm("magic %reg1, #42\n\t"
+ "more_magic %reg2, %reg3"
+ : /* outputs */ : /* inputs */ : /* clobbers */);
+```
+
+Large, non-trivial assembly functions go in pure assembly
+modules, with corresponding C prototypes. The preferred way to
+generate these is *perlasm*: a Perl script that generates a
+`.s` file. Perlasm allows symbolic names for variables
+(registers and stack-allocated locals) that are independent of
+the specific assembler, and supports multiple ABIs and
+assemblers from a single source by adhering to its coding
+rules. See `crypto/perlasm/x86_64-xlate.pl` for an example.
+
+Compiler intrinsics are permitted but used sparingly. They are
+appropriate for self-contained SIMD acceleration where the
+intrinsic vocabulary is well-supported across our target
+compilers and the code does not need to span multiple ABIs --
+`crypto/evp/enc_b64_avx2.c` (AVX2 base64) is an example.
+Intrinsics are not appropriate for cryptographic primitives
+where constant-time execution is required (the compiler may
+reorder, branch, or otherwise alter the timing), or where an
+existing perlasm implementation already covers the multi-ABI
+case.
+
+Assertions
+----------
+
+Assertions check programmer errors -- invariants, preconditions, and
+postconditions that must hold in any correctly-functioning build.
+They are not for runtime conditions such as allocation failure, I/O
+errors, or malformed input from callers; those are errors the
+surrounding code must handle and propagate.
+
+OpenSSL provides three assertion forms, which differ in their
+behaviour depending on whether `NDEBUG` is defined (release) or not
+(debug):
+
+| Form | Failure (debug) | Failure (release) | Success |
+|---|---|---|---|
+| `assert(e)` | abort | `e` not evaluated | no effect |
+| `ossl_assert(e)` | abort | returns 0 | returns 1 |
+| `OPENSSL_assert(e)` | abort | abort | no effect |
+
+Choosing between these forms is a trade-off, not a default. Each
+form pays a cost somewhere:
+
+- `OPENSSL_assert()` terminates the host process when an invariant
+ fails, which is hostile to applications that link against
+ OpenSSL.
+- `ossl_assert()` returns failure in release builds so the host
+ process survives, but the caller must then handle a failure for
+ a condition that, by definition, cannot occur in correct code.
+ That handling code is dead on any correct execution and cannot
+ be exercised by ordinary tests; untested branches accumulate
+ their own bugs and become part of the attack surface.
+- `assert()` is silently dropped in release builds, so an invariant
+ violation in production passes through to downstream code that
+ may then operate on inconsistent state.
+
+Use `ossl_assert()` when the surrounding function already returns
+success/failure and the recovery path collapses naturally into the
+function's existing error path: push an internal error and return
+the function's failure value. The recovery code is then colocated
+with tested error handling and is not a structurally new branch:
+
+```c
+if (!ossl_assert(invariant_holds)) {
+ ERR_raise(ERR_LIB_..., ERR_R_INTERNAL_ERROR);
+ return 0;
+}
+```
+
+Use `assert()` for impossible cases in internal code -- typically
+`switch` defaults, unreachable branches in helpers, and invariants
+local to a function whose contract makes the violation strictly
+impossible. The release-build behaviour ("do nothing") is the
+right choice here, because the alternative is untested recovery
+code for a case that cannot occur, and that code is itself a
+hazard. The assertion expression must be free of side effects,
+because `assert()` does not evaluate it in release builds.
+
+Use `OPENSSL_assert()` only when continued execution would be more
+dangerous than termination -- typically when global library state
+is irrecoverably corrupted -- or in applications, test programs,
+and fuzzers where termination on a failed check is desired.
+`OPENSSL_assert()` aborts in all builds, including production.
diff --git a/apps/asn1parse.c b/apps/asn1parse.c
index ed5ebd076f..b8449762fe 100644
--- a/apps/asn1parse.c
+++ b/apps/asn1parse.c
@@ -82,7 +82,8 @@ int asn1parse_main(int argc, char **argv)
const unsigned char *ctmpbuf;
int indent = 0, noout = 0, dump = 0, informat = FORMAT_PEM;
int offset = 0, ret = 1, i, j;
- long num, tmplen;
+ long num;
+ size_t tmplen;
const unsigned char *tmpbuf;
unsigned int length = 0;
OPTION_CHOICE o;
@@ -241,12 +242,12 @@ int asn1parse_main(int argc, char **argv)
if (sk_OPENSSL_STRING_num(osk)) {
tmpbuf = str;
- tmplen = num;
+ tmplen = (size_t)num;
for (i = 0; i < sk_OPENSSL_STRING_num(osk); i++) {
ASN1_TYPE *atmp;
int typ;
j = strtol(sk_OPENSSL_STRING_value(osk, i), NULL, 0);
- if (j <= 0 || j >= tmplen) {
+ if (j <= 0 || (size_t)j >= tmplen) {
BIO_printf(bio_err, "'%s' is out of range\n",
sk_OPENSSL_STRING_value(osk, i));
continue;
@@ -255,7 +256,7 @@ int asn1parse_main(int argc, char **argv)
tmplen -= j;
atmp = at;
ctmpbuf = tmpbuf;
- at = d2i_ASN1_TYPE(NULL, &ctmpbuf, tmplen);
+ at = d2i_ASN1_TYPE(NULL, &ctmpbuf, (long)tmplen);
ASN1_TYPE_free(atmp);
if (!at) {
BIO_puts(bio_err, "Error parsing structure\n");
@@ -272,11 +273,16 @@ int asn1parse_main(int argc, char **argv)
}
/* hmm... this is a little evil but it works */
tmpbuf = ASN1_STRING_get0_data(at->value.asn1_string);
- tmplen = ASN1_STRING_length(at->value.asn1_string);
+ tmplen = ASN1_STRING_length_ex(at->value.asn1_string);
+ if (tmplen > INT_MAX) {
+ BIO_puts(bio_err, "ASN.1 string length exceeds INT_MAX\n");
+ ERR_print_errors(bio_err);
+ goto end;
+ }
}
/* XXX casts away const */
str = (unsigned char *)tmpbuf;
- num = tmplen;
+ num = (int)tmplen;
}
if (offset < 0 || offset >= num) {
diff --git a/apps/ca.c b/apps/ca.c
index c0a58f4d16..8f98bc9a6a 100644
--- a/apps/ca.c
+++ b/apps/ca.c
@@ -1077,8 +1077,8 @@ end_of_options:
X509 *xi = sk_X509_value(cert_sk, i);
const ASN1_INTEGER *serialNumber = X509_get0_serialNumber(xi);
const unsigned char *psn = ASN1_STRING_get0_data(serialNumber);
- const int snl = ASN1_STRING_length(serialNumber);
- const int filen_len = 2 * (snl > 0 ? snl : 1) + sizeof(".pem");
+ const size_t snl = ASN1_STRING_length_ex(serialNumber);
+ const size_t filen_len = 2 * (snl > 0 ? snl : 1) + sizeof(".pem");
char *n = new_cert + outdirlen;
if (outdirlen + filen_len > PATH_MAX) {
@@ -1089,7 +1089,7 @@ end_of_options:
if (snl > 0) {
static const char HEX_DIGITS[] = "0123456789ABCDEF";
- for (j = 0; j < snl; j++, psn++) {
+ for (j = 0; (size_t)j < snl; j++, psn++) {
*n++ = HEX_DIGITS[*psn >> 4];
*n++ = HEX_DIGITS[*psn & 0x0F];
}
@@ -1523,8 +1523,10 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509,
goto end;
}
if (type != V_ASN1_BMPSTRING && type != V_ASN1_UTF8STRING) {
- j = ASN1_PRINTABLE_type(ASN1_STRING_get0_data(str),
- ASN1_STRING_length(str));
+ size_t tmp = ASN1_STRING_length_ex(str);
+ if (tmp > INT_MAX)
+ goto end;
+ j = ASN1_PRINTABLE_type(ASN1_STRING_get0_data(str), (int)tmp);
if ((j == V_ASN1_T61STRING && type != V_ASN1_T61STRING)
|| (j == V_ASN1_IA5STRING && type == V_ASN1_PRINTABLESTRING)) {
BIO_puts(bio_err,
@@ -1901,9 +1903,9 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509,
/* We now just add it to the database as DB_TYPE_VAL('V') */
row[DB_type] = OPENSSL_strdup("V");
tm = X509_get0_notAfter(ret);
- row[DB_exp_date] = app_malloc(ASN1_STRING_length(tm) + 1, "row expdate");
- memcpy(row[DB_exp_date], ASN1_STRING_get0_data(tm), ASN1_STRING_length(tm));
- row[DB_exp_date][ASN1_STRING_length(tm)] = '\0';
+ row[DB_exp_date] = app_malloc(ASN1_STRING_length_ex(tm) + 1, "row expdate");
+ memcpy(row[DB_exp_date], ASN1_STRING_get0_data(tm), ASN1_STRING_length_ex(tm));
+ row[DB_exp_date][ASN1_STRING_length_ex(tm)] = '\0';
row[DB_rev_date] = NULL;
row[DB_file] = OPENSSL_strdup("unknown");
if ((row[DB_type] == NULL) || (row[DB_file] == NULL)
@@ -2137,9 +2139,9 @@ static int do_revoke(X509 *x509, CA_DB *db, REVINFO_TYPE rev_type,
/* We now just add it to the database as DB_TYPE_REV('V') */
row[DB_type] = OPENSSL_strdup("V");
tm = X509_get0_notAfter(x509);
- row[DB_exp_date] = app_malloc(ASN1_STRING_length(tm) + 1, "row exp_data");
- memcpy(row[DB_exp_date], ASN1_STRING_get0_data(tm), ASN1_STRING_length(tm));
- row[DB_exp_date][ASN1_STRING_length(tm)] = '\0';
+ row[DB_exp_date] = app_malloc(ASN1_STRING_length_ex(tm) + 1, "row exp_data");
+ memcpy(row[DB_exp_date], ASN1_STRING_get0_data(tm), ASN1_STRING_length_ex(tm));
+ row[DB_exp_date][ASN1_STRING_length_ex(tm)] = '\0';
row[DB_rev_date] = NULL;
row[DB_file] = OPENSSL_strdup("unknown");
@@ -2350,7 +2352,7 @@ static char *make_revocation_str(REVINFO_TYPE rev_type, const char *rev_arg)
const char *reason = NULL, *other = NULL;
ASN1_OBJECT *otmp;
ASN1_UTCTIME *revtm = NULL;
- int i;
+ size_t i;
switch (rev_type) {
case REV_NONE:
@@ -2407,12 +2409,12 @@ static char *make_revocation_str(REVINFO_TYPE rev_type, const char *rev_arg)
if (!revtm)
return NULL;
- i = ASN1_STRING_length(revtm) + 1;
+ i = ASN1_STRING_length_ex(revtm) + 1;
if (reason)
- i += (int)(strlen(reason) + 1);
+ i += strlen(reason) + 1;
if (other)
- i += (int)(strlen(other) + 1);
+ i += strlen(other) + 1;
str = app_malloc(i, "revocation reason");
OPENSSL_strlcpy(str, (const char *)ASN1_STRING_get0_data(revtm), i);
@@ -2492,7 +2494,7 @@ static int old_entry_print(const ASN1_OBJECT *obj, const ASN1_STRING *str)
{
char buf[25], *pbuf;
const char *p;
- int j;
+ size_t j;
j = i2a_ASN1_OBJECT(bio_err, obj);
pbuf = buf;
@@ -2514,7 +2516,7 @@ static int old_entry_print(const ASN1_OBJECT *obj, const ASN1_STRING *str)
BIO_printf(bio_err, "ASN.1 %2d:'", ASN1_STRING_type(str));
p = (const char *)ASN1_STRING_get0_data(str);
- for (j = ASN1_STRING_length(str); j > 0; j--) {
+ for (j = ASN1_STRING_length_ex(str); j > 0; j--) {
if ((*p >= ' ') && (*p <= '~'))
BIO_printf(bio_err, "%c", *p);
else if (*p & 0x80)
diff --git a/apps/cmp.c b/apps/cmp.c
index a0770dcb97..abe6de5cb9 100644
--- a/apps/cmp.c
+++ b/apps/cmp.c
@@ -2140,7 +2140,7 @@ static int add_certProfile(OSSL_CMP_CTX *ctx, const char *name)
return 0;
if ((utf8string = ASN1_UTF8STRING_new()) == NULL)
goto err;
- if (!ASN1_STRING_set(utf8string, name, (int)strlen(name))) {
+ if (!ASN1_STRING_set_string(utf8string, name)) {
ASN1_STRING_free(utf8string);
goto err;
}
@@ -2215,7 +2215,7 @@ static int handle_opt_geninfo(OSSL_CMP_CTX *ctx)
else
*end++ = '\0';
if ((text = ASN1_UTF8STRING_new()) == NULL
- || !ASN1_STRING_set(text, ptr, -1))
+ || !ASN1_STRING_set_string(text, ptr))
goto oom;
ptr = end;
ASN1_TYPE_set(type, V_ASN1_UTF8STRING, text);
diff --git a/apps/cms.c b/apps/cms.c
index 46f9b3b11e..5e32ab55af 100644
--- a/apps/cms.c
+++ b/apps/cms.c
@@ -1580,13 +1580,15 @@ static void receipt_request_print(CMS_ContentInfo *cms)
ERR_print_errors(bio_err);
} else {
const char *id;
- int idlen;
+ size_t idlen;
CMS_ReceiptRequest_get0_values(rr, &scid, &allorfirst,
&rlist, &rto);
BIO_puts(bio_err, " Signed Content ID:\n");
- idlen = ASN1_STRING_length(scid);
+ idlen = ASN1_STRING_length_ex(scid);
+ if (idlen > INT_MAX)
+ idlen = INT_MAX;
id = (const char *)ASN1_STRING_get0_data(scid);
- BIO_dump_indent(bio_err, id, idlen, 4);
+ BIO_dump_indent(bio_err, id, (int)idlen, 4);
BIO_puts(bio_err, " Receipts From");
if (rlist != NULL) {
BIO_puts(bio_err, " List:\n");
diff --git a/apps/ec.c b/apps/ec.c
index 588b488ac1..8ed452a153 100644
--- a/apps/ec.c
+++ b/apps/ec.c
@@ -54,7 +54,7 @@ const OPTIONS ec_options[] = {
{ "check", OPT_CHECK, '-', "check key consistency" },
{ "", OPT_CIPHER, '-', "Any supported cipher" },
{ "param_enc", OPT_PARAM_ENC, 's',
- "Specifies the way the ec parameters are encoded" },
+ "Selects between named_curve and explicit EC parameter encoding" },
{ "conv_form", OPT_CONV_FORM, 's', "Specifies the point conversion form " },
OPT_SECTION("Output"),
diff --git a/apps/ecparam.c b/apps/ecparam.c
index cbb2ec8d50..aece2cb81d 100644
--- a/apps/ecparam.c
+++ b/apps/ecparam.c
@@ -57,7 +57,7 @@ const OPTIONS ecparam_options[] = {
{ "text", OPT_TEXT, '-', "Print the ec parameters in text form" },
{ "noout", OPT_NOOUT, '-', "Do not print the ec parameter" },
{ "param_enc", OPT_PARAM_ENC, 's',
- "Specifies the way the ec parameters are encoded" },
+ "Selects between named_curve and explicit EC parameter encoding" },
OPT_SECTION("Parameter"),
{ "check", OPT_CHECK, '-', "Validate the ec parameters" },
diff --git a/apps/lib/apps.c b/apps/lib/apps.c
index b2756b3b1d..b44e4b2bef 100644
--- a/apps/lib/apps.c
+++ b/apps/lib/apps.c
@@ -40,6 +40,7 @@
#include
#include
#include
+#include
#include "s_apps.h"
#include "apps.h"
@@ -605,20 +606,46 @@ EVP_PKEY *load_keyparams_suppress(const char *uri, int format, int maybe_stdin,
int suppress_decode_errors)
{
EVP_PKEY *params = NULL;
+ OSSL_DECODER_CTX *dctx = NULL;
+ BIO *file_bio = BIO_new_file(uri, "rb");
+ OSSL_LIB_CTX *libctx = app_get0_libctx();
+ const char *propq = app_get0_propq();
if (desc == NULL)
desc = "key parameters";
- (void)load_key_certs_crls(uri, format, maybe_stdin, NULL, desc,
- suppress_decode_errors,
- NULL, NULL, ¶ms, NULL, NULL, NULL, NULL, NULL);
- if (params != NULL && keytype != NULL && !EVP_PKEY_is_a(params, keytype)) {
- ERR_print_errors(bio_err);
- BIO_printf(bio_err,
- "Unable to load %s from %s (unexpected parameters type)\n",
- desc, uri);
- EVP_PKEY_free(params);
- params = NULL;
+ /*
+ * Use the store lookup path for anything that is not DER/ASN1 format
+ * Or if we are unable to opens the uri as a file.
+ */
+ if (format != FORMAT_ASN1 || file_bio == NULL) {
+ (void)load_key_certs_crls(uri, format, maybe_stdin, NULL, desc,
+ suppress_decode_errors,
+ NULL, NULL, ¶ms, NULL, NULL, NULL, NULL, NULL);
+ if (params != NULL && keytype != NULL && !EVP_PKEY_is_a(params, keytype)) {
+ ERR_print_errors(bio_err);
+ BIO_printf(bio_err,
+ "Unable to load %s from %s (unexpected parameters type)\n",
+ desc, uri);
+ EVP_PKEY_free(params);
+ params = NULL;
+ }
+ } else {
+ dctx = OSSL_DECODER_CTX_new_for_pkey(¶ms, NULL, NULL, keytype,
+ OSSL_KEYMGMT_SELECT_ALL_PARAMETERS,
+ libctx, propq);
+ if (dctx == NULL) {
+ ERR_print_errors(bio_err);
+ BIO_printf(bio_err, "Unable to allocate decoder context\n");
+ } else {
+ if (!OSSL_DECODER_from_bio(dctx, file_bio)) {
+ ERR_print_errors(bio_err);
+ BIO_printf(bio_err, "Unable to decode file %s\n", uri);
+ }
+ }
}
+
+ BIO_free(file_bio);
+ OSSL_DECODER_CTX_free(dctx);
return params;
}
@@ -1849,11 +1876,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
@@ -2799,7 +2833,7 @@ static const char *get_dp_url(DIST_POINT *dp)
for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
gen = sk_GENERAL_NAME_value(gens, i);
uri = GENERAL_NAME_get0_value(gen, >ype);
- if (gtype == GEN_URI && ASN1_STRING_length(uri) > 6) {
+ if (gtype == GEN_URI && ASN1_STRING_length_ex(uri) > 6) {
const char *uptr = (const char *)ASN1_STRING_get0_data(uri);
if (IS_HTTP(uptr)) /* can/should not use HTTPS here */
@@ -3117,14 +3151,10 @@ static int WIN32_rename(const char *from, const char *to)
if (tfrom == NULL)
goto err;
tto = tfrom + flen;
-#if !defined(_WIN32_WCE) || _WIN32_WCE >= 101
if (!MultiByteToWideChar(CP_ACP, 0, from, (int)flen, (WCHAR *)tfrom, (int)flen))
-#endif
for (i = 0; i < flen; i++)
tfrom[i] = (TCHAR)from[i];
-#if !defined(_WIN32_WCE) || _WIN32_WCE >= 101
if (!MultiByteToWideChar(CP_ACP, 0, to, (int)tlen, (WCHAR *)tto, (int)tlen))
-#endif
for (i = 0; i < tlen; i++)
tto[i] = (TCHAR)to[i];
}
@@ -3692,7 +3722,7 @@ int has_stdin_waiting(void)
int corrupt_signature(ASN1_STRING *signature)
{
const unsigned char *valid = ASN1_STRING_get0_data(signature);
- int length = ASN1_STRING_length(signature);
+ size_t length = ASN1_STRING_length_ex(signature);
unsigned char *s = OPENSSL_memdup(valid, length);
if (s == NULL)
@@ -3700,7 +3730,7 @@ int corrupt_signature(ASN1_STRING *signature)
s[length - 1] ^= 0x1;
- ASN1_STRING_set0(signature, s, length);
+ ASN1_STRING_set0(signature, s, (int)length);
return 1;
}
diff --git a/apps/lib/cmp_mock_srv.c b/apps/lib/cmp_mock_srv.c
index 43cf6af314..825a2b6709 100644
--- a/apps/lib/cmp_mock_srv.c
+++ b/apps/lib/cmp_mock_srv.c
@@ -345,7 +345,7 @@ static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
STACK_OF(ASN1_UTF8STRING) *strs;
ASN1_UTF8STRING *str;
const char *data;
- int len;
+ size_t len;
if (OBJ_obj2nid(obj) == NID_id_it_certProfile) {
if (!OSSL_CMP_ITAV_get0_certProfile(itav, &strs))
@@ -360,7 +360,7 @@ static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT);
return NULL;
}
- if (((len = ASN1_STRING_length(str)) != (int)sizeof("profile1") - 1)
+ if (((len = ASN1_STRING_length_ex(str)) != sizeof("profile1") - 1)
|| memcmp(data, "profile1", len) != 0) {
ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_CERTPROFILE);
return NULL;
diff --git a/apps/lib/opt.c b/apps/lib/opt.c
index 9c6041230b..d139346cc2 100644
--- a/apps/lib/opt.c
+++ b/apps/lib/opt.c
@@ -1236,9 +1236,7 @@ int opt_isdir(const char *name)
if (len_0 > MAX_PATH)
return -1;
-#if !defined(_WIN32_WCE) || _WIN32_WCE >= 101
if (!MultiByteToWideChar(CP_ACP, 0, name, (int)len_0, tempname, MAX_PATH))
-#endif
for (i = 0; i < len_0; i++)
tempname[i] = (WCHAR)name[i];
diff --git a/apps/lib/s_cb.c b/apps/lib/s_cb.c
index d4dcf12a07..f83ffd7236 100644
--- a/apps/lib/s_cb.c
+++ b/apps/lib/s_cb.c
@@ -576,6 +576,7 @@ static STRINT_PAIR ssl_versions[] = {
{ "TLS 1.2", TLS1_2_VERSION },
{ "TLS 1.3", TLS1_3_VERSION },
{ "DTLS 1.0", DTLS1_VERSION },
+ { "DTLS 1.2", DTLS1_2_VERSION },
{ "DTLS 1.0 (bad)", DTLS1_BAD_VER },
{ NULL }
};
@@ -653,7 +654,10 @@ void msg_cb(int write_p, int version, int content_type, const void *buf,
const char *str_version, *str_content_type = "", *str_details1 = "", *str_details2 = "";
const unsigned char *bp = buf;
- if (version == TLS1_VERSION || version == TLS1_1_VERSION || version == TLS1_2_VERSION || version == TLS1_3_VERSION || version == DTLS1_VERSION || version == DTLS1_BAD_VER) {
+ if (version == TLS1_VERSION || version == TLS1_1_VERSION
+ || version == TLS1_2_VERSION || version == TLS1_3_VERSION
+ || version == DTLS1_VERSION || version == DTLS1_2_VERSION
+ || version == DTLS1_BAD_VER) {
str_version = lookup(version, ssl_versions, "???");
switch (content_type) {
case SSL3_RT_CHANGE_CIPHER_SPEC:
@@ -775,8 +779,8 @@ static const STRINT_PAIR tlsext_types[] = {
{ NULL }
};
-/* from rfc8446 4.2.3. + gost (https://tools.ietf.org/id/draft-smyshlyaev-tls12-gost-suites-04.html) */
static STRINT_PAIR signature_tls13_scheme_list[] = {
+ /* RFC 8446 4.2.3 */
{ "rsa_pkcs1_sha1", 0x0201 /* TLSEXT_SIGALG_rsa_pkcs1_sha1 */ },
{ "ecdsa_sha1", 0x0203 /* TLSEXT_SIGALG_ecdsa_sha1 */ },
/* {"rsa_pkcs1_sha224", 0x0301 TLSEXT_SIGALG_rsa_pkcs1_sha224}, not in rfc8446 */
@@ -795,9 +799,59 @@ static STRINT_PAIR signature_tls13_scheme_list[] = {
{ "rsa_pss_pss_sha256", 0x0809 /* TLSEXT_SIGALG_rsa_pss_pss_sha256 */ },
{ "rsa_pss_pss_sha384", 0x080a /* TLSEXT_SIGALG_rsa_pss_pss_sha384 */ },
{ "rsa_pss_pss_sha512", 0x080b /* TLSEXT_SIGALG_rsa_pss_pss_sha512 */ },
+
+ /* RFC 8734 */
+ { "ecdsa_brainpoolP256r1tls13_sha256", 0x81a },
+ { "ecdsa_brainpoolP256r1tls13_sha384", 0x81b },
+ { "ecdsa_brainpoolP256r1tls13_sha512", 0x81c },
+
+ /* RFC 8998 */
+ { "sm2sig_sm3", 0x0708 /* TLSEXT_SIGALG_sm2sig_sm3 */ },
+
+ /* RFC 9367 */
+ { "gostr34102012_256a", 0x709 },
+ { "gostr34102012_256b", 0x70a },
+ { "gostr34102012_256c", 0x70b },
+ { "gostr34102012_256d", 0x70c },
+ { "gostr34102012_512a", 0x70d },
+ { "gostr34102012_512b", 0x70e },
+ { "gostr34102012_512c", 0x70f },
+
+ /* RFC 9963 */
+ { "rsa_pkcs1_sha256_legacy", 0x0420 },
+ { "rsa_pkcs1_sha384_legacy", 0x0520 },
+ { "rsa_pkcs1_sha512_legacy", 0x0620 },
+
+ /* IBS (https://datatracker.ietf.org/doc/html/draft-wang-tls-raw-public-key-with-ibc-02) */
+ { "eccsi_sha256", 0x0704 },
+ { "iso_ibs1", 0x0705 },
+ { "iso_ibs2", 0x0706 },
+ { "iso_chinese_ibs", 0x0707 },
+
+ /* ML-DSA (https://datatracker.ietf.org/doc/html/draft-ietf-tls-mldsa-00) */
+ { "mldsa44", 0x0904 },
+ { "mldsa65", 0x0905 },
+ { "mldsa87", 0x0906 },
+
+ /* SLH-DSA (https://datatracker.ietf.org/doc/html/draft-reddy-tls-slhdsa-01) */
+ { "slhdsa_sha2_128s", 0x0911 },
+ { "slhdsa_sha2_128f", 0x0912 },
+ { "slhdsa_sha2_192s", 0x0913 },
+ { "slhdsa_sha2_192f", 0x0914 },
+ { "slhdsa_sha2_256s", 0x0915 },
+ { "slhdsa_sha2_256f", 0x0916 },
+ { "slhdsa_shake_128s", 0x0917 },
+ { "slhdsa_shake_128f", 0x0918 },
+ { "slhdsa_shake_192s", 0x0919 },
+ { "slhdsa_shake_192f", 0x091a },
+ { "slhdsa_shake_256s", 0x091b },
+ { "slhdsa_shake_256f", 0x091c },
+
+ /* GOST (https://tools.ietf.org/id/draft-smyshlyaev-tls12-gost-suites-04.html) */
{ "gostr34102001", 0xeded /* TLSEXT_SIGALG_gostr34102001_gostr3411 */ },
{ "gostr34102012_256", 0xeeee /* TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256 */ },
{ "gostr34102012_512", 0xefef /* TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512 */ },
+
{ NULL }
};
@@ -1474,10 +1528,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 }
@@ -1511,7 +1562,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/apps/lib/vms_term_sock.c b/apps/lib/vms_term_sock.c
index faceb05d01..e60d7f0a1b 100644
--- a/apps/lib/vms_term_sock.c
+++ b/apps/lib/vms_term_sock.c
@@ -495,7 +495,7 @@ static int CreateSocketPair(int SocketFamily,
SocketPair[0] = SockDesc2;
SocketPair[1] = socket_fd(TcpDeviceChan);
- return (0);
+ return 0;
}
/*----------------------------------------------------------------------------*/
diff --git a/apps/ocsp.c b/apps/ocsp.c
index 2293185daf..59d33e90f2 100644
--- a/apps/ocsp.c
+++ b/apps/ocsp.c
@@ -74,7 +74,7 @@ static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio,
static int send_ocsp_response(BIO *cbio, const OCSP_RESPONSE *resp);
static char *prog;
-#ifdef HTTP_DAEMON
+#ifndef OPENSSL_NO_POSIX_IO
static int index_changed(CA_DB *);
#endif
@@ -680,7 +680,7 @@ int ocsp_main(int argc, char **argv)
redo_accept:
if (acbio != NULL) {
-#ifdef HTTP_DAEMON
+#ifndef OPENSSL_NO_POSIX_IO
if (index_changed(rdb)) {
CA_DB *newrdb = load_index(ridx_filename, NULL);
@@ -926,7 +926,7 @@ end:
return ret;
}
-#ifdef HTTP_DAEMON
+#ifndef OPENSSL_NO_POSIX_IO
static int index_changed(CA_DB *rdb)
{
@@ -937,7 +937,11 @@ static int index_changed(CA_DB *rdb)
|| rdb->dbst.st_ctime != sb.st_ctime
|| rdb->dbst.st_ino != sb.st_ino
|| rdb->dbst.st_dev != sb.st_dev) {
+#ifdef HTTP_DAEMON
syslog(LOG_INFO, "index file changed, reloading");
+#else
+ BIO_printf(bio_err, "%s: index file changed, reloading\n", prog);
+#endif
return 1;
}
}
diff --git a/apps/pkcs12.c b/apps/pkcs12.c
index f817999562..e37aefc7a3 100644
--- a/apps/pkcs12.c
+++ b/apps/pkcs12.c
@@ -833,7 +833,7 @@ int pkcs12_main(int argc, char **argv)
ASN1_INTEGER_get(pbkdf2_param->iter));
BIO_printf(bio_err, "Key length: %ld, Salt length: %d\n",
ASN1_INTEGER_get(pbkdf2_param->keylength),
- ASN1_STRING_length(pbkdf2_param->salt->value.octet_string));
+ (int)ASN1_STRING_length_ex(pbkdf2_param->salt->value.octet_string));
if (pbkdf2_param->prf == NULL) {
prfnid = NID_hmacWithSHA1;
} else {
@@ -847,8 +847,8 @@ int pkcs12_main(int argc, char **argv)
BIO_printf(bio_err, ", Iteration %ld\n",
tmaciter != NULL ? ASN1_INTEGER_get(tmaciter) : 1L);
BIO_printf(bio_err, "MAC length: %ld, salt length: %ld\n",
- tmac != NULL ? ASN1_STRING_length(tmac) : 0L,
- tsalt != NULL ? ASN1_STRING_length(tsalt) : 0L);
+ tmac != NULL ? (long)ASN1_STRING_length_ex(tmac) : 0L,
+ tsalt != NULL ? (long)ASN1_STRING_length_ex(tsalt) : 0L);
}
}
@@ -1231,7 +1231,7 @@ static int alg_print(const X509_ALGOR *alg)
}
BIO_printf(bio_err, ", Salt length: %d, Cost(N): %ld, "
"Block size(r): %ld, Parallelism(p): %ld",
- ASN1_STRING_length(kdf->salt),
+ (int)ASN1_STRING_length_ex(kdf->salt),
ASN1_INTEGER_get(kdf->costParameter),
ASN1_INTEGER_get(kdf->blockSize),
ASN1_INTEGER_get(kdf->parallelizationParameter));
@@ -1282,25 +1282,25 @@ void print_attribute(BIO *out, const ASN1_TYPE *av)
switch (av->type) {
case V_ASN1_BMPSTRING:
value = OPENSSL_uni2asc(ASN1_STRING_get0_data(av->value.bmpstring),
- ASN1_STRING_length(av->value.bmpstring));
+ (int)ASN1_STRING_length_ex(av->value.bmpstring));
BIO_printf(out, "%s\n", value);
OPENSSL_free(value);
break;
case V_ASN1_UTF8STRING:
- BIO_printf(out, "%.*s\n", ASN1_STRING_length(av->value.utf8string),
+ BIO_printf(out, "%.*s\n", (int)ASN1_STRING_length_ex(av->value.utf8string),
ASN1_STRING_get0_data(av->value.utf8string));
break;
case V_ASN1_OCTET_STRING:
hex_print(out, ASN1_STRING_get0_data(av->value.octet_string),
- ASN1_STRING_length(av->value.octet_string));
+ (int)ASN1_STRING_length_ex(av->value.octet_string));
BIO_puts(out, "\n");
break;
case V_ASN1_BIT_STRING:
hex_print(out, ASN1_STRING_get0_data(av->value.bit_string),
- ASN1_STRING_length(av->value.bit_string));
+ (int)ASN1_STRING_length_ex(av->value.bit_string));
BIO_puts(out, "\n");
break;
diff --git a/apps/pkey.c b/apps/pkey.c
index 48b091c86d..868e411820 100644
--- a/apps/pkey.c
+++ b/apps/pkey.c
@@ -72,7 +72,7 @@ const OPTIONS pkey_options[] = {
{ "ec_conv_form", OPT_EC_CONV_FORM, 's',
"Specifies the EC point conversion form in the encoding" },
{ "ec_param_enc", OPT_EC_PARAM_ENC, 's',
- "Specifies the way the EC parameters are encoded" },
+ "Selects between named_curve and explicit EC parameter encoding" },
{ NULL }
};
diff --git a/apps/rand.c b/apps/rand.c
index 7aec7b6e17..3b1647d9b1 100644
--- a/apps/rand.c
+++ b/apps/rand.c
@@ -23,6 +23,7 @@ typedef enum OPTION_choice {
OPT_OUT,
OPT_BASE64,
OPT_HEX,
+ OPT_NO_NEWLINE,
OPT_R_ENUM,
OPT_PROV_ENUM
} OPTION_CHOICE;
@@ -37,6 +38,7 @@ const OPTIONS rand_options[] = {
{ "out", OPT_OUT, '>', "Output file" },
{ "base64", OPT_BASE64, '-', "Base64 encode output" },
{ "hex", OPT_HEX, '-', "Hex encode output" },
+ { "n", OPT_NO_NEWLINE, '-', "Do not output the trailing newline" },
OPT_R_OPTIONS,
OPT_PROV_OPTIONS,
@@ -51,7 +53,7 @@ int rand_main(int argc, char **argv)
BIO *out = NULL;
char *outfile = NULL, *prog;
OPTION_CHOICE o;
- int format = FORMAT_BINARY, r, i, ret = 1;
+ int format = FORMAT_BINARY, r, i, ret = 1, newline = 1;
size_t buflen = (1 << 16); /* max rand chunk size is 2^16 bytes */
long num = -1;
uint64_t scaled_num = 0;
@@ -82,6 +84,9 @@ int rand_main(int argc, char **argv)
case OPT_HEX:
format = FORMAT_TEXT;
break;
+ case OPT_NO_NEWLINE:
+ newline = 0;
+ break;
case OPT_PROV_CASES:
if (!opt_provider(o))
goto end;
@@ -208,7 +213,7 @@ int rand_main(int argc, char **argv)
}
scaled_num -= chunk;
}
- if (format == FORMAT_TEXT)
+ if (newline && format == FORMAT_TEXT)
BIO_puts(out, "\n");
if (BIO_flush(out) <= 0)
goto end;
diff --git a/apps/req.c b/apps/req.c
index 695fd049dd..83ac38ef86 100644
--- a/apps/req.c
+++ b/apps/req.c
@@ -1254,25 +1254,21 @@ static int prompt_info(X509_REQ *req,
if (!join(buf, sizeof(buf), type, "_value", "Name"))
goto err;
- ;
value = app_conf_try_string(req_conf, attr_sect, buf);
if (!join(buf, sizeof(buf), type, "_min", "Name"))
goto err;
- ;
if (!app_conf_try_number(req_conf, attr_sect, buf, &n_min))
n_min = -1;
if (!join(buf, sizeof(buf), type, "_max", "Name"))
goto err;
- ;
if (!app_conf_try_number(req_conf, attr_sect, buf, &n_max))
n_max = -1;
if (!add_attribute_object(req,
v->value, def, value, nid, n_min,
n_max, chtype))
goto err;
- ;
}
}
} else {
diff --git a/apps/s_client.c b/apps/s_client.c
index 2d1f61a179..65aff3eb42 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -3049,6 +3049,7 @@ re_start:
ASN1_TYPE *atyp = NULL;
BIO *ldapbio = BIO_new(BIO_s_mem());
CONF *cnf = NCONF_new(NULL);
+ size_t ssl_request_len;
if (ldapbio == NULL || cnf == NULL) {
BIO_free(ldapbio);
@@ -3081,11 +3082,18 @@ re_start:
BIO_puts(bio_err, "ASN1_generate_nconf failed\n");
goto end;
}
+ ssl_request_len = ASN1_STRING_length_ex(atyp->value.sequence);
+ if (ssl_request_len > INT_MAX) {
+ NCONF_free(cnf);
+ ASN1_TYPE_free(atyp);
+ BIO_puts(bio_err, "generated NCONF size is too large\n");
+ goto end;
+ }
NCONF_free(cnf);
/* Send SSLRequest packet */
BIO_write(sbio, ASN1_STRING_get0_data(atyp->value.sequence),
- ASN1_STRING_length(atyp->value.sequence));
+ (int)ssl_request_len);
(void)BIO_flush(sbio);
ASN1_TYPE_free(atyp);
@@ -3520,29 +3528,32 @@ shut:
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/apps/s_server.c b/apps/s_server.c
index 43b212df7a..4d99e5442b 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -462,7 +462,7 @@ typedef struct tlsextctx_st {
static unsigned int ech_print_cb(SSL *s, const char *str)
{
if (str != NULL)
- BIO_printf(bio_s_out, "ECH Server callback printing: \n%s\n", str);
+ BIO_printf(bio_s_out, "ECH Server callback printing:\n%s\n", str);
return 1;
}
@@ -4020,6 +4020,7 @@ static int www_body(int s, int stype, int prot, unsigned char *context)
if (rpk_files != NULL && !rpk_enable(con)) {
BIO_puts(bio_err, "Error enabling client RPK verification\n");
+ SSL_free(con);
goto err;
}
@@ -4543,6 +4544,7 @@ static int rev_body(int s, int stype, int prot, unsigned char *context)
if (rpk_files != NULL && !rpk_enable(con)) {
BIO_puts(bio_err, "Error enabling client RPK verification\n");
ERR_print_errors(bio_err);
+ SSL_free(con);
goto err;
}
diff --git a/apps/speed.c b/apps/speed.c
index aa10d32bd5..b1732744d3 100644
--- a/apps/speed.c
+++ b/apps/speed.c
@@ -2945,7 +2945,7 @@ int speed_main(int argc, char **argv)
&outlen, loopargs[k].buf,
lengths[testnum])) {
BIO_puts(bio_err,
- "\nFailed to to encrypt the data\n");
+ "\nFailed to encrypt the data\n");
dofail();
exit(1);
}
@@ -4633,7 +4633,7 @@ static int do_multi(int multi, int size_num)
for (n = 0; n < multi; ++n) {
while (wait(&status) == -1)
if (errno != EINTR) {
- BIO_printf(bio_err, "Waitng for child failed with 0x%x\n",
+ BIO_printf(bio_err, "Waiting for child failed with 0x%x\n",
errno);
return 1;
}
diff --git a/apps/spkac.c b/apps/spkac.c
index bcf5626277..27b2392bb9 100644
--- a/apps/spkac.c
+++ b/apps/spkac.c
@@ -155,8 +155,8 @@ int spkac_main(int argc, char **argv)
if (spki == NULL)
goto end;
if (challenge != NULL
- && !ASN1_STRING_set(spki->spkac->challenge,
- challenge, (int)strlen(challenge)))
+ && !ASN1_STRING_set_string(spki->spkac->challenge,
+ challenge))
goto end;
if (!NETSCAPE_SPKI_set_pubkey(spki, pkey)) {
BIO_puts(bio_err, "Error setting public key\n");
diff --git a/apps/ts.c b/apps/ts.c
index aaec526154..2049eb9331 100644
--- a/apps/ts.c
+++ b/apps/ts.c
@@ -583,7 +583,7 @@ static ASN1_INTEGER *create_nonce(int bits)
if ((nonce = ASN1_INTEGER_new()) == NULL)
goto err;
- if (!ASN1_STRING_set(nonce, buf, len))
+ if (!ASN1_STRING_set_data(nonce, buf, len))
goto err;
ret = nonce;
diff --git a/crypto/LPdir_win.c b/crypto/LPdir_win.c
index bc5cec35d9..425a7962d0 100644
--- a/crypto/LPdir_win.c
+++ b/crypto/LPdir_win.c
@@ -36,25 +36,13 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include
#include
+#include "internal/e_os.h"
#include "internal/numbers.h"
#ifndef LPDIR_H
#include "LPdir.h"
#endif
-/*
- * We're most likely overcautious here, but let's reserve for broken WinCE
- * headers and explicitly opt for UNICODE call. Keep in mind that our WinCE
- * builds are compiled with -DUNICODE [as well as -D_UNICODE].
- */
-#if defined(LP_SYS_WINCE) && !defined(FindFirstFile)
-#define FindFirstFile FindFirstFileW
-#endif
-#if defined(LP_SYS_WINCE) && !defined(FindNextFile)
-#define FindNextFile FindNextFileW
-#endif
-
#ifndef NAME_MAX
#define NAME_MAX 255
#endif
diff --git a/crypto/LPdir_wince.c b/crypto/LPdir_wince.c
deleted file mode 100644
index e4c883dcef..0000000000
--- a/crypto/LPdir_wince.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2004-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 file is dual-licensed and is also available under the following
- * terms:
- *
- * Copyright (c) 2004, Richard Levitte
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``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 COPYRIGHT
- * OWNER 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.
- */
-
-#define LP_SYS_WINCE
-/*
- * We might want to define LP_MULTIBYTE_AVAILABLE here. It's currently under
- * investigation what the exact conditions would be
- */
-/* clang-format off */
-#include "LPdir_win.c"
-/* clang-format on */
diff --git a/crypto/armcap.c b/crypto/armcap.c
index cdb8336b13..f4f6b0d7f9 100644
--- a/crypto/armcap.c
+++ b/crypto/armcap.c
@@ -19,7 +19,7 @@
#endif
#include "internal/cryptlib.h"
#ifdef _WIN32
-#include
+#include "internal/e_os.h"
#else
#include
#endif
@@ -69,7 +69,7 @@ uint32_t OPENSSL_rdtsc(void)
/* First determine if getauxval() is available (OSSL_IMPLEMENT_GETAUXVAL) */
-#if defined(__GNUC__) && __GNUC__ >= 2
+#if defined(__GNUC__)
void OPENSSL_cpuid_setup(void) __attribute__((constructor));
#endif
@@ -415,15 +415,52 @@ 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_QCOMM, QCOM_CPU_PART_ORYON_X1) || 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_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_N3) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V3_AE) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V3) || 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_QCOMM, QCOM_CPU_PART_ORYON_X1)
+ || 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_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_N3)
+ || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V3_AE)
+ || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V3)
+ || MIDR_IMPLEMENTER(OPENSSL_arm_midr) == ARM_CPU_IMP_AMPERE
+ || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_OLYMPUS)))
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_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V3_AE) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V3) || 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_ARM, ARM_CPU_PART_N3) || MIDR_IMPLEMENTER(OPENSSL_arm_midr) == ARM_CPU_IMP_AMPERE || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_OLYMPUS)) && (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_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V3_AE)
+ || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V3)
+ || 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_ARM, ARM_CPU_PART_N3)
+ || MIDR_IMPLEMENTER(OPENSSL_arm_midr) == ARM_CPU_IMP_AMPERE
+ || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_OLYMPUS)))
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) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_QCOMM, QCOM_CPU_PART_ORYON_X1) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_OLYMPUS)) && (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)
+ || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_QCOMM, QCOM_CPU_PART_ORYON_X1)
+ || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_OLYMPUS)))
OPENSSL_armcap_P |= ARMV8_HAVE_SHA3_AND_WORTH_USING;
+
if (OPENSSL_armcap_P & ARMV9_SVE2) {
uint64_t vl_bytes = _armv8_sve_get_vl_bytes();
diff --git a/crypto/asn1/a_bitstr.c b/crypto/asn1/a_bitstr.c
index 914ff98400..fdefb80e26 100644
--- a/crypto/asn1/a_bitstr.c
+++ b/crypto/asn1/a_bitstr.c
@@ -18,7 +18,7 @@
#ifndef OPENSSL_NO_DEPRECATED_4_1
int ASN1_BIT_STRING_set(ASN1_BIT_STRING *x, unsigned char *d, int len)
{
- return ASN1_STRING_set(x, d, len);
+ return ossl_asn1_string_set_internal(x, d, len, /*add_nul_byte=*/0);
}
#endif
@@ -263,8 +263,9 @@ int ASN1_BIT_STRING_set1(ASN1_BIT_STRING *abs, const uint8_t *data, size_t lengt
if (length > 0 && (data[length - 1] & ((1 << unused_bits) - 1)) != 0)
return 0;
- if (!ASN1_STRING_set(abs, data, (int)length))
+ if (!ossl_asn1_string_set_internal(abs, data, (int)length, /*add_nul_byte=*/0))
return 0;
+
abs->type = V_ASN1_BIT_STRING;
ossl_asn1_bit_string_set_unused_bits(abs, unused_bits);
diff --git a/crypto/asn1/a_d2i_fp.c b/crypto/asn1/a_d2i_fp.c
index 8f9e267689..41491b92a1 100644
--- a/crypto/asn1/a_d2i_fp.c
+++ b/crypto/asn1/a_d2i_fp.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
@@ -141,7 +141,20 @@ int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
i = BIO_read(in, &(b->data[len]), (int)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;
}
diff --git a/crypto/asn1/a_int.c b/crypto/asn1/a_int.c
index 3b10ee99e5..10db6b6a3c 100644
--- a/crypto/asn1/a_int.c
+++ b/crypto/asn1/a_int.c
@@ -316,7 +316,7 @@ ASN1_INTEGER *ossl_c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp,
} else
ret = *a;
- if (r > INT_MAX || ASN1_STRING_set(ret, NULL, (int)r) == 0) {
+ if (ASN1_STRING_set_data(ret, NULL, r) == 0) {
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
goto err;
}
@@ -371,7 +371,7 @@ static int asn1_string_set_int64(ASN1_STRING *a, int64_t r, int itype)
off = asn1_put_uint64(tbuf, r);
a->type &= ~V_ASN1_NEG;
}
- return ASN1_STRING_set(a, tbuf + off, (int)(sizeof(tbuf) - off));
+ return ASN1_STRING_set_data(a, tbuf + off, (sizeof(tbuf) - off));
}
static int asn1_string_get_uint64(uint64_t *pr, const ASN1_STRING *a,
@@ -399,7 +399,7 @@ static int asn1_string_set_uint64(ASN1_STRING *a, uint64_t r, int itype)
a->type = itype;
off = asn1_put_uint64(tbuf, r);
- return ASN1_STRING_set(a, tbuf + off, (int)(sizeof(tbuf) - off));
+ return ASN1_STRING_set_data(a, tbuf + off, (sizeof(tbuf) - off));
}
/*
@@ -503,7 +503,7 @@ static ASN1_STRING *bn_to_asn1_string(const BIGNUM *bn, ASN1_STRING *ai,
if (len == 0)
len = 1;
- if (ASN1_STRING_set(ret, NULL, len) == 0) {
+ if (ASN1_STRING_set_data(ret, NULL, len) == 0) {
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
goto err;
}
diff --git a/crypto/asn1/a_mbstr.c b/crypto/asn1/a_mbstr.c
index 236082ec39..e70fe92db5 100644
--- a/crypto/asn1/a_mbstr.c
+++ b/crypto/asn1/a_mbstr.c
@@ -69,6 +69,9 @@ int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
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 */
@@ -168,7 +171,7 @@ int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
}
/* If both the same type just copy across */
if (inform == outform) {
- if (!ASN1_STRING_set(dest, in, len)) {
+ if (!ASN1_STRING_set_data(dest, in, len)) {
if (free_out) {
ASN1_STRING_free(dest);
*out = NULL;
@@ -305,7 +308,7 @@ static int out_utf8(uint32_t 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/crypto/asn1/a_octet.c b/crypto/asn1/a_octet.c
index 4efb8ec517..99df7539a1 100644
--- a/crypto/asn1/a_octet.c
+++ b/crypto/asn1/a_octet.c
@@ -25,5 +25,11 @@ int ASN1_OCTET_STRING_cmp(const ASN1_OCTET_STRING *a,
int ASN1_OCTET_STRING_set(ASN1_OCTET_STRING *x, const unsigned char *d,
int len)
{
- return ASN1_STRING_set(x, d, len);
+ if (len < -1) {
+ ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_SMALL);
+ return 0;
+ }
+ if (len == -1)
+ return ASN1_STRING_set_string(x, (const char *)d);
+ return ASN1_STRING_set_data(x, d, len);
}
diff --git a/crypto/asn1/a_strex.c b/crypto/asn1/a_strex.c
index e488c87f5b..4315355632 100644
--- a/crypto/asn1/a_strex.c
+++ b/crypto/asn1/a_strex.c
@@ -12,6 +12,7 @@
#include "internal/cryptlib.h"
#include "internal/sizes.h"
#include "internal/unicode.h"
+#include "internal/safe_math.h"
#include "crypto/asn1.h"
#include
#include
@@ -31,6 +32,8 @@
#define ESC_FLAGS (ASN1_STRFLGS_ESC_2253 | ASN1_STRFLGS_ESC_2254 | ASN1_STRFLGS_ESC_QUOTE | ASN1_STRFLGS_ESC_CTRL | ASN1_STRFLGS_ESC_MSB)
+OSSL_SAFE_MATH_SIGNED(int, int)
+
/*
* Three IO functions for sending data to memory, a BIO and a FILE
* pointer.
@@ -142,6 +145,10 @@ static int do_buf(const unsigned char *buf, int buflen,
const unsigned char *p, *q;
uint32_t c;
+ if (buflen < 0)
+ return -1;
+ if (buflen == 0)
+ return 0;
p = buf;
q = buf + buflen;
outlen = 0;
@@ -236,6 +243,10 @@ static int do_hex_dump(char_io *io_ch, void *arg, unsigned char *buf,
unsigned char *p, *q;
char hextmp[2];
+ if (buflen < 0)
+ return -1;
+ if (buflen == 0)
+ return 0;
if (arg) {
p = buf;
q = buf + buflen;
@@ -430,6 +441,7 @@ static int do_name_ex(char_io *io_ch, void *arg, const X509_NAME *n,
char objtmp[80];
const char *objbuf;
int outlen, len;
+ int err = 0;
char *sep_dn, *sep_mv, *sep_eq;
int sep_dn_len, sep_mv_len, sep_eq_len;
if (indent < 0)
@@ -493,14 +505,20 @@ static int do_name_ex(char_io *io_ch, void *arg, const X509_NAME *n,
if (prev == X509_NAME_ENTRY_set(ent)) {
if (!io_ch(arg, sep_mv, sep_mv_len))
return -1;
- outlen += sep_mv_len;
+ outlen = safe_add_int(outlen, sep_mv_len, &err);
+ if (err != 0)
+ return -1;
} else {
if (!io_ch(arg, sep_dn, sep_dn_len))
return -1;
- outlen += sep_dn_len;
+ outlen = safe_add_int(outlen, sep_dn_len, &err);
+ if (err != 0)
+ return -1;
if (!do_indent(io_ch, arg, indent))
return -1;
- outlen += indent;
+ outlen = safe_add_int(outlen, indent, &err);
+ if (err != 0)
+ return -1;
}
}
prev = X509_NAME_ENTRY_set(ent);
@@ -531,11 +549,18 @@ static int do_name_ex(char_io *io_ch, void *arg, const X509_NAME *n,
if ((objlen < fld_len) && (flags & XN_FLAG_FN_ALIGN)) {
if (!do_indent(io_ch, arg, fld_len - objlen))
return -1;
- outlen += fld_len - objlen;
+ outlen = safe_add_int(outlen, fld_len - objlen, &err);
+ if (err != 0)
+ return -1;
}
if (!io_ch(arg, sep_eq, sep_eq_len))
return -1;
- outlen += objlen + sep_eq_len;
+ outlen = safe_add_int(outlen, objlen, &err);
+ if (err != 0)
+ return -1;
+ outlen = safe_add_int(outlen, sep_eq_len, &err);
+ if (err != 0)
+ return -1;
}
/*
* If the field name is unknown then fix up the DER dump flag. We
@@ -550,7 +575,9 @@ static int do_name_ex(char_io *io_ch, void *arg, const X509_NAME *n,
len = do_print_ex(io_ch, arg, flags | orflags, val);
if (len < 0)
return -1;
- outlen += len;
+ outlen = safe_add_int(outlen, len, &err);
+ if (err != 0)
+ return -1;
}
return outlen;
}
diff --git a/crypto/asn1/a_time.c b/crypto/asn1/a_time.c
index 56366fe531..341bd5142d 100644
--- a/crypto/asn1/a_time.c
+++ b/crypto/asn1/a_time.c
@@ -271,7 +271,7 @@ ASN1_TIME *ossl_asn1_time_from_tm(ASN1_TIME *s, struct tm *ts, int type)
if (tmps == NULL)
return NULL;
- if (!ASN1_STRING_set(tmps, NULL, len))
+ if (!ASN1_STRING_set_data(tmps, NULL, len))
goto err;
tmps->type = type;
diff --git a/crypto/asn1/asn1_gen.c b/crypto/asn1/asn1_gen.c
index 35abf85ca4..6fbf581b49 100644
--- a/crypto/asn1/asn1_gen.c
+++ b/crypto/asn1/asn1_gen.c
@@ -651,7 +651,7 @@ static ASN1_TYPE *asn1_str2type(const char *str, int format, int utype)
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
goto bad_str;
}
- if (!ASN1_STRING_set(atmp->value.asn1_string, str, -1)) {
+ if (!ASN1_STRING_set_string(atmp->value.asn1_string, str)) {
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
goto bad_str;
}
@@ -706,7 +706,7 @@ static ASN1_TYPE *asn1_str2type(const char *str, int format, int utype)
atmp->value.asn1_string->length = rdlen;
atmp->value.asn1_string->type = utype;
} else if (format == ASN1_GEN_FORMAT_ASCII) {
- if (!ASN1_STRING_set(atmp->value.asn1_string, str, -1)) {
+ if (!ASN1_STRING_set_string(atmp->value.asn1_string, str)) {
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
goto bad_str;
}
diff --git a/crypto/asn1/asn1_lib.c b/crypto/asn1/asn1_lib.c
index 99903564e2..4b9e720bad 100644
--- a/crypto/asn1/asn1_lib.c
+++ b/crypto/asn1/asn1_lib.c
@@ -265,7 +265,8 @@ int ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *str)
if (str == NULL)
return 0;
dst->type = str->type;
- if (!ASN1_STRING_set(dst, str->data, str->length))
+ if (!ossl_asn1_string_set_internal(dst, str->data, str->length,
+ /*add_nul_byte=*/0))
return 0;
/* Copy flags but preserve embed value */
dst->flags &= ASN1_STRING_FLAG_EMBED;
@@ -289,12 +290,18 @@ ASN1_STRING *ASN1_STRING_dup(const ASN1_STRING *str)
return ret;
}
-int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len_in)
+int ossl_asn1_string_set_internal(ASN1_STRING *str, const uint8_t *data,
+ int len_in, int add_nul_byte)
{
- unsigned char *c;
- const char *data = _data;
- size_t len;
+ size_t len, alloc_len;
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ /*
+ * Force no NUL byte for callers that are requesting it
+ * 0 length object data will be NULL
+ */
+ add_nul_byte = 0;
+#endif
if (len_in < -1) {
ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_SMALL);
return 0;
@@ -302,16 +309,17 @@ int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len_in)
if (len_in == -1) {
if (data == NULL)
return 0;
- len = strlen(data);
+ len = strlen((const char *)data);
} else {
len = (size_t)len_in;
}
/*
- * Verify that the length fits within an integer for assignment to
- * str->length below. The additional 1 is subtracted to allow for the
- * '\0' terminator even though this isn't strictly necessary.
+ * Add one to the length to allow for adding an a '\0' terminator
+ * "even though this isn't strictly necessary".
*/
- if (len > INT_MAX - 1) {
+ alloc_len = add_nul_byte ? len + 1 : len;
+
+ if (alloc_len > INT_MAX) {
ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LARGE);
return 0;
}
@@ -322,39 +330,47 @@ int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len_in)
str->flags &= ~ASN1_STRING_FLAG_DATA_NOT_OWNED;
}
- if ((size_t)str->length <= len || str->data == NULL) {
- c = str->data;
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
- /* No NUL terminator in fuzzing builds */
- str->data = OPENSSL_realloc(c, len != 0 ? len : 1);
-#else
- str->data = OPENSSL_realloc(c, len + 1);
-#endif
- if (str->data == NULL) {
- str->data = c;
- return 0;
- }
+ /* Ensure copying a 0 length data field is defined. */
+ if (alloc_len == 0) {
+ OPENSSL_free(str->data);
+ str->data = NULL;
+ str->length = 0;
+ return 1;
}
+
+ if ((size_t)str->length != alloc_len) {
+ uint8_t *c;
+ c = OPENSSL_realloc(str->length == 0 ? NULL : str->data, alloc_len);
+ if (c == NULL)
+ return 0;
+ str->data = c;
+ }
+ /* length never includes the added \0 byte */
str->length = (int)len;
- if (data != NULL) {
+
+ if (data != NULL && str->data != NULL) {
memcpy(str->data, data, len);
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
- /* Set the unused byte to something non NUL and printable. */
- if (len == 0)
- str->data[len] = '~';
-#else
- /*
- * Add a NUL terminator. This should not be necessary - but we add it as
- * a safety precaution
- */
- str->data[len] = '\0';
-#endif
+ if (add_nul_byte) {
+ /*
+ * Add a '\0' terminator. This should not be necessary - but we add it as
+ * a safety precaution
+ */
+ str->data[len] = '\0';
+ }
}
ossl_asn1_bit_string_clear_unused_bits(str);
return 1;
}
+#ifndef OPENSSL_NO_DEPRECATED_4_1
+int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len_in)
+{
+ return ossl_asn1_string_set_internal(str, (const uint8_t *)_data, len_in,
+ /*add_nul_byte=*/1);
+}
+#endif
+
void ASN1_STRING_set0(ASN1_STRING *str, void *data, int len)
{
if (!(str->flags & ASN1_STRING_FLAG_DATA_NOT_OWNED)) {
@@ -365,6 +381,26 @@ void ASN1_STRING_set0(ASN1_STRING *str, void *data, int len)
str->length = len;
}
+int ASN1_STRING_set_data(ASN1_STRING *str, const uint8_t *data, size_t len_in)
+{
+ if (str->type == V_ASN1_BIT_STRING) {
+ ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_BITSTRING_FORMAT);
+ return 0;
+ }
+ /* This will go away once ASN1_STRING can size_t internally */
+ if (len_in > INT_MAX) {
+ ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LARGE);
+ return 0;
+ }
+ return ossl_asn1_string_set_internal(str, data, (int)len_in, /*add_nul_byte=*/0);
+}
+
+int ASN1_STRING_set_string(ASN1_STRING *str, const char *c_string)
+{
+ return ASN1_STRING_set_data(str, (const uint8_t *)c_string,
+ strlen(c_string));
+}
+
ASN1_STRING *ASN1_STRING_new(void)
{
return ASN1_STRING_type_new(V_ASN1_OCTET_STRING);
@@ -469,10 +505,17 @@ int ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b)
}
}
+#ifndef OPENSSL_NO_DEPRECATED_4_1
int ASN1_STRING_length(const ASN1_STRING *x)
{
return x->length;
}
+#endif
+
+size_t ASN1_STRING_length_ex(const ASN1_STRING *x)
+{
+ return (size_t)x->length;
+}
#ifndef OPENSSL_NO_DEPRECATED_3_0
void ASN1_STRING_length_set(ASN1_STRING *x, int len)
@@ -509,7 +552,7 @@ char *ossl_sk_ASN1_UTF8STRING2text(STACK_OF(ASN1_UTF8STRING) *text,
current = sk_ASN1_UTF8STRING_value(text, i);
if (i > 0)
length += sep_len;
- length += ASN1_STRING_length(current);
+ length += ASN1_STRING_length_ex(current);
if (max_len != 0 && length > max_len)
return NULL;
}
@@ -519,7 +562,7 @@ char *ossl_sk_ASN1_UTF8STRING2text(STACK_OF(ASN1_UTF8STRING) *text,
p = result;
for (i = 0; i < sk_ASN1_UTF8STRING_num(text); i++) {
current = sk_ASN1_UTF8STRING_value(text, i);
- length = ASN1_STRING_length(current);
+ length = ASN1_STRING_length_ex(current);
if (i > 0 && sep_len > 0) {
strncpy(p, sep, sep_len + 1); /* using + 1 to silence gcc warning */
p += sep_len;
diff --git a/crypto/asn1/asn1_local.h b/crypto/asn1/asn1_local.h
index 46d7aca7a2..6f3ee7983c 100644
--- a/crypto/asn1/asn1_local.h
+++ b/crypto/asn1/asn1_local.h
@@ -12,6 +12,7 @@
#if !defined(OSSL_LIBCRYPTO_ASN1_ASN1_LOCAL_H)
#define OSSL_LIBCRYPTO_ASN1_ASN1_LOCAL_H
+#include
#include "crypto/asn1.h"
typedef const ASN1_VALUE const_ASN1_VALUE;
@@ -99,5 +100,9 @@ int ossl_asn1_item_ex_new_intern(ASN1_VALUE **pval, const ASN1_ITEM *it,
OSSL_LIB_CTX *libctx, const char *propq);
int ossl_asn1_time_time_t_to_tm(const time_t *time, struct tm *out_tm);
int ossl_asn1_time_tm_to_time_t(const struct tm *tm, time_t *out);
+int ossl_asn1_call_aux_cb(const ASN1_AUX *aux, int operation,
+ const ASN1_VALUE **in, const ASN1_ITEM *it, void *exarg);
+int ossl_asn1_string_set_internal(ASN1_STRING *str, const uint8_t *data,
+ int len_in, int add_nul_byte);
#endif /* !defined(OSSL_LIBCRYPTO_ASN1_ASN1_LOCAL_H) */
diff --git a/crypto/asn1/evp_asn1.c b/crypto/asn1/evp_asn1.c
index 2d50dc657b..2f081e56d3 100644
--- a/crypto/asn1/evp_asn1.c
+++ b/crypto/asn1/evp_asn1.c
@@ -34,6 +34,7 @@ int ASN1_TYPE_set_octetstring(ASN1_TYPE *a, unsigned char *data, int len)
int ASN1_TYPE_get_octetstring(const ASN1_TYPE *a, unsigned char *data, int max_len)
{
int ret, num;
+ size_t tmp;
const unsigned char *p;
if ((a->type != V_ASN1_OCTET_STRING) || (a->value.octet_string == NULL)) {
@@ -41,7 +42,13 @@ int ASN1_TYPE_get_octetstring(const ASN1_TYPE *a, unsigned char *data, int max_l
return -1;
}
p = ASN1_STRING_get0_data(a->value.octet_string);
- ret = ASN1_STRING_length(a->value.octet_string);
+ tmp = ASN1_STRING_length_ex(a->value.octet_string);
+ if (tmp > INT_MAX) {
+ ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LARGE);
+ return -1;
+ }
+ ret = (int)tmp;
+
if (ret < max_len)
num = ret;
else
@@ -69,11 +76,19 @@ static ossl_inline void asn1_type_init_oct(ASN1_OCTET_STRING *oct,
static int asn1_type_get_int_oct(ASN1_OCTET_STRING *oct, int32_t anum,
long *num, unsigned char *data, int max_len)
{
- int ret = ASN1_STRING_length(oct), n;
+ int ret, n;
+ size_t tmp;
if (num != NULL)
*num = anum;
+ tmp = ASN1_STRING_length_ex(oct);
+
+ if (tmp > INT_MAX)
+ tmp = INT_MAX;
+
+ ret = (int)tmp;
+
if (max_len > ret)
n = ret;
else
diff --git a/crypto/asn1/p5_scrypt.c b/crypto/asn1/p5_scrypt.c
index 64980a1a68..9e1b537b9f 100644
--- a/crypto/asn1/p5_scrypt.c
+++ b/crypto/asn1/p5_scrypt.c
@@ -173,7 +173,7 @@ static X509_ALGOR *pkcs5_scrypt_set(const unsigned char *salt, int saltlen,
saltlen = PKCS5_DEFAULT_PBE2_SALT_LEN;
/* This will either copy salt or grow the buffer */
- if (ASN1_STRING_set(sparam->salt, salt, saltlen) == 0) {
+ if (ASN1_STRING_set_data(sparam->salt, salt, saltlen) == 0) {
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
goto err;
}
diff --git a/crypto/asn1/p8_pkey.c b/crypto/asn1/p8_pkey.c
index 143f503dea..77f03e82ef 100644
--- a/crypto/asn1/p8_pkey.c
+++ b/crypto/asn1/p8_pkey.c
@@ -72,11 +72,13 @@ int PKCS8_pkey_get0(const ASN1_OBJECT **ppkalg,
const unsigned char **pk, int *ppklen,
const X509_ALGOR **pa, const PKCS8_PRIV_KEY_INFO *p8)
{
+ if (ASN1_STRING_length_ex(p8->pkey) > INT_MAX)
+ return 0;
if (ppkalg)
*ppkalg = p8->pkeyalg->algorithm;
if (pk) {
*pk = ASN1_STRING_get0_data(p8->pkey);
- *ppklen = ASN1_STRING_length(p8->pkey);
+ *ppklen = (int)ASN1_STRING_length_ex(p8->pkey);
}
if (pa)
*pa = p8->pkeyalg;
diff --git a/crypto/asn1/tasn_dec.c b/crypto/asn1/tasn_dec.c
index 197fd24105..911eb42be7 100644
--- a/crypto/asn1/tasn_dec.c
+++ b/crypto/asn1/tasn_dec.c
@@ -983,7 +983,7 @@ static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, long len,
ASN1_STRING_set0(stmp, (unsigned char *)cont /* UGLY CAST! */, ilen);
*free_cont = 0;
} else {
- if (!ASN1_STRING_set(stmp, cont, ilen)) {
+ if (!ASN1_STRING_set_data(stmp, cont, len)) {
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
ASN1_STRING_free(stmp);
*pval = NULL;
diff --git a/crypto/asn1/tasn_enc.c b/crypto/asn1/tasn_enc.c
index 834d087ebc..e489e29a0c 100644
--- a/crypto/asn1/tasn_enc.c
+++ b/crypto/asn1/tasn_enc.c
@@ -85,16 +85,10 @@ int ASN1_item_ex_i2d(const ASN1_VALUE **pval, unsigned char **out,
int i, seqcontlen, seqlen, ndef = 1;
const ASN1_EXTERN_FUNCS *ef;
const ASN1_AUX *aux = it->funcs;
- ASN1_aux_const_cb *asn1_cb = NULL;
if ((it->itype != ASN1_ITYPE_PRIMITIVE) && *pval == NULL)
return 0;
- if (aux != NULL) {
- asn1_cb = ((aux->flags & ASN1_AFLG_CONST_CB) != 0) ? aux->asn1_const_cb
- : (ASN1_aux_const_cb *)aux->asn1_cb; /* backward compatibility */
- }
-
switch (it->itype) {
case ASN1_ITYPE_PRIMITIVE:
@@ -123,7 +117,7 @@ int ASN1_item_ex_i2d(const ASN1_VALUE **pval, unsigned char **out,
ERR_raise(ERR_LIB_ASN1, ASN1_R_BAD_TEMPLATE);
return -1;
}
- if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL))
+ if (!ossl_asn1_call_aux_cb(aux, ASN1_OP_I2D_PRE, pval, it, NULL))
return 0;
i = ossl_asn1_get_choice_selector_const(pval, it);
if ((i >= 0) && (i < it->tcount)) {
@@ -134,7 +128,7 @@ int ASN1_item_ex_i2d(const ASN1_VALUE **pval, unsigned char **out,
return asn1_template_ex_i2d(pchval, out, chtt, -1, aclass);
}
/* Fixme: error condition if selector out of range */
- if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL))
+ if (!ossl_asn1_call_aux_cb(aux, ASN1_OP_I2D_POST, pval, it, NULL))
return 0;
break;
@@ -166,7 +160,7 @@ int ASN1_item_ex_i2d(const ASN1_VALUE **pval, unsigned char **out,
aclass = (aclass & ~ASN1_TFLG_TAG_CLASS)
| V_ASN1_UNIVERSAL;
}
- if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL))
+ if (!ossl_asn1_call_aux_cb(aux, ASN1_OP_I2D_PRE, pval, it, NULL))
return 0;
/* First work out sequence content length */
for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) {
@@ -200,7 +194,7 @@ int ASN1_item_ex_i2d(const ASN1_VALUE **pval, unsigned char **out,
}
if (ndef == 2)
ASN1_put_eoc(out);
- if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL))
+ if (!ossl_asn1_call_aux_cb(aux, ASN1_OP_I2D_POST, pval, it, NULL))
return 0;
return seqlen;
diff --git a/crypto/asn1/tasn_prn.c b/crypto/asn1/tasn_prn.c
index 080b5623e4..72922c6530 100644
--- a/crypto/asn1/tasn_prn.c
+++ b/crypto/asn1/tasn_prn.c
@@ -138,15 +138,12 @@ static int asn1_item_print_ctx(BIO *out, const ASN1_VALUE **fld, int indent,
const ASN1_EXTERN_FUNCS *ef;
const ASN1_VALUE **tmpfld;
const ASN1_AUX *aux = it->funcs;
- ASN1_aux_const_cb *asn1_cb = NULL;
ASN1_PRINT_ARG parg;
int i;
if (aux != NULL) {
parg.out = out;
parg.indent = indent;
parg.pctx = pctx;
- asn1_cb = ((aux->flags & ASN1_AFLG_CONST_CB) != 0) ? aux->asn1_const_cb
- : (ASN1_aux_const_cb *)aux->asn1_cb; /* backward compatibility */
}
if (((it->itype != ASN1_ITYPE_PRIMITIVE)
@@ -220,13 +217,11 @@ static int asn1_item_print_ctx(BIO *out, const ASN1_VALUE **fld, int indent,
}
}
- if (asn1_cb) {
- i = asn1_cb(ASN1_OP_PRINT_PRE, fld, it, &parg);
- if (i == 0)
- return 0;
- if (i == 2)
- return 1;
- }
+ i = ossl_asn1_call_aux_cb(aux, ASN1_OP_PRINT_PRE, fld, it, &parg);
+ if (i == 0)
+ return 0;
+ if (i == 2)
+ return 1;
/* Print each field entry */
for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) {
@@ -244,11 +239,9 @@ static int asn1_item_print_ctx(BIO *out, const ASN1_VALUE **fld, int indent,
return 0;
}
- if (asn1_cb) {
- i = asn1_cb(ASN1_OP_PRINT_POST, fld, it, &parg);
- if (i == 0)
- return 0;
- }
+ i = ossl_asn1_call_aux_cb(aux, ASN1_OP_PRINT_POST, fld, it, &parg);
+ if (i == 0)
+ return 0;
break;
default:
diff --git a/crypto/asn1/tasn_utl.c b/crypto/asn1/tasn_utl.c
index 5e82a10fbd..a4ab762960 100644
--- a/crypto/asn1/tasn_utl.c
+++ b/crypto/asn1/tasn_utl.c
@@ -288,3 +288,19 @@ err:
ERR_raise(ERR_LIB_ASN1, ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE);
return NULL;
}
+
+int ossl_asn1_call_aux_cb(const ASN1_AUX *aux, int operation,
+ const ASN1_VALUE **in, const ASN1_ITEM *it, void *exarg)
+{
+ if (aux == NULL)
+ return 1;
+
+ if ((aux->flags & ASN1_AFLG_CONST_CB) != 0) {
+ if (aux->asn1_const_cb != NULL)
+ return aux->asn1_const_cb(operation, in, it, exarg);
+ } else if (aux->asn1_cb != NULL) {
+ return aux->asn1_cb(operation, (ASN1_VALUE **)in, it, exarg);
+ }
+
+ return 1;
+}
diff --git a/crypto/asn1/x_long.c b/crypto/asn1/x_long.c
index 19f44f7b68..4dc9dc6c6b 100644
--- a/crypto/asn1/x_long.c
+++ b/crypto/asn1/x_long.c
@@ -8,8 +8,8 @@
*/
#include
+#include "internal/cryptlib.h"
#include
-#include "crypto/cryptlib.h"
#define COPY_SIZE(a, b) (sizeof(a) < sizeof(b) ? sizeof(a) : sizeof(b))
@@ -56,6 +56,31 @@ static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
memcpy(pval, &it->size, COPY_SIZE(*pval, it->size));
}
+/*
+ * Originally BN_num_bits_word was called to perform this operation, but
+ * trouble is that there is no guarantee that sizeof(long) equals to
+ * sizeof(BN_ULONG). BN_ULONG is a configurable type that can be as wide
+ * as long, but also double or half...
+ */
+static int num_bits_ulong(unsigned long value)
+{
+ size_t i;
+ unsigned long ret = 0;
+
+ /*
+ * It is argued that *on average* constant counter loop performs
+ * not worse [if not better] than one with conditional break or
+ * mask-n-table-lookup-style, because of branch misprediction
+ * penalties.
+ */
+ for (i = 0; i < sizeof(value) * 8; i++) {
+ ret += (value != 0);
+ value >>= 1;
+ }
+
+ return (int)ret;
+}
+
static int long_i2c(const ASN1_VALUE **pval, unsigned char *cont, int *putype,
const ASN1_ITEM *it)
{
@@ -78,7 +103,7 @@ static int long_i2c(const ASN1_VALUE **pval, unsigned char *cont, int *putype,
sign = 0;
utmp = ltmp;
}
- clen = (int)ossl_num_bits(utmp);
+ clen = num_bits_ulong(utmp);
/* If MSB of leading octet set we need to pad */
if (!(clen & 0x7))
pad = 1;
diff --git a/crypto/async/arch/async_win.c b/crypto/async/arch/async_win.c
index 849da5c3c4..2ca4ed6a93 100644
--- a/crypto/async/arch/async_win.c
+++ b/crypto/async/arch/async_win.c
@@ -12,7 +12,7 @@
#ifdef ASYNC_WIN
-#include
+#include "internal/e_os.h"
#include "internal/cryptlib.h"
int ASYNC_is_capable(void)
diff --git a/crypto/async/async_local.h b/crypto/async/async_local.h
index e1d1113464..f10a6745f8 100644
--- a/crypto/async/async_local.h
+++ b/crypto/async/async_local.h
@@ -21,6 +21,7 @@
#include
#include
+#include
typedef struct async_ctx_st async_ctx;
typedef struct async_pool_st async_pool;
@@ -29,7 +30,6 @@ typedef struct async_pool_st async_pool;
#define ASYNC_WIN
#define ASYNC_ARCH
-#include
#include "internal/cryptlib.h"
typedef struct async_fibre_st {
diff --git a/crypto/bio/bio_lib.c b/crypto/bio/bio_lib.c
index b7d4bc549e..6066cc0d8c 100644
--- a/crypto/bio/bio_lib.c
+++ b/crypto/bio/bio_lib.c
@@ -116,24 +116,22 @@ BIO *BIO_new(const BIO_METHOD *method)
return BIO_new_ex(NULL, method);
}
-int BIO_free(BIO *a)
+static int BIO_free_int(BIO *a, int *ret)
{
- int ret;
if (a == NULL)
return 0;
- if (CRYPTO_DOWN_REF(&a->references, &ret) <= 0)
+ if (CRYPTO_DOWN_REF(&a->references, ret) <= 0)
return 0;
- REF_PRINT_COUNT("BIO", ret, a);
- if (ret > 0)
+ REF_PRINT_COUNT("BIO", *ret, a);
+ if (*ret > 0)
return 1;
- REF_ASSERT_ISNT(ret < 0);
+ REF_ASSERT_ISNT(*ret < 0);
if (HAS_CALLBACK(a)) {
- ret = (int)bio_call_callback(a, BIO_CB_FREE, NULL, 0, 0, 0L, 1L, NULL);
- if (ret <= 0)
+ if ((int)bio_call_callback(a, BIO_CB_FREE, NULL, 0, 0, 0L, 1L, NULL) <= 0)
return 0;
}
@@ -149,6 +147,13 @@ int BIO_free(BIO *a)
return 1;
}
+int BIO_free(BIO *b)
+{
+ int ref;
+
+ return BIO_free_int(b, &ref);
+}
+
void BIO_set_data(BIO *a, void *ptr)
{
a->ptr = ptr;
@@ -188,7 +193,7 @@ int BIO_up_ref(BIO *a)
{
int i;
- if (CRYPTO_UP_REF(&a->references, &i) <= 0)
+ if (!CRYPTO_UP_REF(&a->references, &i))
return 0;
REF_PRINT_COUNT("BIO", i, a);
@@ -874,11 +879,11 @@ void BIO_free_all(BIO *bio)
while (bio != NULL) {
b = bio;
- CRYPTO_GET_REF(&b->references, &ref);
bio = bio->next_bio;
- BIO_free(b);
- /* Since ref count > 1, don't free anyone else. */
- if (ref > 1)
+ ref = 0;
+ BIO_free_int(b, &ref);
+ /* Since ref count > 0, don't free anyone else. */
+ if (ref > 0)
break;
}
}
diff --git a/crypto/bio/bio_local.h b/crypto/bio/bio_local.h
index 36f72f5df1..87227e4f8f 100644
--- a/crypto/bio/bio_local.h
+++ b/crypto/bio/bio_local.h
@@ -74,6 +74,7 @@ struct bio_addrinfo_st {
#include "internal/cryptlib.h"
#include "internal/bio.h"
#include "internal/refcount.h"
+#include "internal/time.h"
typedef struct bio_f_buffer_ctx_struct {
/*-
@@ -122,6 +123,87 @@ struct bio_st {
};
#ifndef OPENSSL_NO_SOCK
+
+typedef struct bio_connect_st {
+ int state;
+ int connect_family;
+ int connect_sock_type;
+ char *param_hostname;
+ char *param_service;
+ int connect_mode;
+#ifndef OPENSSL_NO_KTLS
+ unsigned char record_type;
+#endif
+ int tfo_first;
+
+ BIO_ADDRINFO *addr_first;
+ const BIO_ADDRINFO *addr_iter;
+ /*
+ * int socket; this will be kept in bio->num so that it is compatible
+ * with the bss_sock bio
+ */
+ /*
+ * called when the connection is initially made callback(BIO,state,ret);
+ * The callback should return 'ret'. state is for compatibility with the
+ * ssl info_callback
+ */
+ BIO_info_cb *info_callback;
+ /*
+ * Used when connect_sock_type is SOCK_DGRAM. Owned by us; we forward
+ * read/write(mmsg) calls to this if present.
+ */
+ BIO *dgram_bio;
+} BIO_CONNECT;
+
+typedef struct bio_accept_st {
+ int state;
+ int accept_family;
+ int bind_mode; /* Socket mode for BIO_listen */
+ int accepted_mode; /* Socket mode for BIO_accept (set on accepted sock) */
+ char *param_addr;
+ char *param_serv;
+
+ int accept_sock;
+
+ BIO_ADDRINFO *addr_first;
+ const BIO_ADDRINFO *addr_iter;
+ BIO_ADDR cache_accepting_addr; /* Useful if we asked for port 0 */
+ char *cache_accepting_name, *cache_accepting_serv;
+ BIO_ADDR cache_peer_addr;
+ char *cache_peer_name, *cache_peer_serv;
+
+ BIO *bio_chain;
+} BIO_ACCEPT;
+
+#ifndef OPENSSL_NO_DGRAM
+typedef struct bio_dgram_data_st {
+ BIO_ADDR peer;
+ BIO_ADDR local_addr;
+ unsigned int connected;
+ unsigned int _errno;
+ unsigned int mtu;
+ OSSL_TIME next_timeout;
+ OSSL_TIME socket_timeout;
+ unsigned int peekmode;
+ char local_addr_enabled;
+} bio_dgram_data;
+#endif
+
+#define BIO_CONN_S_BEFORE 1
+#define BIO_CONN_S_GET_ADDR 2
+#define BIO_CONN_S_CREATE_SOCKET 3
+#define BIO_CONN_S_CONNECT 4
+#define BIO_CONN_S_OK 5
+#define BIO_CONN_S_BLOCKED_CONNECT 6
+#define BIO_CONN_S_CONNECT_ERROR 7
+
+#define BIO_ACPT_S_BEFORE 1
+#define BIO_ACPT_S_GET_ADDR 2
+#define BIO_ACPT_S_CREATE_SOCKET 3
+#define BIO_ACPT_S_LISTEN 4
+#define BIO_ACPT_S_ACCEPT 5
+#define BIO_ACPT_S_OK 6
+
#ifdef OPENSSL_SYS_VMS
typedef unsigned int socklen_t;
#endif
diff --git a/crypto/bio/bio_print.c b/crypto/bio/bio_print.c
index 8b0c3481f0..5366587a2a 100644
--- a/crypto/bio/bio_print.c
+++ b/crypto/bio/bio_print.c
@@ -111,7 +111,7 @@ int BIO_vprintf(BIO *bio, const char *format, va_list args)
*/
sz = vsnprintf(buf, sizeof(buf), format, args);
if (sz >= 0) {
- if ((size_t)sz > sizeof(buf)) {
+ if ((size_t)sz >= sizeof(buf)) {
sz += 1;
abuf = (char *)OPENSSL_malloc(sz);
if (abuf == NULL) {
diff --git a/crypto/bio/bss_acpt.c b/crypto/bio/bss_acpt.c
index 1ba91c6592..c9cdba041a 100644
--- a/crypto/bio/bss_acpt.c
+++ b/crypto/bio/bss_acpt.c
@@ -15,26 +15,6 @@
#ifndef OPENSSL_NO_SOCK
-typedef struct bio_accept_st {
- int state;
- int accept_family;
- int bind_mode; /* Socket mode for BIO_listen */
- int accepted_mode; /* Socket mode for BIO_accept (set on accepted sock) */
- char *param_addr;
- char *param_serv;
-
- int accept_sock;
-
- BIO_ADDRINFO *addr_first;
- const BIO_ADDRINFO *addr_iter;
- BIO_ADDR cache_accepting_addr; /* Useful if we asked for port 0 */
- char *cache_accepting_name, *cache_accepting_serv;
- BIO_ADDR cache_peer_addr;
- char *cache_peer_name, *cache_peer_serv;
-
- BIO *bio_chain;
-} BIO_ACCEPT;
-
static int acpt_write(BIO *h, const char *buf, int num);
static int acpt_read(BIO *h, char *buf, int size);
static int acpt_puts(BIO *h, const char *str);
@@ -46,13 +26,6 @@ static void acpt_close_socket(BIO *data);
static BIO_ACCEPT *BIO_ACCEPT_new(void);
static void BIO_ACCEPT_free(BIO_ACCEPT *a);
-#define ACPT_S_BEFORE 1
-#define ACPT_S_GET_ADDR 2
-#define ACPT_S_CREATE_SOCKET 3
-#define ACPT_S_LISTEN 4
-#define ACPT_S_ACCEPT 5
-#define ACPT_S_OK 6
-
static const BIO_METHOD methods_acceptp = {
BIO_TYPE_ACCEPT,
"socket accept",
@@ -83,7 +56,7 @@ static int acpt_new(BIO *bi)
if ((ba = BIO_ACCEPT_new()) == NULL)
return 0;
bi->ptr = (char *)ba;
- ba->state = ACPT_S_BEFORE;
+ ba->state = BIO_ACPT_S_BEFORE;
bi->shutdown = 1;
return 1;
}
@@ -152,7 +125,7 @@ static int acpt_state(BIO *b, BIO_ACCEPT *c)
for (;;) {
switch (c->state) {
- case ACPT_S_BEFORE:
+ case BIO_ACPT_S_BEFORE:
if (c->param_addr == NULL && c->param_serv == NULL) {
ERR_raise_data(ERR_LIB_BIO,
BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED,
@@ -174,10 +147,10 @@ static int acpt_state(BIO *b, BIO_ACCEPT *c)
OPENSSL_free(c->cache_peer_serv);
c->cache_peer_serv = NULL;
- c->state = ACPT_S_GET_ADDR;
+ c->state = BIO_ACPT_S_GET_ADDR;
break;
- case ACPT_S_GET_ADDR: {
+ case BIO_ACPT_S_GET_ADDR: {
int family = AF_UNSPEC;
switch (c->accept_family) {
case BIO_FAMILY_IPV6:
@@ -213,10 +186,10 @@ static int acpt_state(BIO *b, BIO_ACCEPT *c)
goto exit_loop;
}
c->addr_iter = c->addr_first;
- c->state = ACPT_S_CREATE_SOCKET;
+ c->state = BIO_ACPT_S_CREATE_SOCKET;
break;
- case ACPT_S_CREATE_SOCKET:
+ case BIO_ACPT_S_CREATE_SOCKET:
ERR_set_mark();
s = BIO_socket(BIO_ADDRINFO_family(c->addr_iter),
BIO_ADDRINFO_socktype(c->addr_iter),
@@ -238,11 +211,11 @@ static int acpt_state(BIO *b, BIO_ACCEPT *c)
}
c->accept_sock = s;
b->num = s;
- c->state = ACPT_S_LISTEN;
+ c->state = BIO_ACPT_S_LISTEN;
s = -1;
break;
- case ACPT_S_LISTEN: {
+ case BIO_ACPT_S_LISTEN: {
if (!BIO_listen(c->accept_sock,
BIO_ADDRINFO_address(c->addr_iter),
c->bind_mode)) {
@@ -271,14 +244,14 @@ static int acpt_state(BIO *b, BIO_ACCEPT *c)
OPENSSL_free(c->cache_accepting_serv);
c->cache_accepting_name = BIO_ADDR_hostname_string(&c->cache_accepting_addr, 1);
c->cache_accepting_serv = BIO_ADDR_service_string(&c->cache_accepting_addr, 1);
- c->state = ACPT_S_ACCEPT;
+ c->state = BIO_ACPT_S_ACCEPT;
s = -1;
ret = 1;
goto end;
- case ACPT_S_ACCEPT:
+ case BIO_ACPT_S_ACCEPT:
if (b->next_bio != NULL) {
- c->state = ACPT_S_OK;
+ c->state = BIO_ACPT_S_OK;
break;
}
BIO_clear_retry_flags(b);
@@ -334,14 +307,14 @@ static int acpt_state(BIO *b, BIO_ACCEPT *c)
c->cache_peer_name = BIO_ADDR_hostname_string(&c->cache_peer_addr, 1);
c->cache_peer_serv = BIO_ADDR_service_string(&c->cache_peer_addr, 1);
- c->state = ACPT_S_OK;
+ c->state = BIO_ACPT_S_OK;
bio = NULL;
ret = 1;
goto end;
- case ACPT_S_OK:
+ case BIO_ACPT_S_OK:
if (b->next_bio == NULL) {
- c->state = ACPT_S_ACCEPT;
+ c->state = BIO_ACPT_S_ACCEPT;
break;
}
ret = 1;
@@ -412,7 +385,7 @@ static long acpt_ctrl(BIO *b, int cmd, long num, void *ptr)
switch (cmd) {
case BIO_CTRL_RESET:
ret = 0;
- data->state = ACPT_S_BEFORE;
+ data->state = BIO_ACPT_S_BEFORE;
acpt_close_socket(b);
BIO_ADDRINFO_free(data->addr_first);
data->addr_first = NULL;
@@ -474,7 +447,7 @@ static long acpt_ctrl(BIO *b, int cmd, long num, void *ptr)
case BIO_C_SET_FD:
b->num = *((int *)ptr);
data->accept_sock = b->num;
- data->state = ACPT_S_ACCEPT;
+ data->state = BIO_ACPT_S_ACCEPT;
b->shutdown = (int)num;
b->init = 1;
break;
diff --git a/crypto/bio/bss_conn.c b/crypto/bio/bss_conn.c
index 0e84e959d8..c4355392e4 100644
--- a/crypto/bio/bss_conn.c
+++ b/crypto/bio/bss_conn.c
@@ -16,37 +16,6 @@
#ifndef OPENSSL_NO_SOCK
-typedef struct bio_connect_st {
- int state;
- int connect_family;
- int connect_sock_type;
- char *param_hostname;
- char *param_service;
- int connect_mode;
-#ifndef OPENSSL_NO_KTLS
- unsigned char record_type;
-#endif
- int tfo_first;
-
- BIO_ADDRINFO *addr_first;
- const BIO_ADDRINFO *addr_iter;
- /*
- * int socket; this will be kept in bio->num so that it is compatible
- * with the bss_sock bio
- */
- /*
- * called when the connection is initially made callback(BIO,state,ret);
- * The callback should return 'ret'. state is for compatibility with the
- * ssl info_callback
- */
- BIO_info_cb *info_callback;
- /*
- * Used when connect_sock_type is SOCK_DGRAM. Owned by us; we forward
- * read/write(mmsg) calls to this if present.
- */
- BIO *dgram_bio;
-} BIO_CONNECT;
-
static int conn_write(BIO *h, const char *buf, int num);
static int conn_read(BIO *h, char *buf, int size);
static int conn_puts(BIO *h, const char *str);
@@ -65,14 +34,6 @@ static void conn_close_socket(BIO *data);
static BIO_CONNECT *BIO_CONNECT_new(void);
static void BIO_CONNECT_free(BIO_CONNECT *a);
-#define BIO_CONN_S_BEFORE 1
-#define BIO_CONN_S_GET_ADDR 2
-#define BIO_CONN_S_CREATE_SOCKET 3
-#define BIO_CONN_S_CONNECT 4
-#define BIO_CONN_S_OK 5
-#define BIO_CONN_S_BLOCKED_CONNECT 6
-#define BIO_CONN_S_CONNECT_ERROR 7
-
static const BIO_METHOD methods_connectp = {
BIO_TYPE_CONNECT,
"socket connect",
diff --git a/crypto/bio/bss_dgram.c b/crypto/bio/bss_dgram.c
index 0a1479e834..1d98239511 100644
--- a/crypto/bio/bss_dgram.c
+++ b/crypto/bio/bss_dgram.c
@@ -14,7 +14,6 @@
#include
#include
-#include "internal/time.h"
#include "bio_local.h"
#ifndef OPENSSL_NO_DGRAM
@@ -213,21 +212,7 @@ static const BIO_METHOD methods_dgramp_sctp = {
NULL, /* sendmmsg */
NULL, /* recvmmsg */
};
-#endif
-typedef struct bio_dgram_data_st {
- BIO_ADDR peer;
- BIO_ADDR local_addr;
- unsigned int connected;
- unsigned int _errno;
- unsigned int mtu;
- OSSL_TIME next_timeout;
- OSSL_TIME socket_timeout;
- unsigned int peekmode;
- char local_addr_enabled;
-} bio_dgram_data;
-
-#ifndef OPENSSL_NO_SCTP
typedef struct bio_dgram_sctp_save_message_st {
BIO *bio;
char *data;
diff --git a/crypto/bio/bss_file.c b/crypto/bio/bss_file.c
index 11e96a23d7..7aed585342 100644
--- a/crypto/bio/bss_file.c
+++ b/crypto/bio/bss_file.c
@@ -332,7 +332,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/crypto/bio/bss_log.c b/crypto/bio/bss_log.c
index 74a5b6c5c5..2928ae5c41 100644
--- a/crypto/bio/bss_log.c
+++ b/crypto/bio/bss_log.c
@@ -22,8 +22,7 @@
#include "bio_local.h"
#include "internal/cryptlib.h"
-#if defined(OPENSSL_SYS_WINCE)
-#elif defined(OPENSSL_SYS_WIN32)
+#if defined(OPENSSL_SYS_WIN32)
#elif defined(__wasi__)
#define NO_SYSLOG
#elif defined(OPENSSL_SYS_VMS)
diff --git a/crypto/bn/asm/x86_64-gcc.c b/crypto/bn/asm/x86_64-gcc.c
index c25b06e770..03299a7b72 100644
--- a/crypto/bn/asm/x86_64-gcc.c
+++ b/crypto/bn/asm/x86_64-gcc.c
@@ -8,7 +8,7 @@
*/
#include "../bn_local.h"
-#if !(defined(__GNUC__) && __GNUC__ >= 2)
+#if !defined(__GNUC__)
/* clang-format off */
# include "../bn_asm.c" /* kind of dirty hack for Sun Studio */
/* clang-format on */
@@ -261,7 +261,7 @@ BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
#else
/* Simics 1.4<7 has buggy sbbq:-( */
#define BN_MASK2 0xffffffffffffffffL
-BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, int n)
+BN_ULONG bn_sub_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
{
BN_ULONG t1, t2;
int c = 0;
@@ -408,7 +408,7 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, int n)
#define sqr_add_c2(a, i, j, c0, c1, c2) \
mul_add_c2((a)[i], (a)[j], c0, c1, c2)
-void bn_mul_comba8(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b)
+void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
{
BN_ULONG c1, c2, c3;
@@ -511,7 +511,7 @@ void bn_mul_comba8(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b)
r[15] = c1;
}
-void bn_mul_comba4(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b)
+void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
{
BN_ULONG c1, c2, c3;
diff --git a/crypto/bn/bn_add.c b/crypto/bn/bn_add.c
index 1784091b01..24151d0e13 100644
--- a/crypto/bn/bn_add.c
+++ b/crypto/bn/bn_add.c
@@ -96,7 +96,9 @@ int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
if (bn_wexpand(r, max + 1) == NULL)
return 0;
- bn_set_top(r, max);
+ r->top = max;
+ if (max == 0)
+ goto end;
ap = a->d;
bp = b->d;
@@ -114,8 +116,9 @@ int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
carry &= (t2 == 0);
}
*rp = carry;
- bn_set_top(r, r->top + (int)carry);
+ r->top += (int)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,8 +168,10 @@ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
while (max && *--rp == 0)
max--;
- bn_set_top(r, max);
+end:
+ r->top = max;
r->neg = 0;
+ bn_pollute(r);
return 1;
}
diff --git a/crypto/bn/bn_asm.c b/crypto/bn/bn_asm.c
index f7998658ac..e667702143 100644
--- a/crypto/bn/bn_asm.c
+++ b/crypto/bn/bn_asm.c
@@ -622,7 +622,7 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
mul_add_c2((a)[i], (a)[j], c0, c1, c2)
#endif /* !BN_LLONG */
-void bn_mul_comba8(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b)
+void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
{
BN_ULONG c1, c2, c3;
@@ -725,7 +725,7 @@ void bn_mul_comba8(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b)
r[15] = c1;
}
-void bn_mul_comba4(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b)
+void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
{
BN_ULONG c1, c2, c3;
@@ -1006,7 +1006,7 @@ void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a)
bn_sqr_normal(r, a, 8, t);
}
-void bn_mul_comba4(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b)
+void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
{
r[4] = bn_mul_words(&(r[0]), a, 4, b[0]);
r[5] = bn_mul_add_words(&(r[1]), a, 4, b[1]);
@@ -1014,7 +1014,7 @@ void bn_mul_comba4(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b)
r[7] = bn_mul_add_words(&(r[3]), a, 4, b[3]);
}
-void bn_mul_comba8(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b)
+void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
{
r[8] = bn_mul_words(&(r[0]), a, 8, b[0]);
r[9] = bn_mul_add_words(&(r[1]), a, 8, b[1]);
diff --git a/crypto/bn/bn_blind.c b/crypto/bn/bn_blind.c
index 681b086b18..7722ed1e48 100644
--- a/crypto/bn/bn_blind.c
+++ b/crypto/bn/bn_blind.c
@@ -185,7 +185,7 @@ int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b,
}
mask = (BN_ULONG)0 - ((rtop - ntop) >> (8 * sizeof(ntop) - 1));
/* always true, if (rtop >= ntop) n->top = r->top; */
- bn_set_top(n, (int)((rtop & ~mask) | (ntop & mask)));
+ n->top = (int)((rtop & ~mask) | (ntop & mask));
n->flags |= (BN_FLG_FIXED_TOP & ~mask);
}
ret = bn_mul_mont_fixed_top(n, n, r, b->m_ctx, ctx);
diff --git a/crypto/bn/bn_conv.c b/crypto/bn/bn_conv.c
index ff49ebca81..f295e5db9a 100644
--- a/crypto/bn/bn_conv.c
+++ b/crypto/bn/bn_conv.c
@@ -178,7 +178,7 @@ int BN_hex2bn(BIGNUM **bn, const char *a)
}
j -= BN_BYTES * 2;
}
- bn_set_top(ret, h);
+ ret->top = h;
bn_correct_top(ret);
*bn = ret;
diff --git a/crypto/bn/bn_dh.c b/crypto/bn/bn_dh.c
index ee948095dd..1630be9191 100644
--- a/crypto/bn/bn_dh.c
+++ b/crypto/bn/bn_dh.c
@@ -1374,53 +1374,50 @@ static const BN_ULONG ffdhe8192_q[] = {
#define make_dh_bn(x) \
extern const BIGNUM ossl_bignum_##x; \
const BIGNUM ossl_bignum_##x = { \
- .d = (BN_ULONG *)x, \
- .top = OSSL_NELEM(x), \
- .dmax = OSSL_NELEM(x), \
- .flags = BN_FLG_STATIC_DATA, \
- }
+ (BN_ULONG *)x, \
+ OSSL_NELEM(x), \
+ OSSL_NELEM(x), \
+ 0, BN_FLG_STATIC_DATA \
+ };
static const BN_ULONG value_2 = 2;
const BIGNUM ossl_bignum_const_2 = {
- .d = (BN_ULONG *)&value_2,
- .top = 1,
- .dmax = 1,
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)&value_2, 1, 1, 0, BN_FLG_STATIC_DATA
};
-make_dh_bn(dh1024_160_p);
-make_dh_bn(dh1024_160_q);
-make_dh_bn(dh1024_160_g);
-make_dh_bn(dh2048_224_p);
-make_dh_bn(dh2048_224_q);
-make_dh_bn(dh2048_224_g);
-make_dh_bn(dh2048_256_p);
-make_dh_bn(dh2048_256_q);
-make_dh_bn(dh2048_256_g);
+make_dh_bn(dh1024_160_p)
+make_dh_bn(dh1024_160_q)
+make_dh_bn(dh1024_160_g)
+make_dh_bn(dh2048_224_p)
+make_dh_bn(dh2048_224_q)
+make_dh_bn(dh2048_224_g)
+make_dh_bn(dh2048_256_p)
+make_dh_bn(dh2048_256_q)
+make_dh_bn(dh2048_256_g)
-make_dh_bn(ffdhe2048_p);
-make_dh_bn(ffdhe2048_q);
-make_dh_bn(ffdhe3072_p);
-make_dh_bn(ffdhe3072_q);
-make_dh_bn(ffdhe4096_p);
-make_dh_bn(ffdhe4096_q);
-make_dh_bn(ffdhe6144_p);
-make_dh_bn(ffdhe6144_q);
-make_dh_bn(ffdhe8192_p);
-make_dh_bn(ffdhe8192_q);
+make_dh_bn(ffdhe2048_p)
+make_dh_bn(ffdhe2048_q)
+make_dh_bn(ffdhe3072_p)
+make_dh_bn(ffdhe3072_q)
+make_dh_bn(ffdhe4096_p)
+make_dh_bn(ffdhe4096_q)
+make_dh_bn(ffdhe6144_p)
+make_dh_bn(ffdhe6144_q)
+make_dh_bn(ffdhe8192_p)
+make_dh_bn(ffdhe8192_q)
#ifndef FIPS_MODULE
-make_dh_bn(modp_1536_p);
-make_dh_bn(modp_1536_q);
+make_dh_bn(modp_1536_p)
+make_dh_bn(modp_1536_q)
#endif
-make_dh_bn(modp_2048_p);
-make_dh_bn(modp_2048_q);
-make_dh_bn(modp_3072_p);
-make_dh_bn(modp_3072_q);
-make_dh_bn(modp_4096_p);
-make_dh_bn(modp_4096_q);
-make_dh_bn(modp_6144_p);
-make_dh_bn(modp_6144_q);
-make_dh_bn(modp_8192_p);
-make_dh_bn(modp_8192_q);
+make_dh_bn(modp_2048_p)
+make_dh_bn(modp_2048_q)
+make_dh_bn(modp_3072_p)
+make_dh_bn(modp_3072_q)
+make_dh_bn(modp_4096_p)
+make_dh_bn(modp_4096_q)
+make_dh_bn(modp_6144_p)
+make_dh_bn(modp_6144_q)
+make_dh_bn(modp_8192_p)
+make_dh_bn(modp_8192_q)
diff --git a/crypto/bn/bn_div.c b/crypto/bn/bn_div.c
index 0cec75bf94..a731b2d37d 100644
--- a/crypto/bn/bn_div.c
+++ b/crypto/bn/bn_div.c
@@ -61,7 +61,7 @@ int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d,
BN_zero(dv);
if (bn_wexpand(dv, 1) == NULL)
goto end;
- bn_set_top(dv, 1);
+ dv->top = 1;
if (!BN_lshift(D, D, nm - nd))
goto end;
@@ -160,7 +160,7 @@ static int bn_left_align(BIGNUM *num)
#if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM) \
&& !defined(PEDANTIC) && !defined(BN_DIV3W)
-#if defined(__GNUC__) && __GNUC__ >= 2
+#if defined(__GNUC__)
#if defined(__i386) || defined(__i386__)
/*-
* There were two reasons for implementing this template:
@@ -310,9 +310,7 @@ int bn_div_fixed_top(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num,
if (bn_wexpand(snum, div_n + 1) == NULL)
goto err;
memset(&(snum->d[num_n]), 0, (div_n - num_n + 1) * sizeof(BN_ULONG));
- num_n = div_n + 1;
- bn_set_top(snum, num_n);
- snum->flags |= BN_FLG_FIXED_TOP;
+ snum->top = num_n = div_n + 1;
}
loop = num_n - div_n;
@@ -332,15 +330,13 @@ int bn_div_fixed_top(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num,
goto err;
num_neg = num->neg;
res->neg = (num_neg ^ divisor->neg);
- bn_set_top(res, loop);
+ res->top = loop;
res->flags |= BN_FLG_FIXED_TOP;
resp = &(res->d[loop]);
/* space for temp */
if (!bn_wexpand(tmp, (div_n + 1)))
goto err;
- tmp->top = div_n + 1;
- tmp->flags |= BN_FLG_FIXED_TOP;
for (i = 0; i < loop; i++, wnumtop--) {
BN_ULONG q, l0;
@@ -450,7 +446,7 @@ int bn_div_fixed_top(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num,
}
/* snum holds remainder, it's as wide as divisor */
snum->neg = num_neg;
- bn_set_top(snum, div_n);
+ snum->top = div_n;
snum->flags |= BN_FLG_FIXED_TOP;
if (rm != NULL && bn_rshift_fixed_top(rm, snum, norm_shift) == 0)
diff --git a/crypto/bn/bn_exp.c b/crypto/bn/bn_exp.c
index 65445a40e5..c3bd5e7b5d 100644
--- a/crypto/bn/bn_exp.c
+++ b/crypto/bn/bn_exp.c
@@ -402,7 +402,7 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
r->d[0] = (0 - m->d[0]) & BN_MASK2;
for (i = 1; i < j; i++)
r->d[i] = (~m->d[i]) & BN_MASK2;
- bn_set_top(r, j);
+ r->top = j;
r->flags |= BN_FLG_FIXED_TOP;
} else
#endif
@@ -468,8 +468,7 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
val[0]->d[0] = 1; /* borrow val[0] */
for (i = 1; i < j; i++)
val[0]->d[i] = 0;
- bn_set_top(val[0], j);
- val[0]->flags |= BN_FLG_FIXED_TOP;
+ val[0]->top = j;
if (!BN_mod_mul_montgomery(rr, r, val[0], mont, ctx))
goto err;
} else
@@ -582,7 +581,7 @@ static int MOD_EXP_CTIME_COPY_FROM_PREBUF(BIGNUM *b, int top,
}
}
- bn_set_top(b, top);
+ b->top = top;
b->flags |= BN_FLG_FIXED_TOP;
return 1;
}
@@ -613,7 +612,7 @@ int bn_mod_exp_mont_fixed_top(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
unsigned char *powerbufFree = NULL;
int powerbufLen = 0;
unsigned char *powerbuf = NULL;
- BIGNUM tmp = { .data = NULL }, am = { .data = NULL };
+ BIGNUM tmp, am;
#if defined(SPARC_T4_MONT)
unsigned int t4 = 0;
#endif
@@ -682,7 +681,7 @@ int bn_mod_exp_mont_fixed_top(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
goto err;
RSAZ_1024_mod_exp_avx2(rr->d, a->d, p->d, m->d, mont->RR.d,
mont->n0[0]);
- bn_set_top(rr, 16);
+ rr->top = 16;
rr->neg = 0;
bn_correct_top(rr);
ret = 1;
@@ -691,7 +690,7 @@ int bn_mod_exp_mont_fixed_top(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
if (NULL == bn_wexpand(rr, 8))
goto err;
RSAZ_512_mod_exp(rr->d, a->d, p->d, m->d, mont->n0[0], mont->RR.d);
- bn_set_top(rr, 8);
+ rr->top = 8;
rr->neg = 0;
bn_correct_top(rr);
ret = 1;
@@ -1489,12 +1488,12 @@ int BN_mod_exp_mont_consttime_x2(BIGNUM *rr1, const BIGNUM *a1, const BIGNUM *p1
mont2->RR.d, mont2->n0[0],
mod_bits);
- bn_set_top(rr1, topn);
+ rr1->top = topn;
rr1->neg = 0;
bn_correct_top(rr1);
bn_check_top(rr1);
- bn_set_top(rr2, topn);
+ rr2->top = topn;
rr2->neg = 0;
bn_correct_top(rr2);
bn_check_top(rr2);
diff --git a/crypto/bn/bn_gf2m.c b/crypto/bn/bn_gf2m.c
index 5ad173337e..81a7fda5b3 100644
--- a/crypto/bn/bn_gf2m.c
+++ b/crypto/bn/bn_gf2m.c
@@ -267,7 +267,7 @@ int BN_GF2m_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
r->d[i] = at->d[i];
}
- bn_set_top(r, at->top);
+ r->top = at->top;
bn_correct_top(r);
return 1;
@@ -305,7 +305,7 @@ int BN_GF2m_mod_arr(BIGNUM *r, const BIGNUM *a, const int p[])
for (j = 0; j < a->top; j++) {
r->d[j] = a->d[j];
}
- bn_set_top(r, a->top);
+ r->top = a->top;
}
z = r->d;
@@ -419,7 +419,7 @@ int BN_GF2m_mod_mul_arr(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
zlen = a->top + b->top + 4;
if (!bn_wexpand(s, zlen))
goto err;
- bn_set_top(s, zlen);
+ s->top = zlen;
for (i = 0; i < zlen; i++)
s->d[i] = 0;
@@ -498,7 +498,7 @@ int BN_GF2m_mod_sqr_arr(BIGNUM *r, const BIGNUM *a, const int p[],
s->d[2 * i] = SQR0(a->d[i]);
}
- bn_set_top(s, 2 * a->top);
+ s->top = 2 * a->top;
bn_correct_top(s);
if (!BN_GF2m_mod_arr(r, s, p))
goto err;
@@ -618,20 +618,20 @@ static int BN_GF2m_mod_inv_vartime(BIGNUM *r, const BIGNUM *a,
udp = u->d;
for (i = u->top; i < top; i++)
udp[i] = 0;
- bn_set_top(u, top);
+ u->top = top;
if (!bn_wexpand(b, top))
goto err;
bdp = b->d;
bdp[0] = 1;
for (i = 1; i < top; i++)
bdp[i] = 0;
- bn_set_top(b, top);
+ b->top = top;
if (!bn_wexpand(c, top))
goto err;
cdp = c->d;
for (i = 0; i < top; i++)
cdp[i] = 0;
- bn_set_top(c, top);
+ c->top = top;
vdp = v->d; /* It pays off to "cache" *->d pointers,
* because it allows optimizer to be more
* aggressive. But we don't have to "cache"
diff --git a/crypto/bn/bn_intern.c b/crypto/bn/bn_intern.c
index 89e0b5a60a..f963d42b86 100644
--- a/crypto/bn/bn_intern.c
+++ b/crypto/bn/bn_intern.c
@@ -174,9 +174,7 @@ void bn_set_static_words(BIGNUM *a, const BN_ULONG *words, int size)
* |const| qualifier omission is compensated by BN_FLG_STATIC_DATA
* flag, which effectively means "read-only data".
*/
- a->data = NULL;
a->d = (BN_ULONG *)words;
- /* No need to call bn_set_top() in this case */
a->dmax = a->top = size;
a->neg = 0;
a->flags |= BN_FLG_STATIC_DATA;
@@ -190,10 +188,8 @@ int bn_set_words(BIGNUM *a, const BN_ULONG *words, int num_words)
return 0;
}
- /* TODO(FIXNUM): In the future, we'll use an OSSL_FN function on a->data */
memcpy(a->d, words, sizeof(BN_ULONG) * num_words);
-
- bn_set_top(a, num_words);
+ a->top = num_words;
bn_correct_top(a);
return 1;
}
diff --git a/crypto/bn/bn_lib.c b/crypto/bn/bn_lib.c
index e3ed1b29ea..a63e2b9154 100644
--- a/crypto/bn/bn_lib.c
+++ b/crypto/bn/bn_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
@@ -9,14 +9,11 @@
#include
#include
-#include
-#include
-#include
#include "internal/cryptlib.h"
#include "internal/endian.h"
-#include "internal/constant_time.h"
-#include "crypto/fn.h"
#include "bn_local.h"
+#include
+#include "internal/constant_time.h"
/* This stuff appears to be completely unused, so is deprecated */
#ifndef OPENSSL_NO_DEPRECATED_0_9_8
@@ -86,24 +83,12 @@ const BIGNUM *BN_value_one(void)
{
static const BN_ULONG data_one = 1L;
static const BIGNUM const_one = {
- .d = (BN_ULONG *)&data_one,
- .top = 1,
- .dmax = 1,
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)&data_one, 1, 1, 0, BN_FLG_STATIC_DATA
};
return &const_one;
}
-/*
- * Old Visual Studio ARM compiler miscompiles BN_num_bits_word()
- * https://mta.openssl.org/pipermail/openssl-users/2018-August/008465.html
- */
-#if defined(_MSC_VER) && defined(_ARM_) && defined(_WIN32_WCE) \
- && _MSC_VER >= 1400 && _MSC_VER < 1501
-#define MS_BROKEN_BN_num_bits_word
-#pragma optimize("", off)
-#endif
int BN_num_bits_word(BN_ULONG l)
{
BN_ULONG x, mask;
@@ -148,9 +133,6 @@ int BN_num_bits_word(BN_ULONG l)
return bits;
}
-#ifdef MS_BROKEN_BN_num_bits_word
-#pragma optimize("", on)
-#endif
/*
* This function still leaks `a->dmax`: it's caller's responsibility to
@@ -205,7 +187,7 @@ int BN_num_bits(const BIGNUM *a)
return ((i * BN_BITS2) + BN_num_bits_word(a->d[i]));
}
-static void bn_free_d(BIGNUM *a, bool clear)
+static void bn_free_d(BIGNUM *a, int clear)
{
if (BN_get_flags(a, BN_FLG_SECURE))
OPENSSL_secure_clear_free(a->d, a->dmax * sizeof(a->d[0]));
@@ -219,12 +201,8 @@ void BN_clear_free(BIGNUM *a)
{
if (a == NULL)
return;
- if (!BN_get_flags(a, BN_FLG_STATIC_DATA)) {
- if (a->data != NULL)
- OSSL_FN_clear_free(a->data);
- else
- bn_free_d(a, true);
- }
+ if (a->d != NULL && !BN_get_flags(a, BN_FLG_STATIC_DATA))
+ bn_free_d(a, 1);
if (BN_get_flags(a, BN_FLG_MALLOCED)) {
OPENSSL_cleanse(a, sizeof(*a));
OPENSSL_free(a);
@@ -235,12 +213,8 @@ void BN_free(BIGNUM *a)
{
if (a == NULL)
return;
- if (!BN_get_flags(a, BN_FLG_STATIC_DATA)) {
- if (a->data != NULL)
- OSSL_FN_free(a->data);
- else
- bn_free_d(a, false);
- }
+ if (!BN_get_flags(a, BN_FLG_STATIC_DATA))
+ bn_free_d(a, 0);
if (a->flags & BN_FLG_MALLOCED)
OPENSSL_free(a);
}
@@ -275,11 +249,11 @@ BIGNUM *BN_secure_new(void)
/* This is used by bn_expand2() */
/* The caller MUST check that words > b->dmax before calling this */
-static OSSL_FN *bn_expand_internal(const BIGNUM *b, int words)
+static BN_ULONG *bn_expand_internal(const BIGNUM *b, int words)
{
- OSSL_FN *a = NULL;
+ BN_ULONG *a = NULL;
- if (ossl_unlikely(words > BN_MAX_WORDS)) {
+ if (ossl_unlikely(words > (INT_MAX / (4 * BN_BITS2)))) {
ERR_raise(ERR_LIB_BN, BN_R_BIGNUM_TOO_LONG);
return NULL;
}
@@ -288,19 +262,15 @@ static OSSL_FN *bn_expand_internal(const BIGNUM *b, int words)
return NULL;
}
if (BN_get_flags(b, BN_FLG_SECURE))
- a = OSSL_FN_secure_new_limbs(words);
+ a = OPENSSL_secure_calloc(words, sizeof(*a));
else
- a = OSSL_FN_new_limbs(words);
+ a = OPENSSL_calloc(words, sizeof(*a));
if (ossl_unlikely(a == NULL))
return NULL;
assert(b->top <= words);
- if (b->top > 0) {
- if (b->data != NULL)
- ossl_fn_copy_internal(a, b->data, -1);
- else if (b->d != NULL)
- ossl_fn_copy_internal_limbs(a, b->d, b->top);
- }
+ if (b->top > 0)
+ memcpy(a, b->d, sizeof(*a) * b->top);
return a;
}
@@ -316,58 +286,19 @@ static OSSL_FN *bn_expand_internal(const BIGNUM *b, int words)
BIGNUM *bn_expand2(BIGNUM *b, int words)
{
if (ossl_likely(words > b->dmax)) {
- OSSL_FN *a = bn_expand_internal(b, words);
+ BN_ULONG *a = bn_expand_internal(b, words);
if (ossl_unlikely(!a))
return NULL;
- if (b->data != NULL)
- OSSL_FN_clear_free(b->data);
- else if (b->d != NULL)
- bn_free_d(b, true);
- b->data = a;
- /* TODO(FIXNUM) The following is TO BE REMOVED */
- b->d = b->data->d;
- b->dmax = b->data->dsize;
+ if (b->d != NULL)
+ bn_free_d(b, 1);
+ b->d = a;
+ b->dmax = words;
}
return b;
}
-OSSL_FN *bn_acquire_ossl_fn(BIGNUM *b, int limbs)
-{
- if (ossl_unlikely(b == NULL))
- return NULL;
-
- if (bn_wexpand(b, limbs) == NULL)
- return NULL;
- /* TODO(FIXNUM): should we add a flag bit for this in b->flags ? */
- return b->data;
-}
-
-void bn_release(BIGNUM *b, int limbs)
-{
- if (ossl_unlikely(b == NULL || b->data == NULL))
- return;
-
- int fixed_top = (b->flags & BN_FLG_FIXED_TOP) != 0;
-
- bn_set_top(b, limbs);
-
- /* Don't correct top if BN_FLG_FIXED_TOP was set */
- if (fixed_top)
- return;
-
- bn_correct_top(b);
-}
-
-OSSL_FN *bn_get_ossl_fn(const BIGNUM *bn)
-{
- if (ossl_unlikely(bn == NULL))
- return NULL;
-
- return bn->data;
-}
-
BIGNUM *BN_dup(const BIGNUM *a)
{
BIGNUM *t;
@@ -400,14 +331,11 @@ BIGNUM *BN_copy(BIGNUM *a, const BIGNUM *b)
if (ossl_unlikely(bn_wexpand(a, bn_words) == NULL))
return NULL;
- if (ossl_likely(bn_words > 0)) {
- if (b->data != NULL)
- ossl_fn_copy_internal(a->data, b->data, bn_words);
- else if (b->d != NULL)
- ossl_fn_copy_internal_limbs(a->data, b->d, bn_words);
- }
+ if (ossl_likely(b->top > 0))
+ memcpy(a->d, b->d, sizeof(b->d[0]) * bn_words);
+
a->neg = b->neg;
- bn_set_top(a, b->top);
+ a->top = b->top;
a->flags |= b->flags & BN_FLG_FIXED_TOP;
bn_check_top(a);
return a;
@@ -419,7 +347,6 @@ BIGNUM *BN_copy(BIGNUM *a, const BIGNUM *b)
void BN_swap(BIGNUM *a, BIGNUM *b)
{
int flags_old_a, flags_old_b;
- OSSL_FN *tmp_data;
BN_ULONG *tmp_d;
int tmp_top, tmp_dmax, tmp_neg;
@@ -429,19 +356,16 @@ void BN_swap(BIGNUM *a, BIGNUM *b)
flags_old_a = a->flags;
flags_old_b = b->flags;
- tmp_data = a->data;
tmp_d = a->d;
tmp_top = a->top;
tmp_dmax = a->dmax;
tmp_neg = a->neg;
- a->data = b->data;
a->d = b->d;
a->top = b->top;
a->dmax = b->dmax;
a->neg = b->neg;
- b->data = tmp_data;
b->d = tmp_d;
b->top = tmp_top;
b->dmax = tmp_dmax;
@@ -458,12 +382,10 @@ void BN_clear(BIGNUM *a)
if (a == NULL)
return;
bn_check_top(a);
- if (a->data != NULL)
- OSSL_FN_clear(a->data);
- else if (a->d != NULL)
+ if (a->d != NULL)
OPENSSL_cleanse(a->d, sizeof(*a->d) * a->dmax);
a->neg = 0;
- bn_set_top(a, 0);
+ a->top = 0;
a->flags &= ~BN_FLG_FIXED_TOP;
}
@@ -480,11 +402,11 @@ BN_ULONG BN_get_word(const BIGNUM *a)
int BN_set_word(BIGNUM *a, BN_ULONG w)
{
bn_check_top(a);
- if (bn_wexpand(a, 1) == NULL)
+ if (bn_expand(a, (int)sizeof(BN_ULONG) * 8) == NULL)
return 0;
a->neg = 0;
a->d[0] = w;
- bn_set_top(a, (w ? 1 : 0));
+ a->top = (w ? 1 : 0);
a->flags &= ~BN_FLG_FIXED_TOP;
bn_check_top(a);
return 1;
@@ -566,7 +488,7 @@ static BIGNUM *bin2bn(const unsigned char *s, int len, BIGNUM *ret,
}
/* If it was all zeros, we're done */
if (len == 0) {
- bn_set_top(ret, 0);
+ ret->top = 0;
return ret;
}
n = ((len - 1) / BN_BYTES) + 1; /* Number of resulting bignum chunks */
@@ -574,7 +496,7 @@ static BIGNUM *bin2bn(const unsigned char *s, int len, BIGNUM *ret,
BN_free(bn);
return NULL;
}
- bn_set_top(ret, n);
+ ret->top = n;
ret->neg = neg;
for (i = 0; n-- > 0; i++) {
BN_ULONG l = 0; /* Accumulator */
@@ -774,19 +696,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((int)constant_time_lt_bn(ap[i], bp[i]),
-1, res);
res = constant_time_select_int((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;
}
@@ -855,7 +795,7 @@ int BN_cmp(const BIGNUM *a, const BIGNUM *b)
int BN_set_bit(BIGNUM *a, int n)
{
- int i, j;
+ int i, j, k;
if (n < 0)
return 0;
@@ -865,12 +805,9 @@ int BN_set_bit(BIGNUM *a, int n)
if (a->top <= i) {
if (bn_wexpand(a, i + 1) == NULL)
return 0;
- /*
- * If 'a' is actually expanded, we know that the expanded
- * part of the 'd' array is zeroed during allocation, so
- * no need to zero it again here.
- */
- bn_set_top(a, i + 1);
+ for (k = a->top; k < i + 1; k++)
+ a->d[k] = 0;
+ a->top = i + 1;
a->flags &= ~BN_FLG_FIXED_TOP;
}
@@ -923,9 +860,9 @@ int ossl_bn_mask_bits_fixed_top(BIGNUM *a, int n)
if (w >= a->top)
return 0;
if (b == 0)
- bn_set_top(a, w);
+ a->top = w;
else {
- bn_set_top(a, w + 1);
+ a->top = w + 1;
a->d[w] &= ~(BN_MASK2 << b);
}
a->flags |= BN_FLG_FIXED_TOP;
@@ -1092,7 +1029,7 @@ int BN_security_bits(int L, int N)
void BN_zero_ex(BIGNUM *a)
{
a->neg = 0;
- bn_set_top(a, 0);
+ a->top = 0;
a->flags &= ~BN_FLG_FIXED_TOP;
}
@@ -1103,12 +1040,7 @@ int BN_abs_is_word(const BIGNUM *a, const BN_ULONG w)
int BN_is_zero(const BIGNUM *a)
{
- if ((a->flags & BN_FLG_FIXED_TOP) == 0)
- return a->top == 0;
- for (size_t i = a->top; i-- > 0;)
- if (a->d[i] != (BN_ULONG)0)
- return 0;
- return 1;
+ return a->top == 0;
}
int BN_is_one(const BIGNUM *a)
@@ -1155,7 +1087,6 @@ int BN_to_montgomery(BIGNUM *r, const BIGNUM *a, BN_MONT_CTX *mont,
void BN_with_flags(BIGNUM *dest, const BIGNUM *b, int flags)
{
- dest->data = b->data;
dest->d = b->d;
dest->top = b->top;
dest->dmax = b->dmax;
@@ -1239,11 +1170,6 @@ void bn_correct_top_consttime(BIGNUM *a)
}
mask = constant_time_eq_int(atop, 0);
- /*
- * We just went through the whole 'd' array to identify where
- * any leading set of zeros are located, so there's no need to
- * call bn_set_top() here.
- */
a->top = atop;
a->neg = constant_time_select_int(mask, 0, a->neg);
a->flags &= ~BN_FLG_FIXED_TOP;
@@ -1260,14 +1186,10 @@ void bn_correct_top(BIGNUM *a)
if (*ftl != 0)
break;
}
- /*
- * We just verified that the BN_ULONGs between a->top and
- * tmp_top are all zero, so there's no need to call
- * bn_set_top() here.
- */
a->top = tmp_top;
}
if (a->top == 0)
a->neg = 0;
a->flags &= ~BN_FLG_FIXED_TOP;
+ bn_pollute(a);
}
diff --git a/crypto/bn/bn_local.h b/crypto/bn/bn_local.h
index d6813efed7..4602cdcaba 100644
--- a/crypto/bn/bn_local.h
+++ b/crypto/bn/bn_local.h
@@ -10,24 +10,27 @@
#ifndef OSSL_CRYPTO_BN_LOCAL_H
#define OSSL_CRYPTO_BN_LOCAL_H
-#include
-#include
-
#include
#include "internal/cryptlib.h"
#include "internal/numbers.h"
#include "crypto/bn.h"
-#include "../fn/fn_local.h"
-
/*
- * BN_RAND_DEBUG was historically used to poison unused words in bignum data,
- * for integrity debugging purposes. This isn't done any more, but enabling
- * BN_RAND_DEBUG also defined BN_DEBUG, which we preserve for the moment.
+ * These preprocessor symbols control various aspects of the bignum headers
+ * and library code. They're not defined by any "normal" configuration, as
+ * they are intended for development and testing purposes. NB: defining
+ * them can be useful for debugging application code as well as openssl
+ * itself. BN_DEBUG - turn on various debugging alterations to the bignum
+ * code BN_RAND_DEBUG - uses random poisoning of unused words to trip up
+ * mismanagement of bignum internals. Enable BN_RAND_DEBUG is known to
+ * break some of the OpenSSL tests.
*/
#if defined(BN_RAND_DEBUG) && !defined(BN_DEBUG)
#define BN_DEBUG
#endif
+#if defined(BN_RAND_DEBUG)
+#include
+#endif
/*
* This should limit the stack usage due to alloca to about 4K.
@@ -117,65 +120,32 @@ typedef unsigned long long BN_ULLONG;
#define BN_DEC_FMT2 "%09u"
#endif
-#define BN_MAX_WORDS (INT_MAX / (4 * BN_BITS2))
-
-BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num,
- BN_ULONG w);
-BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w);
-void bn_sqr_words(BN_ULONG *rp, const BN_ULONG *ap, int num);
-BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d);
-BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
- int num);
-BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
- int num);
-
-struct bignum_st {
- /* The number itself is a FIXNUM */
- OSSL_FN *data;
-
- /* Some of these flags are replicated in OSSL_FN, some are not */
- int flags;
-
- BN_ULONG *d; /* Pointer to |data->d| */
- int top; /* Index of last used d +1. */
- /* The next are internal book keeping for bn_expand. */
- int dmax; /* Copy of |data->dsize| */
- int neg; /* One if the number is negative */
-};
-
/*-
* Bignum consistency macros
- *
* There is one "API" macro, bn_fix_top(), for stripping leading zeroes from
* bignum data after direct manipulations on the data. There is also an
* "internal" macro, bn_check_top(), for verifying that there are no leading
- * zeroes, and in case the BIGNUM has an integrated OSSL_FN, check the
- * consistency of the integration, including that the unused part of the
- * data is all zeros.
- *
- * Unfortunately, some auditing is required due to the fact that bn_fix_top()
- * has become an overabused duck-tape because bignum data is occasionally
- * passed around in an inconsistent state. So the following changes have been
- * made to sort this out;
- *
+ * zeroes. Unfortunately, some auditing is required due to the fact that
+ * bn_fix_top() has become an overabused duct-tape because bignum data is
+ * occasionally passed around in an inconsistent state. So the following
+ * changes have been made to sort this out;
* - bn_fix_top()s implementation has been moved to bn_correct_top()
- * - if BN_DEBUG isn't defined:
- * - bn_check_top() does nothing.
- * - bn_fix_top() maps to bn_correct_top()
- * - if BN_DEBUG is defined:
- * - bn_check_top() performs its consistency checks
+ * - if BN_DEBUG isn't defined, bn_fix_top() maps to bn_correct_top(), and
+ * bn_check_top() is as before.
+ * - if BN_DEBUG *is* defined;
+ * - bn_check_top() tries to pollute unused words even if the bignum 'top' is
+ * consistent. (ed: only if BN_RAND_DEBUG is defined)
* - bn_fix_top() maps to bn_check_top() rather than "fixing" anything.
- *
* The idea is to have debug builds flag up inconsistent bignums when they
- * occur. If that occurs in a bn_fix_top(), we examine the code in question;
- * if the use of bn_fix_top() was appropriate (ie. it follows directly after
- * code that manipulates the bignum) it is converted to bn_correct_top(),
- * and if it was not appropriate, we convert it permanently to bn_check_top()
- * and track down the cause of the bug. Eventually, no internal code should be
- * using the bn_fix_top() macro. External applications and libraries should try
- * this with their own code too, both in terms of building against the openssl
- * headers with BN_DEBUG defined *and* linking with a version of OpenSSL built
- * with it defined. This not only improves external code, it provides more test
+ * occur. If that occurs in a bn_fix_top(), we examine the code in question; if
+ * the use of bn_fix_top() was appropriate (ie. it follows directly after code
+ * that manipulates the bignum) it is converted to bn_correct_top(), and if it
+ * was not appropriate, we convert it permanently to bn_check_top() and track
+ * down the cause of the bug. Eventually, no internal code should be using the
+ * bn_fix_top() macro. External applications and libraries should try this with
+ * their own code too, both in terms of building against the openssl headers
+ * with BN_DEBUG defined *and* linking with a version of OpenSSL built with it
+ * defined. This not only improves external code, it provides more test
* coverage for openssl's own code.
*/
@@ -194,49 +164,54 @@ struct bignum_st {
* all operations manipulating the bit in question in non-BN_DEBUG build.
*/
#define BN_FLG_FIXED_TOP 0x10000
-
-static ossl_inline bool bn_check_zero(BN_ULONG *words, int num_words)
-{
- for (int i = 0; i < num_words; i++)
- if (words[i] != 0)
- return false;
- return true;
-}
-
-static ossl_inline void bn_check_top(const BIGNUM *bn)
-{
- if (bn != NULL) {
- /* BIGNUM <-> OSSL_FN compat checks */
- if (bn->data != NULL) {
- /* TODO(FIXNUM): Assertion for the future */
- /* assert(_bnum2->d == NULL); */
- assert(bn->d == bn->data->d);
- assert(bn->dmax == bn->data->dsize);
- assert(bn_check_zero(&bn->d[bn->top], bn->dmax - bn->top));
- }
- /* BIGNUM specific checks */
- if (bn->top == 0) {
- assert(!bn->neg);
- } else if ((bn->flags & BN_FLG_FIXED_TOP) == 0) {
- assert(bn->d[bn->top - 1] != 0);
- }
- assert(bn->dmax >= 0 && bn->dmax <= BN_MAX_WORDS);
- }
-}
+#ifdef BN_RAND_DEBUG
+#define bn_pollute(a) \
+ do { \
+ const BIGNUM *_bnum1 = (a); \
+ if (_bnum1->top < _bnum1->dmax) { \
+ unsigned char _tmp_char; \
+ /* We cast away const without the compiler knowing, any \
+ * *genuinely* constant variables that aren't mutable \
+ * wouldn't be constructed with top!=dmax. */ \
+ BN_ULONG *_not_const; \
+ memcpy(&_not_const, &_bnum1->d, sizeof(_not_const)); \
+ (void)RAND_bytes(&_tmp_char, 1); /* Debug only - safe to ignore error return */ \
+ memset(_not_const + _bnum1->top, _tmp_char, \
+ sizeof(*_not_const) * (_bnum1->dmax - _bnum1->top)); \
+ } \
+ } while (0)
+#else
+#define bn_pollute(a)
+#endif
+#define bn_check_top(a) \
+ do { \
+ const BIGNUM *_bnum2 = (a); \
+ if (_bnum2 != NULL) { \
+ int _top = _bnum2->top; \
+ if (_top == 0) { \
+ assert(!_bnum2->neg); \
+ } else if ((_bnum2->flags & BN_FLG_FIXED_TOP) == 0) { \
+ assert(_bnum2->d[_top - 1] != 0); \
+ } \
+ bn_pollute(_bnum2); \
+ } \
+ } while (0)
#define bn_fix_top(a) bn_check_top(a)
-static ossl_inline void bn_wcheck_size(const BIGNUM *bn, int words)
-{
- assert(words <= bn->dmax);
- assert(words >= bn->top);
-}
-
#define bn_check_size(bn, bits) bn_wcheck_size(bn, ((bits + BN_BITS2 - 1)) / BN_BITS2)
+#define bn_wcheck_size(bn, words) \
+ do { \
+ const BIGNUM *_bnum2 = (bn); \
+ assert((words) <= (_bnum2)->dmax && (words) >= (_bnum2)->top); \
+ /* avoid unused variable warning with NDEBUG */ \
+ (void)(_bnum2); \
+ } while (0)
#else /* !BN_DEBUG */
#define BN_FLG_FIXED_TOP 0
+#define bn_pollute(a)
#define bn_check_top(a)
#define bn_fix_top(a) bn_correct_top(a)
#define bn_check_size(bn, bits)
@@ -244,6 +219,29 @@ static ossl_inline void bn_wcheck_size(const BIGNUM *bn, int words)
#endif
+BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num,
+ BN_ULONG w);
+BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w);
+void bn_sqr_words(BN_ULONG *rp, const BN_ULONG *ap, int num);
+BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d);
+BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
+ int num);
+BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
+ int num);
+
+struct bignum_st {
+ BN_ULONG *d; /*
+ * Pointer to an array of 'BN_BITS2' bit
+ * chunks. These chunks are organised in
+ * a least significant chunk first order.
+ */
+ int top; /* Index of last used d +1. */
+ /* The next are internal book keeping for bn_expand. */
+ int dmax; /* Size of the d array. */
+ int neg; /* one if the number is negative */
+ int flags;
+};
+
/* Used for montgomery multiplication */
struct bn_mont_ctx_st {
BIGNUM RR; /* used to convert to montgomery form,
@@ -382,7 +380,7 @@ struct bn_gencb_st {
#if defined(__DECC)
#include
#define BN_UMULT_HIGH(a, b) (BN_ULONG)asm("umulh %a0,%a1,%v0", (a), (b))
-#elif defined(__GNUC__) && __GNUC__ >= 2
+#elif defined(__GNUC__)
#define BN_UMULT_HIGH(a, b) ({ \
register BN_ULONG ret; \
asm ("umulh %1,%2,%0" \
@@ -391,7 +389,7 @@ struct bn_gencb_st {
ret; })
#endif /* compiler */
#elif defined(_ARCH_PPC64) && defined(SIXTY_FOUR_BIT_LONG)
-#if defined(__GNUC__) && __GNUC__ >= 2
+#if defined(__GNUC__)
#define BN_UMULT_HIGH(a, b) ({ \
register BN_ULONG ret; \
asm ("mulhdu %0,%1,%2" \
@@ -400,7 +398,7 @@ struct bn_gencb_st {
ret; })
#endif /* compiler */
#elif (defined(__x86_64) || defined(__x86_64__)) && (defined(SIXTY_FOUR_BIT_LONG) || defined(SIXTY_FOUR_BIT))
-#if defined(__GNUC__) && __GNUC__ >= 2
+#if defined(__GNUC__)
#define BN_UMULT_HIGH(a, b) ({ \
register BN_ULONG ret,discard; \
asm ("mulq %3" \
@@ -424,7 +422,7 @@ unsigned __int64 _umul128(unsigned __int64 a, unsigned __int64 b,
#define BN_UMULT_LOHI(low, high, a, b) ((low) = _umul128((a), (b), &(high)))
#endif
#elif defined(__mips) && (defined(SIXTY_FOUR_BIT) || defined(SIXTY_FOUR_BIT_LONG))
-#if defined(__GNUC__) && __GNUC__ >= 2
+#if defined(__GNUC__)
#define BN_UMULT_HIGH(a, b) ({ \
register BN_ULONG ret; \
asm ("dmultu %1,%2" \
@@ -437,7 +435,7 @@ unsigned __int64 _umul128(unsigned __int64 a, unsigned __int64 b,
: "r"(a), "r"(b));
#endif
#elif defined(__aarch64__) && defined(SIXTY_FOUR_BIT_LONG)
-#if defined(__GNUC__) && __GNUC__ >= 2
+#if defined(__GNUC__)
#define BN_UMULT_HIGH(a, b) ({ \
register BN_ULONG ret; \
asm ("umulh %0,%1,%2" \
@@ -645,21 +643,21 @@ void BN_RECP_CTX_init(BN_RECP_CTX *recp);
void BN_MONT_CTX_init(BN_MONT_CTX *ctx);
void bn_init(BIGNUM *a);
-void bn_mul_normal(BN_ULONG *r, const BN_ULONG *a, int na, const BN_ULONG *b, int nb);
-void bn_mul_comba8(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b);
-void bn_mul_comba4(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b);
+void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b, int nb);
+void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b);
+void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b);
void bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, int n, BN_ULONG *tmp);
void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a);
void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a);
int bn_cmp_words(const BN_ULONG *a, const BN_ULONG *b, int n);
int bn_cmp_part_words(const BN_ULONG *a, const BN_ULONG *b, int cl, int dl);
-void bn_mul_recursive(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, int n2,
+void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
int dna, int dnb, BN_ULONG *t);
-void bn_mul_part_recursive(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
+void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b,
int n, int tna, int tnb, BN_ULONG *t);
void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2, BN_ULONG *t);
-void bn_mul_low_normal(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, int n);
-void bn_mul_low_recursive(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, int n2,
+void bn_mul_low_normal(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n);
+void bn_mul_low_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
BN_ULONG *t);
BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
int cl, int dl);
@@ -669,7 +667,6 @@ void bn_correct_top_consttime(BIGNUM *a);
BIGNUM *int_bn_mod_inverse(BIGNUM *in,
const BIGNUM *a, const BIGNUM *n, BN_CTX *ctx,
int *noinv);
-void bn_mul_truncated(BN_ULONG *r, int nr, const BN_ULONG *a, int na, const BN_ULONG *b, int nb);
static ossl_inline BIGNUM *bn_expand(BIGNUM *a, int bits)
{
@@ -685,29 +682,4 @@ static ossl_inline BIGNUM *bn_expand(BIGNUM *a, int bits)
int ossl_bn_check_prime(const BIGNUM *w, int checks, BN_CTX *ctx,
int do_trial_division, BN_GENCB *cb);
-/**
- * Set top on a given BIGNUM. If it has an associated OSSL_FN (the 'data'
- * field is non-NULL), and the new 'top' is less than the existing 'top',
- * zeroise the space between them.
- *
- * @param[in] b The BIGNUM instance to zeroise
- * @param[in] newtop The new 'top'
- * @returns the new 'top'
- * @pre b must not be NULL and newtop must be zero or positive
- */
-static ossl_inline int bn_set_top(BIGNUM *b, int newtop)
-{
- assert(b != NULL && newtop >= 0);
-
- if (b->data != NULL && newtop < b->top) {
- BN_ULONG *start = &(b->d[newtop]);
- size_t bytes = sizeof(BN_ULONG) * (b->top - newtop);
-
- memset(start, 0, bytes);
- }
-
- b->top = newtop;
- return b->top;
-}
-
#endif
diff --git a/crypto/bn/bn_mod.c b/crypto/bn/bn_mod.c
index 6db2636d76..703072bbf2 100644
--- a/crypto/bn/bn_mod.c
+++ b/crypto/bn/bn_mod.c
@@ -90,7 +90,7 @@ int bn_mod_add_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
rp[i] = (carry & tp[i]) | (~carry & rp[i]);
((volatile BN_ULONG *)tp)[i] = 0;
}
- bn_set_top(r, (int)mtop);
+ r->top = (int)mtop;
r->flags |= BN_FLG_FIXED_TOP;
r->neg = 0;
@@ -176,7 +176,7 @@ int bn_mod_sub_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
carry += (rp[i] < ta);
}
- bn_set_top(r, (int)mtop);
+ r->top = (int)mtop;
r->flags |= BN_FLG_FIXED_TOP;
r->neg = 0;
diff --git a/crypto/bn/bn_mont.c b/crypto/bn/bn_mont.c
index aeaf399231..0bdfce3c48 100644
--- a/crypto/bn/bn_mont.c
+++ b/crypto/bn/bn_mont.c
@@ -46,7 +46,7 @@ int bn_mul_mont_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
return 0;
if (bn_mul_mont(r->d, a->d, b->d, mont->N.d, mont->n0, num)) {
r->neg = a->neg ^ b->neg;
- bn_set_top(r, num);
+ r->top = num;
r->flags |= BN_FLG_FIXED_TOP;
return 1;
}
@@ -94,7 +94,7 @@ static int bn_from_montgomery_word(BIGNUM *ret, BIGNUM *r, BN_MONT_CTX *mont)
n = &(mont->N);
nl = n->top;
if (nl == 0) {
- bn_set_top(ret, 0);
+ ret->top = 0;
return 1;
}
@@ -112,7 +112,7 @@ static int bn_from_montgomery_word(BIGNUM *ret, BIGNUM *r, BN_MONT_CTX *mont)
rp[i] &= v;
}
- bn_set_top(r, max);
+ r->top = max;
r->flags |= BN_FLG_FIXED_TOP;
n0 = mont->n0[0];
@@ -131,7 +131,7 @@ static int bn_from_montgomery_word(BIGNUM *ret, BIGNUM *r, BN_MONT_CTX *mont)
if (bn_wexpand(ret, nl) == NULL)
return 0;
- bn_set_top(ret, nl);
+ ret->top = nl;
ret->flags |= BN_FLG_FIXED_TOP;
ret->neg = r->neg;
@@ -325,7 +325,7 @@ int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx)
Ri->neg = 0;
Ri->d[0] = BN_MASK2;
Ri->d[1] = BN_MASK2;
- bn_set_top(Ri, 2);
+ Ri->top = 2;
}
if (!BN_div(Ri, NULL, Ri, &tmod, ctx))
goto err;
diff --git a/crypto/bn/bn_mpi.c b/crypto/bn/bn_mpi.c
index 17ffc6a476..d2a86a3ead 100644
--- a/crypto/bn/bn_mpi.c
+++ b/crypto/bn/bn_mpi.c
@@ -65,7 +65,7 @@ BIGNUM *BN_mpi2bn(const unsigned char *d, int n, BIGNUM *ain)
if (len == 0) {
a->neg = 0;
- bn_set_top(a, 0);
+ a->top = 0;
return a;
}
d += 4;
diff --git a/crypto/bn/bn_mul.c b/crypto/bn/bn_mul.c
index d887c23225..aefc335923 100644
--- a/crypto/bn/bn_mul.c
+++ b/crypto/bn/bn_mul.c
@@ -11,6 +11,479 @@
#include "internal/cryptlib.h"
#include "bn_local.h"
+#if defined(OPENSSL_NO_ASM) || !defined(OPENSSL_BN_ASM_PART_WORDS)
+/*
+ * Here follows specialised variants of bn_add_words() and bn_sub_words().
+ * They have the property performing operations on arrays of different sizes.
+ * The sizes of those arrays is expressed through cl, which is the common
+ * length ( basically, min(len(a),len(b)) ), and dl, which is the delta
+ * between the two lengths, calculated as len(a)-len(b). All lengths are the
+ * number of BN_ULONGs... For the operations that require a result array as
+ * parameter, it must have the length cl+abs(dl). These functions should
+ * probably end up in bn_asm.c as soon as there are assembler counterparts
+ * for the systems that use assembler files.
+ */
+
+BN_ULONG bn_sub_part_words(BN_ULONG *r,
+ const BN_ULONG *a, const BN_ULONG *b,
+ int cl, int dl)
+{
+ BN_ULONG c, t;
+
+ assert(cl >= 0);
+ c = bn_sub_words(r, a, b, cl);
+
+ if (dl == 0)
+ return c;
+
+ r += cl;
+ a += cl;
+ b += cl;
+
+ if (dl < 0) {
+ for (;;) {
+ t = b[0];
+ r[0] = (0 - t - c) & BN_MASK2;
+ if (t != 0)
+ c = 1;
+ if (++dl >= 0)
+ break;
+
+ t = b[1];
+ r[1] = (0 - t - c) & BN_MASK2;
+ if (t != 0)
+ c = 1;
+ if (++dl >= 0)
+ break;
+
+ t = b[2];
+ r[2] = (0 - t - c) & BN_MASK2;
+ if (t != 0)
+ c = 1;
+ if (++dl >= 0)
+ break;
+
+ t = b[3];
+ r[3] = (0 - t - c) & BN_MASK2;
+ if (t != 0)
+ c = 1;
+ if (++dl >= 0)
+ break;
+
+ b += 4;
+ r += 4;
+ }
+ } else {
+ int save_dl = dl;
+ while (c) {
+ t = a[0];
+ r[0] = (t - c) & BN_MASK2;
+ if (t != 0)
+ c = 0;
+ if (--dl <= 0)
+ break;
+
+ t = a[1];
+ r[1] = (t - c) & BN_MASK2;
+ if (t != 0)
+ c = 0;
+ if (--dl <= 0)
+ break;
+
+ t = a[2];
+ r[2] = (t - c) & BN_MASK2;
+ if (t != 0)
+ c = 0;
+ if (--dl <= 0)
+ break;
+
+ t = a[3];
+ r[3] = (t - c) & BN_MASK2;
+ if (t != 0)
+ c = 0;
+ if (--dl <= 0)
+ break;
+
+ save_dl = dl;
+ a += 4;
+ r += 4;
+ }
+ if (dl > 0) {
+ if (save_dl > dl) {
+ switch (save_dl - dl) {
+ case 1:
+ r[1] = a[1];
+ if (--dl <= 0)
+ break;
+ /* fall through */
+ case 2:
+ r[2] = a[2];
+ if (--dl <= 0)
+ break;
+ /* fall through */
+ case 3:
+ r[3] = a[3];
+ if (--dl <= 0)
+ break;
+ }
+ a += 4;
+ r += 4;
+ }
+ }
+ if (dl > 0) {
+ for (;;) {
+ r[0] = a[0];
+ if (--dl <= 0)
+ break;
+ r[1] = a[1];
+ if (--dl <= 0)
+ break;
+ r[2] = a[2];
+ if (--dl <= 0)
+ break;
+ r[3] = a[3];
+ if (--dl <= 0)
+ break;
+
+ a += 4;
+ r += 4;
+ }
+ }
+ }
+ return c;
+}
+#endif
+
+#ifndef OPENSSL_SMALL_FOOTPRINT
+/*
+ * Karatsuba recursive multiplication algorithm (cf. Knuth, The Art of
+ * Computer Programming, Vol. 2)
+ */
+
+/*-
+ * r is 2*n2 words in size,
+ * a and b are both n2 words in size.
+ * n2 must be a power of 2.
+ * We multiply and return the result.
+ * t must be 2*n2 words in size
+ * We calculate
+ * a[0]*b[0]
+ * a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0])
+ * a[1]*b[1]
+ */
+/* dnX may not be positive, but n2/2+dnX has to be */
+void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
+ int dna, int dnb, BN_ULONG *t)
+{
+ int n = n2 / 2, c1, c2;
+ int tna = n + dna, tnb = n + dnb;
+ unsigned int neg, zero;
+ BN_ULONG ln, lo, *p;
+
+ /*
+ * Only call bn_mul_comba 8 if n2 == 8 and the two arrays are complete
+ * [steve]
+ */
+ if (n2 == 8 && dna == 0 && dnb == 0) {
+ bn_mul_comba8(r, a, b);
+ return;
+ }
+
+ /* Else do normal multiply */
+ if (n2 < BN_MUL_RECURSIVE_SIZE_NORMAL) {
+ bn_mul_normal(r, a, n2 + dna, b, n2 + dnb);
+ if ((dna + dnb) < 0)
+ memset(&r[2 * n2 + dna + dnb], 0,
+ sizeof(BN_ULONG) * -(dna + dnb));
+ return;
+ }
+ /* r=(a[0]-a[1])*(b[1]-b[0]) */
+ c1 = bn_cmp_part_words(a, &(a[n]), tna, n - tna);
+ c2 = bn_cmp_part_words(&(b[n]), b, tnb, tnb - n);
+ zero = neg = 0;
+ switch (c1 * 3 + c2) {
+ case -4:
+ bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
+ bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
+ break;
+ case -3:
+ zero = 1;
+ break;
+ case -2:
+ bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
+ bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); /* + */
+ neg = 1;
+ break;
+ case -1:
+ case 0:
+ case 1:
+ zero = 1;
+ break;
+ case 2:
+ bn_sub_part_words(t, a, &(a[n]), tna, n - tna); /* + */
+ bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
+ neg = 1;
+ break;
+ case 3:
+ zero = 1;
+ break;
+ case 4:
+ bn_sub_part_words(t, a, &(a[n]), tna, n - tna);
+ bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n);
+ break;
+ }
+
+ if (n == 4 && dna == 0 && dnb == 0) { /* XXX: bn_mul_comba4 could take
+ * extra args to do this well */
+ if (!zero)
+ bn_mul_comba4(&(t[n2]), t, &(t[n]));
+ else
+ memset(&t[n2], 0, sizeof(*t) * 8);
+
+ bn_mul_comba4(r, a, b);
+ bn_mul_comba4(&(r[n2]), &(a[n]), &(b[n]));
+ } else if (n == 8 && dna == 0 && dnb == 0) { /* XXX: bn_mul_comba8 could
+ * take extra args to do
+ * this well */
+ if (!zero)
+ bn_mul_comba8(&(t[n2]), t, &(t[n]));
+ else
+ memset(&t[n2], 0, sizeof(*t) * 16);
+
+ bn_mul_comba8(r, a, b);
+ bn_mul_comba8(&(r[n2]), &(a[n]), &(b[n]));
+ } else {
+ p = &(t[n2 * 2]);
+ if (!zero)
+ bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p);
+ else
+ memset(&t[n2], 0, sizeof(*t) * n2);
+ bn_mul_recursive(r, a, b, n, 0, 0, p);
+ bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), n, dna, dnb, p);
+ }
+
+ /*-
+ * t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign
+ * r[10] holds (a[0]*b[0])
+ * r[32] holds (b[1]*b[1])
+ */
+
+ c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));
+
+ if (neg) { /* if t[32] is negative */
+ c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
+ } else {
+ /* Might have a carry */
+ c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), t, n2));
+ }
+
+ /*-
+ * t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1])
+ * r[10] holds (a[0]*b[0])
+ * r[32] holds (b[1]*b[1])
+ * c1 holds the carry bits
+ */
+ c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
+ if (c1) {
+ p = &(r[n + n2]);
+ lo = *p;
+ ln = (lo + c1) & BN_MASK2;
+ *p = ln;
+
+ /*
+ * The overflow will stop before we over write words we should not
+ * overwrite
+ */
+ if (ln < (BN_ULONG)c1) {
+ do {
+ p++;
+ lo = *p;
+ ln = (lo + 1) & BN_MASK2;
+ *p = ln;
+ } while (ln == 0);
+ }
+ }
+}
+
+/*
+ * n+tn is the word length t needs to be n*4 is size, as does r
+ */
+/* tnX may not be negative but less than n */
+void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n,
+ int tna, int tnb, BN_ULONG *t)
+{
+ int i, j, n2 = n * 2;
+ int c1, c2, neg;
+ BN_ULONG ln, lo, *p;
+
+ if (n < 8) {
+ bn_mul_normal(r, a, n + tna, b, n + tnb);
+ return;
+ }
+
+ /* r=(a[0]-a[1])*(b[1]-b[0]) */
+ c1 = bn_cmp_part_words(a, &(a[n]), tna, n - tna);
+ c2 = bn_cmp_part_words(&(b[n]), b, tnb, tnb - n);
+ neg = 0;
+ switch (c1 * 3 + c2) {
+ case -4:
+ bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
+ bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
+ break;
+ case -3:
+ case -2:
+ bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
+ bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); /* + */
+ neg = 1;
+ break;
+ case -1:
+ case 0:
+ case 1:
+ case 2:
+ bn_sub_part_words(t, a, &(a[n]), tna, n - tna); /* + */
+ bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
+ neg = 1;
+ break;
+ case 3:
+ case 4:
+ bn_sub_part_words(t, a, &(a[n]), tna, n - tna);
+ bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n);
+ break;
+ }
+ /*
+ * The zero case isn't yet implemented here. The speedup would probably
+ * be negligible.
+ */
+#if 0
+ if (n == 4) {
+ bn_mul_comba4(&(t[n2]), t, &(t[n]));
+ bn_mul_comba4(r, a, b);
+ bn_mul_normal(&(r[n2]), &(a[n]), tn, &(b[n]), tn);
+ memset(&r[n2 + tn * 2], 0, sizeof(*r) * (n2 - tn * 2));
+ } else
+#endif
+ if (n == 8) {
+ bn_mul_comba8(&(t[n2]), t, &(t[n]));
+ bn_mul_comba8(r, a, b);
+ bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb);
+ memset(&r[n2 + tna + tnb], 0, sizeof(*r) * (n2 - tna - tnb));
+ } else {
+ p = &(t[n2 * 2]);
+ bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p);
+ bn_mul_recursive(r, a, b, n, 0, 0, p);
+ i = n / 2;
+ /*
+ * If there is only a bottom half to the number, just do it
+ */
+ if (tna > tnb)
+ j = tna - i;
+ else
+ j = tnb - i;
+ if (j == 0) {
+ bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]),
+ i, tna - i, tnb - i, p);
+ memset(&r[n2 + i * 2], 0, sizeof(*r) * (n2 - i * 2));
+ } else if (j > 0) { /* eg, n == 16, i == 8 and tn == 11 */
+ bn_mul_part_recursive(&(r[n2]), &(a[n]), &(b[n]),
+ i, tna - i, tnb - i, p);
+ memset(&(r[n2 + tna + tnb]), 0,
+ sizeof(BN_ULONG) * (n2 - tna - tnb));
+ } else { /* (j < 0) eg, n == 16, i == 8 and tn == 5 */
+
+ memset(&r[n2], 0, sizeof(*r) * n2);
+ if (tna < BN_MUL_RECURSIVE_SIZE_NORMAL
+ && tnb < BN_MUL_RECURSIVE_SIZE_NORMAL) {
+ bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb);
+ } else {
+ for (;;) {
+ i /= 2;
+ /*
+ * these simplified conditions work exclusively because
+ * difference between tna and tnb is 1 or 0
+ */
+ if (i < tna || i < tnb) {
+ bn_mul_part_recursive(&(r[n2]),
+ &(a[n]), &(b[n]),
+ i, tna - i, tnb - i, p);
+ break;
+ } else if (i == tna || i == tnb) {
+ bn_mul_recursive(&(r[n2]),
+ &(a[n]), &(b[n]),
+ i, tna - i, tnb - i, p);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /*-
+ * t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign
+ * r[10] holds (a[0]*b[0])
+ * r[32] holds (b[1]*b[1])
+ */
+
+ c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));
+
+ if (neg) { /* if t[32] is negative */
+ c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
+ } else {
+ /* Might have a carry */
+ c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), t, n2));
+ }
+
+ /*-
+ * t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1])
+ * r[10] holds (a[0]*b[0])
+ * r[32] holds (b[1]*b[1])
+ * c1 holds the carry bits
+ */
+ c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
+ if (c1) {
+ p = &(r[n + n2]);
+ lo = *p;
+ ln = (lo + c1) & BN_MASK2;
+ *p = ln;
+
+ /*
+ * The overflow will stop before we over write words we should not
+ * overwrite
+ */
+ if (ln < (BN_ULONG)c1) {
+ do {
+ p++;
+ lo = *p;
+ ln = (lo + 1) & BN_MASK2;
+ *p = ln;
+ } while (ln == 0);
+ }
+ }
+}
+
+/*-
+ * a and b must be the same size, which is n2.
+ * r needs to be n2 words and t needs to be n2*2
+ */
+void bn_mul_low_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
+ BN_ULONG *t)
+{
+ int n = n2 / 2;
+
+ bn_mul_recursive(r, a, b, n, 0, 0, &(t[0]));
+ if (n >= BN_MUL_LOW_RECURSIVE_SIZE_NORMAL) {
+ bn_mul_low_recursive(&(t[0]), &(a[0]), &(b[n]), n, &(t[n2]));
+ bn_add_words(&(r[n]), &(r[n]), &(t[0]), n);
+ bn_mul_low_recursive(&(t[0]), &(a[n]), &(b[0]), n, &(t[n2]));
+ bn_add_words(&(r[n]), &(r[n]), &(t[0]), n);
+ } else {
+ bn_mul_low_normal(&(t[0]), &(a[0]), &(b[n]), n);
+ bn_mul_low_normal(&(t[n]), &(a[n]), &(b[0]), n);
+ bn_add_words(&(r[n]), &(r[n]), &(t[0]), n);
+ bn_add_words(&(r[n]), &(r[n]), &(t[n]), n);
+ }
+}
+#endif /* OPENSSL_SMALL_FOOTPRINT */
+
int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
{
int ret = bn_mul_fixed_top(r, a, b, ctx);
@@ -28,6 +501,8 @@ int bn_mul_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
BIGNUM *rr;
#if !defined(OPENSSL_SMALL_FOOTPRINT)
int i;
+ BIGNUM *t = NULL;
+ int j = 0, k;
#endif
bn_check_top(a);
@@ -58,8 +533,7 @@ int bn_mul_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
if (al == 4) {
if (bn_wexpand(rr, 8) == NULL)
goto err;
- rr->flags |= BN_FLG_FIXED_TOP;
- bn_set_top(rr, 8);
+ rr->top = 8;
bn_mul_comba4(rr->d, a->d, b->d);
goto end;
}
@@ -67,8 +541,7 @@ int bn_mul_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
if (al == 8) {
if (bn_wexpand(rr, 16) == NULL)
goto err;
- rr->flags |= BN_FLG_FIXED_TOP;
- bn_set_top(rr, 16);
+ rr->top = 16;
bn_mul_comba8(rr->d, a->d, b->d);
goto end;
}
@@ -76,9 +549,6 @@ int bn_mul_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
if ((al >= BN_MULL_SIZE_NORMAL) && (bl >= BN_MULL_SIZE_NORMAL)) {
if (i >= -1 && i <= 1) {
- BIGNUM *t = NULL;
- int j = 0, k;
-
/*
* Find out the power of two lower or equal to the longest of the
* two numbers
@@ -98,33 +568,26 @@ int bn_mul_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
if (al > j || bl > j) {
if (bn_wexpand(t, k * 4) == NULL)
goto err;
- t->top = k * 4;
- t->flags |= BN_FLG_FIXED_TOP;
if (bn_wexpand(rr, k * 4) == NULL)
goto err;
- bn_set_top(rr, k * 4);
- rr->flags |= BN_FLG_FIXED_TOP;
bn_mul_part_recursive(rr->d, a->d, b->d,
j, al - j, bl - j, t->d);
} else { /* al <= j || bl <= j */
+
if (bn_wexpand(t, k * 2) == NULL)
goto err;
- t->top = k * 2;
- t->flags |= BN_FLG_FIXED_TOP;
if (bn_wexpand(rr, k * 2) == NULL)
goto err;
- bn_set_top(rr, k * 2);
- rr->flags |= BN_FLG_FIXED_TOP;
bn_mul_recursive(rr->d, a->d, b->d, j, al - j, bl - j, t->d);
}
- bn_set_top(rr, top);
+ rr->top = top;
goto end;
}
}
#endif /* OPENSSL_SMALL_FOOTPRINT */
if (bn_wexpand(rr, top) == NULL)
goto err;
- bn_set_top(rr, top);
+ rr->top = top;
bn_mul_normal(rr->d, a->d, al, b->d, bl);
#if !defined(OPENSSL_SMALL_FOOTPRINT)
@@ -141,3 +604,66 @@ err:
BN_CTX_end(ctx);
return ret;
}
+
+void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b, int nb)
+{
+ BN_ULONG *rr;
+
+ if (na < nb) {
+ int itmp;
+ BN_ULONG *ltmp;
+
+ itmp = na;
+ na = nb;
+ nb = itmp;
+ ltmp = a;
+ a = b;
+ b = ltmp;
+ }
+ rr = &(r[na]);
+ if (nb <= 0) {
+ (void)bn_mul_words(r, a, na, 0);
+ return;
+ } else
+ rr[0] = bn_mul_words(r, a, na, b[0]);
+
+ for (;;) {
+ if (--nb <= 0)
+ return;
+ rr[1] = bn_mul_add_words(&(r[1]), a, na, b[1]);
+ if (--nb <= 0)
+ return;
+ rr[2] = bn_mul_add_words(&(r[2]), a, na, b[2]);
+ if (--nb <= 0)
+ return;
+ rr[3] = bn_mul_add_words(&(r[3]), a, na, b[3]);
+ if (--nb <= 0)
+ return;
+ rr[4] = bn_mul_add_words(&(r[4]), a, na, b[4]);
+ rr += 4;
+ r += 4;
+ b += 4;
+ }
+}
+
+void bn_mul_low_normal(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
+{
+ bn_mul_words(r, a, n, b[0]);
+
+ for (;;) {
+ if (--n <= 0)
+ return;
+ bn_mul_add_words(&(r[1]), a, n, b[1]);
+ if (--n <= 0)
+ return;
+ bn_mul_add_words(&(r[2]), a, n, b[2]);
+ if (--n <= 0)
+ return;
+ bn_mul_add_words(&(r[3]), a, n, b[3]);
+ if (--n <= 0)
+ return;
+ bn_mul_add_words(&(r[4]), a, n, b[4]);
+ r += 4;
+ b += 4;
+ }
+}
diff --git a/crypto/bn/bn_nist.c b/crypto/bn/bn_nist.c
index b7c99006d0..b820ef7486 100644
--- a/crypto/bn/bn_nist.c
+++ b/crypto/bn/bn_nist.c
@@ -184,38 +184,43 @@ static const BN_ULONG _nist_p_521_sqr[] = {
#endif
static const BIGNUM ossl_bignum_nist_p_192 = {
- .d = (BN_ULONG *)_nist_p_192[0],
- .top = BN_NIST_192_TOP,
- .dmax = BN_NIST_192_TOP,
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)_nist_p_192[0],
+ BN_NIST_192_TOP,
+ BN_NIST_192_TOP,
+ 0,
+ BN_FLG_STATIC_DATA
};
static const BIGNUM ossl_bignum_nist_p_224 = {
- .d = (BN_ULONG *)_nist_p_224[0],
- .top = BN_NIST_224_TOP,
- .dmax = BN_NIST_224_TOP,
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)_nist_p_224[0],
+ BN_NIST_224_TOP,
+ BN_NIST_224_TOP,
+ 0,
+ BN_FLG_STATIC_DATA
};
static const BIGNUM ossl_bignum_nist_p_256 = {
- .d = (BN_ULONG *)_nist_p_256[0],
- .top = BN_NIST_256_TOP,
- .dmax = BN_NIST_256_TOP,
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)_nist_p_256[0],
+ BN_NIST_256_TOP,
+ BN_NIST_256_TOP,
+ 0,
+ BN_FLG_STATIC_DATA
};
static const BIGNUM ossl_bignum_nist_p_384 = {
- .d = (BN_ULONG *)_nist_p_384[0],
- .top = BN_NIST_384_TOP,
- .dmax = BN_NIST_384_TOP,
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)_nist_p_384[0],
+ BN_NIST_384_TOP,
+ BN_NIST_384_TOP,
+ 0,
+ BN_FLG_STATIC_DATA
};
static const BIGNUM ossl_bignum_nist_p_521 = {
- .d = (BN_ULONG *)_nist_p_521,
- .top = BN_NIST_521_TOP,
- .dmax = BN_NIST_521_TOP,
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)_nist_p_521,
+ BN_NIST_521_TOP,
+ BN_NIST_521_TOP,
+ 0,
+ BN_FLG_STATIC_DATA
};
const BIGNUM *BN_get0_nist_prime_192(void)
@@ -354,10 +359,10 @@ int BN_nist_mod_192(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
} buf;
BN_ULONG c_d[BN_NIST_192_TOP], *res;
static const BIGNUM ossl_bignum_nist_p_192_sqr = {
- .d = (BN_ULONG *)_nist_p_192_sqr,
- .top = OSSL_NELEM(_nist_p_192_sqr),
- .dmax = OSSL_NELEM(_nist_p_192_sqr),
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)_nist_p_192_sqr,
+ OSSL_NELEM(_nist_p_192_sqr),
+ OSSL_NELEM(_nist_p_192_sqr),
+ 0, BN_FLG_STATIC_DATA
};
field = &ossl_bignum_nist_p_192; /* just to make sure */
@@ -457,7 +462,7 @@ int BN_nist_mod_192(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
? r_d
: c_d;
nist_cp_bn(r_d, res, BN_NIST_192_TOP);
- bn_set_top(r, BN_NIST_192_TOP);
+ r->top = BN_NIST_192_TOP;
bn_correct_top(r);
return 1;
@@ -490,10 +495,10 @@ int BN_nist_mod_224(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
BN_ULONG c_d[BN_NIST_224_TOP], *res;
bn_addsub_f adjust;
static const BIGNUM ossl_bignum_nist_p_224_sqr = {
- .d = (BN_ULONG *)_nist_p_224_sqr,
- .top = OSSL_NELEM(_nist_p_224_sqr),
- .dmax = OSSL_NELEM(_nist_p_224_sqr),
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)_nist_p_224_sqr,
+ OSSL_NELEM(_nist_p_224_sqr),
+ OSSL_NELEM(_nist_p_224_sqr),
+ 0, BN_FLG_STATIC_DATA
};
field = &ossl_bignum_nist_p_224; /* just to make sure */
@@ -625,7 +630,7 @@ int BN_nist_mod_224(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
? r_d
: c_d;
nist_cp_bn(r_d, res, BN_NIST_224_TOP);
- bn_set_top(r, BN_NIST_224_TOP);
+ r->top = BN_NIST_224_TOP;
bn_correct_top(r);
return 1;
@@ -656,10 +661,10 @@ int BN_nist_mod_256(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
BN_ULONG c_d[BN_NIST_256_TOP], *res;
bn_addsub_f adjust;
static const BIGNUM ossl_bignum_nist_p_256_sqr = {
- .d = (BN_ULONG *)_nist_p_256_sqr,
- .top = OSSL_NELEM(_nist_p_256_sqr),
- .dmax = OSSL_NELEM(_nist_p_256_sqr),
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)_nist_p_256_sqr,
+ OSSL_NELEM(_nist_p_256_sqr),
+ OSSL_NELEM(_nist_p_256_sqr),
+ 0, BN_FLG_STATIC_DATA
};
field = &ossl_bignum_nist_p_256; /* just to make sure */
@@ -854,7 +859,7 @@ int BN_nist_mod_256(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
? r_d
: c_d;
nist_cp_bn(r_d, res, BN_NIST_256_TOP);
- bn_set_top(r, BN_NIST_256_TOP);
+ r->top = BN_NIST_256_TOP;
bn_correct_top(r);
return 1;
@@ -889,10 +894,10 @@ int BN_nist_mod_384(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
BN_ULONG c_d[BN_NIST_384_TOP], *res;
bn_addsub_f adjust;
static const BIGNUM ossl_bignum_nist_p_384_sqr = {
- .d = (BN_ULONG *)_nist_p_384_sqr,
- .top = OSSL_NELEM(_nist_p_384_sqr),
- .dmax = OSSL_NELEM(_nist_p_384_sqr),
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)_nist_p_384_sqr,
+ OSSL_NELEM(_nist_p_384_sqr),
+ OSSL_NELEM(_nist_p_384_sqr),
+ 0, BN_FLG_STATIC_DATA
};
field = &ossl_bignum_nist_p_384; /* just to make sure */
@@ -1121,7 +1126,7 @@ int BN_nist_mod_384(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
? r_d
: c_d;
nist_cp_bn(r_d, res, BN_NIST_384_TOP);
- bn_set_top(r, BN_NIST_384_TOP);
+ r->top = BN_NIST_384_TOP;
bn_correct_top(r);
return 1;
@@ -1137,10 +1142,10 @@ int BN_nist_mod_521(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
int top = a->top, i;
BN_ULONG *r_d, *a_d = a->d, t_d[BN_NIST_521_TOP], val, tmp, *res;
static const BIGNUM ossl_bignum_nist_p_521_sqr = {
- .d = (BN_ULONG *)_nist_p_521_sqr,
- .top = OSSL_NELEM(_nist_p_521_sqr),
- .dmax = OSSL_NELEM(_nist_p_521_sqr),
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)_nist_p_521_sqr,
+ OSSL_NELEM(_nist_p_521_sqr),
+ OSSL_NELEM(_nist_p_521_sqr),
+ 0, BN_FLG_STATIC_DATA
};
field = &ossl_bignum_nist_p_521; /* just to make sure */
@@ -1192,7 +1197,7 @@ int BN_nist_mod_521(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
? r_d
: t_d;
nist_cp_bn(r_d, res, BN_NIST_521_TOP);
- bn_set_top(r, BN_NIST_521_TOP);
+ r->top = BN_NIST_521_TOP;
bn_correct_top(r);
return 1;
diff --git a/crypto/bn/bn_prime.c b/crypto/bn/bn_prime.c
index d626956e3d..33a9fc8d67 100644
--- a/crypto/bn/bn_prime.c
+++ b/crypto/bn/bn_prime.c
@@ -55,10 +55,11 @@ static const BN_ULONG small_prime_factors[] = {
#define BN_SMALL_PRIME_FACTORS_TOP OSSL_NELEM(small_prime_factors)
static const BIGNUM _bignum_small_prime_factors = {
- .d = (BN_ULONG *)small_prime_factors,
- .top = BN_SMALL_PRIME_FACTORS_TOP,
- .dmax = BN_SMALL_PRIME_FACTORS_TOP,
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)small_prime_factors,
+ BN_SMALL_PRIME_FACTORS_TOP,
+ BN_SMALL_PRIME_FACTORS_TOP,
+ 0,
+ BN_FLG_STATIC_DATA
};
const BIGNUM *ossl_bn_get0_small_factors(void)
diff --git a/crypto/bn/bn_rsa_fips186_5.c b/crypto/bn/bn_rsa_fips186_5.c
index ee80bb3a5a..635f013f73 100644
--- a/crypto/bn/bn_rsa_fips186_5.c
+++ b/crypto/bn/bn_rsa_fips186_5.c
@@ -41,10 +41,11 @@ static const BN_ULONG inv_sqrt_2_val[] = {
};
const BIGNUM ossl_bn_inv_sqrt_2 = {
- .d = (BN_ULONG *)inv_sqrt_2_val,
- .top = OSSL_NELEM(inv_sqrt_2_val),
- .dmax = OSSL_NELEM(inv_sqrt_2_val),
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)inv_sqrt_2_val,
+ OSSL_NELEM(inv_sqrt_2_val),
+ OSSL_NELEM(inv_sqrt_2_val),
+ 0,
+ BN_FLG_STATIC_DATA
};
/*
diff --git a/crypto/bn/bn_s390x.c b/crypto/bn/bn_s390x.c
index ef96161ced..4e7aba35f6 100644
--- a/crypto/bn/bn_s390x.c
+++ b/crypto/bn/bn_s390x.c
@@ -20,16 +20,20 @@
#include
#include
+/*
+ * Returns 1 for success, 0 for failure, and -1 to tell the caller to use the
+ * SW-fallback.
+ */
static int s390x_mod_exp_hw(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
const BIGNUM *m)
{
struct ica_rsa_modexpo me;
unsigned char *buffer;
size_t size;
- int res = 0;
+ int res = -1;
if (OPENSSL_s390xcex == -1 || OPENSSL_s390xcex_nodev)
- return 0;
+ return -1;
size = BN_num_bytes(m);
buffer = OPENSSL_calloc(size, 4);
if (buffer == NULL)
@@ -42,11 +46,15 @@ static int s390x_mod_exp_hw(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
me.n_modulus = buffer + 3 * size;
if (BN_bn2binpad(a, me.inputdata, size) == -1
|| BN_bn2binpad(p, me.b_key, size) == -1
- || BN_bn2binpad(m, me.n_modulus, size) == -1)
+ || BN_bn2binpad(m, me.n_modulus, size) == -1) {
+ res = 0;
goto dealloc;
+ }
if (ioctl(OPENSSL_s390xcex, ICARSAMODEXPO, &me) != -1) {
if (BN_bin2bn(me.outputdata, size, r) != NULL)
res = 1;
+ else
+ res = 0;
} else if (errno == EBADF || errno == ENOTTY) {
/*
* In this cases, someone (e.g. a sandbox) closed the fd.
@@ -71,27 +79,34 @@ dealloc:
int s390x_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
{
- if (s390x_mod_exp_hw(r, a, p, m) == 1)
- return 1;
- return BN_mod_exp_mont(r, a, p, m, ctx, m_ctx);
+ int rc;
+
+ rc = s390x_mod_exp_hw(r, a, p, m);
+ if (rc < 0)
+ return BN_mod_exp_mont(r, a, p, m, ctx, m_ctx);
+ return rc;
}
+/*
+ * Returns 1 for success, 0 for failure, and -1 to tell the caller to use the
+ * SW-fallback.
+ */
int s390x_crt(BIGNUM *r, const BIGNUM *i, const BIGNUM *p, const BIGNUM *q,
const BIGNUM *dmp, const BIGNUM *dmq, const BIGNUM *iqmp)
{
struct ica_rsa_modexpo_crt crt;
unsigned char *buffer, *part;
size_t size, plen, qlen;
- int res = 0;
+ int res = -1;
if (OPENSSL_s390xcex == -1 || OPENSSL_s390xcex_nodev)
- return 0;
+ return -1;
/*-
* Hardware-accelerated CRT can only deal with p>q. Fall back to
* software in the (hopefully rare) other cases.
*/
if (BN_ucmp(p, q) != 1)
- return 0;
+ return -1;
plen = BN_num_bytes(p);
qlen = BN_num_bytes(q);
size = (plen > qlen ? plen : qlen);
@@ -119,11 +134,15 @@ int s390x_crt(BIGNUM *r, const BIGNUM *i, const BIGNUM *p, const BIGNUM *q,
|| BN_bn2binpad(q, crt.nq_prime, size) == -1
|| BN_bn2binpad(dmp, crt.bp_key, size + 8) == -1
|| BN_bn2binpad(dmq, crt.bq_key, size) == -1
- || BN_bn2binpad(iqmp, crt.u_mult_inv, size + 8) == -1)
+ || BN_bn2binpad(iqmp, crt.u_mult_inv, size + 8) == -1) {
+ res = 0;
goto dealloc;
+ }
if (ioctl(OPENSSL_s390xcex, ICARSACRT, &crt) != -1) {
if (BN_bin2bn(crt.outputdata, crt.outputdatalength, r) != NULL)
res = 1;
+ else
+ res = 0;
} else if (errno == EBADF || errno == ENOTTY) {
/*
* In this cases, someone (e.g. a sandbox) closed the fd.
diff --git a/crypto/bn/bn_shift.c b/crypto/bn/bn_shift.c
index 2e6f7c7401..1ba635096e 100644
--- a/crypto/bn/bn_shift.c
+++ b/crypto/bn/bn_shift.c
@@ -23,7 +23,7 @@ int BN_lshift1(BIGNUM *r, const BIGNUM *a)
r->neg = a->neg;
if (bn_wexpand(r, a->top + 1) == NULL)
return 0;
- bn_set_top(r, a->top);
+ r->top = a->top;
} else {
if (bn_wexpand(r, a->top + 1) == NULL)
return 0;
@@ -37,7 +37,7 @@ int BN_lshift1(BIGNUM *r, const BIGNUM *a)
c = t >> (BN_BITS2 - 1);
}
*rp = c;
- bn_set_top(r, r->top + (int)c);
+ r->top += (int)c;
bn_check_top(r);
return 1;
}
@@ -62,10 +62,11 @@ int BN_rshift1(BIGNUM *r, const BIGNUM *a)
r->neg = a->neg;
}
rp = r->d;
+ r->top = i;
t = ap[--i];
rp[i] = t >> 1;
c = t << (BN_BITS2 - 1);
- bn_set_top(r, i + (t > 1));
+ r->top -= (t == 1);
while (i > 0) {
t = ap[--i];
rp[i] = ((t >> 1) & BN_MASK2) | c;
@@ -140,7 +141,7 @@ int bn_lshift_fixed_top(BIGNUM *r, const BIGNUM *a, int n)
memset(r->d, 0, sizeof(*t) * nw);
r->neg = a->neg;
- bn_set_top(r, a->top + nw + 1);
+ r->top = a->top + nw + 1;
r->flags |= BN_FLG_FIXED_TOP;
return 1;
@@ -208,7 +209,7 @@ int bn_rshift_fixed_top(BIGNUM *r, const BIGNUM *a, int n)
t[i] = l >> rb;
r->neg = a->neg;
- bn_set_top(r, top);
+ r->top = top;
r->flags |= BN_FLG_FIXED_TOP;
return 1;
diff --git a/crypto/bn/bn_sqr.c b/crypto/bn/bn_sqr.c
index 1eb9e4c9ab..807577bae5 100644
--- a/crypto/bn/bn_sqr.c
+++ b/crypto/bn/bn_sqr.c
@@ -34,7 +34,7 @@ int bn_sqr_fixed_top(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx)
al = a->top;
if (al <= 0) {
- bn_set_top(r, 0);
+ r->top = 0;
r->neg = 0;
return 1;
}
@@ -91,12 +91,8 @@ int bn_sqr_fixed_top(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx)
#endif
}
- /* Ensure that tmp won't cause any trouble */
- tmp->top = tmp->dmax;
- tmp->flags |= BN_FLG_FIXED_TOP;
-
rr->neg = 0;
- bn_set_top(rr, max);
+ rr->top = max;
rr->flags |= BN_FLG_FIXED_TOP;
if (r != rr && BN_copy(r, rr) == NULL)
goto err;
@@ -104,6 +100,7 @@ int bn_sqr_fixed_top(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx)
ret = 1;
err:
bn_check_top(rr);
+ bn_check_top(tmp);
BN_CTX_end(ctx);
return ret;
}
diff --git a/crypto/bn/bn_srp.c b/crypto/bn/bn_srp.c
index 1e7b38b619..1cc30a56dd 100644
--- a/crypto/bn/bn_srp.c
+++ b/crypto/bn/bn_srp.c
@@ -49,10 +49,11 @@ static const BN_ULONG bn_group_1024_value[] = {
};
const BIGNUM ossl_bn_group_1024 = {
- .d = (BN_ULONG *)bn_group_1024_value,
- .top = OSSL_NELEM(bn_group_1024_value),
- .dmax = OSSL_NELEM(bn_group_1024_value),
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)bn_group_1024_value,
+ OSSL_NELEM(bn_group_1024_value),
+ OSSL_NELEM(bn_group_1024_value),
+ 0,
+ BN_FLG_STATIC_DATA
};
static const BN_ULONG bn_group_1536_value[] = {
@@ -83,10 +84,11 @@ static const BN_ULONG bn_group_1536_value[] = {
};
const BIGNUM ossl_bn_group_1536 = {
- .d = (BN_ULONG *)bn_group_1536_value,
- .top = OSSL_NELEM(bn_group_1536_value),
- .dmax = OSSL_NELEM(bn_group_1536_value),
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)bn_group_1536_value,
+ OSSL_NELEM(bn_group_1536_value),
+ OSSL_NELEM(bn_group_1536_value),
+ 0,
+ BN_FLG_STATIC_DATA
};
static const BN_ULONG bn_group_2048_value[] = {
@@ -125,10 +127,11 @@ static const BN_ULONG bn_group_2048_value[] = {
};
const BIGNUM ossl_bn_group_2048 = {
- .d = (BN_ULONG *)bn_group_2048_value,
- .top = OSSL_NELEM(bn_group_2048_value),
- .dmax = OSSL_NELEM(bn_group_2048_value),
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)bn_group_2048_value,
+ OSSL_NELEM(bn_group_2048_value),
+ OSSL_NELEM(bn_group_2048_value),
+ 0,
+ BN_FLG_STATIC_DATA
};
static const BN_ULONG bn_group_3072_value[] = {
@@ -183,10 +186,11 @@ static const BN_ULONG bn_group_3072_value[] = {
};
const BIGNUM ossl_bn_group_3072 = {
- .d = (BN_ULONG *)bn_group_3072_value,
- .top = OSSL_NELEM(bn_group_3072_value),
- .dmax = OSSL_NELEM(bn_group_3072_value),
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)bn_group_3072_value,
+ OSSL_NELEM(bn_group_3072_value),
+ OSSL_NELEM(bn_group_3072_value),
+ 0,
+ BN_FLG_STATIC_DATA
};
static const BN_ULONG bn_group_4096_value[] = {
@@ -257,10 +261,11 @@ static const BN_ULONG bn_group_4096_value[] = {
};
const BIGNUM ossl_bn_group_4096 = {
- .d = (BN_ULONG *)bn_group_4096_value,
- .top = OSSL_NELEM(bn_group_4096_value),
- .dmax = OSSL_NELEM(bn_group_4096_value),
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)bn_group_4096_value,
+ OSSL_NELEM(bn_group_4096_value),
+ OSSL_NELEM(bn_group_4096_value),
+ 0,
+ BN_FLG_STATIC_DATA
};
static const BN_ULONG bn_group_6144_value[] = {
@@ -363,10 +368,11 @@ static const BN_ULONG bn_group_6144_value[] = {
};
const BIGNUM ossl_bn_group_6144 = {
- .d = (BN_ULONG *)bn_group_6144_value,
- .top = OSSL_NELEM(bn_group_6144_value),
- .dmax = OSSL_NELEM(bn_group_6144_value),
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)bn_group_6144_value,
+ OSSL_NELEM(bn_group_6144_value),
+ OSSL_NELEM(bn_group_6144_value),
+ 0,
+ BN_FLG_STATIC_DATA
};
static const BN_ULONG bn_group_8192_value[] = {
@@ -501,35 +507,39 @@ static const BN_ULONG bn_group_8192_value[] = {
};
const BIGNUM ossl_bn_group_8192 = {
- .d = (BN_ULONG *)bn_group_8192_value,
- .top = OSSL_NELEM(bn_group_8192_value),
- .dmax = OSSL_NELEM(bn_group_8192_value),
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)bn_group_8192_value,
+ OSSL_NELEM(bn_group_8192_value),
+ OSSL_NELEM(bn_group_8192_value),
+ 0,
+ BN_FLG_STATIC_DATA
};
static const BN_ULONG bn_generator_19_value[] = { 19 };
const BIGNUM ossl_bn_generator_19 = {
- .d = (BN_ULONG *)bn_generator_19_value,
- .top = 1,
- .dmax = 1,
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)bn_generator_19_value,
+ 1,
+ 1,
+ 0,
+ BN_FLG_STATIC_DATA
};
static const BN_ULONG bn_generator_5_value[] = { 5 };
const BIGNUM ossl_bn_generator_5 = {
- .d = (BN_ULONG *)bn_generator_5_value,
- .top = 1,
- .dmax = 1,
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)bn_generator_5_value,
+ 1,
+ 1,
+ 0,
+ BN_FLG_STATIC_DATA
};
static const BN_ULONG bn_generator_2_value[] = { 2 };
const BIGNUM ossl_bn_generator_2 = {
- .d = (BN_ULONG *)bn_generator_2_value,
- .top = 1,
- .dmax = 1,
- .flags = BN_FLG_STATIC_DATA,
+ (BN_ULONG *)bn_generator_2_value,
+ 1,
+ 1,
+ 0,
+ BN_FLG_STATIC_DATA
};
#endif
diff --git a/crypto/bn/bnw_mul.c b/crypto/bn/bnw_mul.c
deleted file mode 100644
index d2f44d8608..0000000000
--- a/crypto/bn/bnw_mul.c
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * Copyright 1995-2025 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
- */
-
-#include
-#include "bn_local.h"
-
-#ifndef OPENSSL_SMALL_FOOTPRINT
-/*
- * Karatsuba recursive multiplication algorithm (cf. Knuth, The Art of
- * Computer Programming, Vol. 2)
- */
-
-/*-
- * r is 2*n2 words in size,
- * a and b are both n2 words in size.
- * n2 must be a power of 2.
- * We multiply and return the result.
- * t must be 2*n2 words in size
- * We calculate
- * a[0]*b[0]
- * a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0])
- * a[1]*b[1]
- */
-/* dnX may not be positive, but n2/2+dnX has to be */
-void bn_mul_recursive(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, int n2,
- int dna, int dnb, BN_ULONG *t)
-{
- int n = n2 / 2, c1, c2;
- int tna = n + dna, tnb = n + dnb;
- unsigned int neg, zero;
- BN_ULONG ln, lo, *p;
-
- /*
- * Only call bn_mul_comba 8 if n2 == 8 and the two arrays are complete
- * [steve]
- */
- if (n2 == 8 && dna == 0 && dnb == 0) {
- bn_mul_comba8(r, a, b);
- return;
- }
-
- /* Else do normal multiply */
- if (n2 < BN_MUL_RECURSIVE_SIZE_NORMAL) {
- bn_mul_normal(r, a, n2 + dna, b, n2 + dnb);
- if ((dna + dnb) < 0)
- memset(&r[2 * n2 + dna + dnb], 0,
- sizeof(BN_ULONG) * -(dna + dnb));
- return;
- }
- /* r=(a[0]-a[1])*(b[1]-b[0]) */
- c1 = bn_cmp_part_words(a, &(a[n]), tna, n - tna);
- c2 = bn_cmp_part_words(&(b[n]), b, tnb, tnb - n);
- zero = neg = 0;
- switch (c1 * 3 + c2) {
- case -4:
- bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
- bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
- break;
- case -3:
- zero = 1;
- break;
- case -2:
- bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
- bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); /* + */
- neg = 1;
- break;
- case -1:
- case 0:
- case 1:
- zero = 1;
- break;
- case 2:
- bn_sub_part_words(t, a, &(a[n]), tna, n - tna); /* + */
- bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
- neg = 1;
- break;
- case 3:
- zero = 1;
- break;
- case 4:
- bn_sub_part_words(t, a, &(a[n]), tna, n - tna);
- bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n);
- break;
- }
-
- if (n == 4 && dna == 0 && dnb == 0) { /* XXX: bn_mul_comba4 could take
- * extra args to do this well */
- if (!zero)
- bn_mul_comba4(&(t[n2]), t, &(t[n]));
- else
- memset(&t[n2], 0, sizeof(*t) * 8);
-
- bn_mul_comba4(r, a, b);
- bn_mul_comba4(&(r[n2]), &(a[n]), &(b[n]));
- } else if (n == 8 && dna == 0 && dnb == 0) { /* XXX: bn_mul_comba8 could
- * take extra args to do
- * this well */
- if (!zero)
- bn_mul_comba8(&(t[n2]), t, &(t[n]));
- else
- memset(&t[n2], 0, sizeof(*t) * 16);
-
- bn_mul_comba8(r, a, b);
- bn_mul_comba8(&(r[n2]), &(a[n]), &(b[n]));
- } else {
- p = &(t[n2 * 2]);
- if (!zero)
- bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p);
- else
- memset(&t[n2], 0, sizeof(*t) * n2);
- bn_mul_recursive(r, a, b, n, 0, 0, p);
- bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), n, dna, dnb, p);
- }
-
- /*-
- * t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign
- * r[10] holds (a[0]*b[0])
- * r[32] holds (b[1]*b[1])
- */
-
- c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));
-
- if (neg) { /* if t[32] is negative */
- c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
- } else {
- /* Might have a carry */
- c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), t, n2));
- }
-
- /*-
- * t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1])
- * r[10] holds (a[0]*b[0])
- * r[32] holds (b[1]*b[1])
- * c1 holds the carry bits
- */
- c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
- if (c1) {
- p = &(r[n + n2]);
- lo = *p;
- ln = (lo + c1) & BN_MASK2;
- *p = ln;
-
- /*
- * The overflow will stop before we over write words we should not
- * overwrite
- */
- if (ln < (BN_ULONG)c1) {
- do {
- p++;
- lo = *p;
- ln = (lo + 1) & BN_MASK2;
- *p = ln;
- } while (ln == 0);
- }
- }
-}
-
-/*
- * n+tn is the word length t needs to be n*4 is size, as does r
- */
-/* tnX may not be negative but less than n */
-void bn_mul_part_recursive(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
- int n, int tna, int tnb, BN_ULONG *t)
-{
- int i, j, n2 = n * 2;
- int c1, c2, neg;
- BN_ULONG ln, lo, *p;
-
- if (n < 8) {
- bn_mul_normal(r, a, n + tna, b, n + tnb);
- return;
- }
-
- /* r=(a[0]-a[1])*(b[1]-b[0]) */
- c1 = bn_cmp_part_words(a, &(a[n]), tna, n - tna);
- c2 = bn_cmp_part_words(&(b[n]), b, tnb, tnb - n);
- neg = 0;
- switch (c1 * 3 + c2) {
- case -4:
- bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
- bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
- break;
- case -3:
- case -2:
- bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
- bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); /* + */
- neg = 1;
- break;
- case -1:
- case 0:
- case 1:
- case 2:
- bn_sub_part_words(t, a, &(a[n]), tna, n - tna); /* + */
- bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
- neg = 1;
- break;
- case 3:
- case 4:
- bn_sub_part_words(t, a, &(a[n]), tna, n - tna);
- bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n);
- break;
- }
- /*
- * The zero case isn't yet implemented here. The speedup would probably
- * be negligible.
- */
-#if 0
- if (n == 4) {
- bn_mul_comba4(&(t[n2]), t, &(t[n]));
- bn_mul_comba4(r, a, b);
- bn_mul_normal(&(r[n2]), &(a[n]), tn, &(b[n]), tn);
- memset(&r[n2 + tn * 2], 0, sizeof(*r) * (n2 - tn * 2));
- } else
-#endif
- if (n == 8) {
- bn_mul_comba8(&(t[n2]), t, &(t[n]));
- bn_mul_comba8(r, a, b);
- bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb);
- memset(&r[n2 + tna + tnb], 0, sizeof(*r) * (n2 - tna - tnb));
- } else {
- p = &(t[n2 * 2]);
- bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p);
- bn_mul_recursive(r, a, b, n, 0, 0, p);
- i = n / 2;
- /*
- * If there is only a bottom half to the number, just do it
- */
- if (tna > tnb)
- j = tna - i;
- else
- j = tnb - i;
- if (j == 0) {
- bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]),
- i, tna - i, tnb - i, p);
- memset(&r[n2 + i * 2], 0, sizeof(*r) * (n2 - i * 2));
- } else if (j > 0) { /* eg, n == 16, i == 8 and tn == 11 */
- bn_mul_part_recursive(&(r[n2]), &(a[n]), &(b[n]),
- i, tna - i, tnb - i, p);
- memset(&(r[n2 + tna + tnb]), 0,
- sizeof(BN_ULONG) * (n2 - tna - tnb));
- } else { /* (j < 0) eg, n == 16, i == 8 and tn == 5 */
-
- memset(&r[n2], 0, sizeof(*r) * n2);
- if (tna < BN_MUL_RECURSIVE_SIZE_NORMAL
- && tnb < BN_MUL_RECURSIVE_SIZE_NORMAL) {
- bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb);
- } else {
- for (;;) {
- i /= 2;
- /*
- * these simplified conditions work exclusively because
- * difference between tna and tnb is 1 or 0
- */
- if (i < tna || i < tnb) {
- bn_mul_part_recursive(&(r[n2]),
- &(a[n]), &(b[n]),
- i, tna - i, tnb - i, p);
- break;
- } else if (i == tna || i == tnb) {
- bn_mul_recursive(&(r[n2]),
- &(a[n]), &(b[n]),
- i, tna - i, tnb - i, p);
- break;
- }
- }
- }
- }
- }
-
- /*-
- * t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign
- * r[10] holds (a[0]*b[0])
- * r[32] holds (b[1]*b[1])
- */
-
- c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));
-
- if (neg) { /* if t[32] is negative */
- c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
- } else {
- /* Might have a carry */
- c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), t, n2));
- }
-
- /*-
- * t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1])
- * r[10] holds (a[0]*b[0])
- * r[32] holds (b[1]*b[1])
- * c1 holds the carry bits
- */
- c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
- if (c1) {
- p = &(r[n + n2]);
- lo = *p;
- ln = (lo + c1) & BN_MASK2;
- *p = ln;
-
- /*
- * The overflow will stop before we over write words we should not
- * overwrite
- */
- if (ln < (BN_ULONG)c1) {
- do {
- p++;
- lo = *p;
- ln = (lo + 1) & BN_MASK2;
- *p = ln;
- } while (ln == 0);
- }
- }
-}
-
-/*-
- * a and b must be the same size, which is n2.
- * r needs to be n2 words and t needs to be n2*2
- */
-void bn_mul_low_recursive(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
- int n2, BN_ULONG *t)
-{
- int n = n2 / 2;
-
- bn_mul_recursive(r, a, b, n, 0, 0, &(t[0]));
- if (n >= BN_MUL_LOW_RECURSIVE_SIZE_NORMAL) {
- bn_mul_low_recursive(&(t[0]), &(a[0]), &(b[n]), n, &(t[n2]));
- bn_add_words(&(r[n]), &(r[n]), &(t[0]), n);
- bn_mul_low_recursive(&(t[0]), &(a[n]), &(b[0]), n, &(t[n2]));
- bn_add_words(&(r[n]), &(r[n]), &(t[0]), n);
- } else {
- bn_mul_low_normal(&(t[0]), &(a[0]), &(b[n]), n);
- bn_mul_low_normal(&(t[n]), &(a[n]), &(b[0]), n);
- bn_add_words(&(r[n]), &(r[n]), &(t[0]), n);
- bn_add_words(&(r[n]), &(r[n]), &(t[n]), n);
- }
-}
-#endif /* OPENSSL_SMALL_FOOTPRINT */
-
-/*
- * This function doesn't zero out the rest of r in case of nr>na+nb;
- * it's the calling function's responsibility to do so.
- */
-void bn_mul_truncated(BN_ULONG *r, int nr, const BN_ULONG *a, int na,
- const BN_ULONG *b, int nb)
-{
- BN_ULONG tmp, *carryp = NULL;
- int n; /* Number of words to use in the current iteration */
-
- if (na < nb) {
- int itmp;
- const BN_ULONG *ltmp;
-
- itmp = na;
- na = nb;
- nb = itmp;
- ltmp = a;
- a = b;
- b = ltmp;
- }
- n = (na < nr) ? na : nr;
- if (nb <= 0) {
- (void)bn_mul_words(r, a, n, 0);
- return;
- } else {
- carryp = (na < nr) ? &r[na] : &tmp;
- *carryp = bn_mul_words(r, a, n, b[0]);
- }
-
- for (int i = 1; i < nb && i < nr; i++) {
- int rspace = nr - i;
- n = (na < rspace) ? na : rspace;
- carryp = (na < rspace) ? &r[i + na] : &tmp;
- *carryp = bn_mul_add_words(&(r[i]), a, n, b[i]);
- }
-}
-
-void bn_mul_normal(BN_ULONG *r, const BN_ULONG *a, int na, const BN_ULONG *b,
- int nb)
-{
- bn_mul_truncated(r, na + nb, a, na, b, nb);
-}
-
-void bn_mul_low_normal(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, int n)
-{
- bn_mul_words(r, a, n, b[0]);
-
- for (;;) {
- if (--n <= 0)
- return;
- bn_mul_add_words(&(r[1]), a, n, b[1]);
- if (--n <= 0)
- return;
- bn_mul_add_words(&(r[2]), a, n, b[2]);
- if (--n <= 0)
- return;
- bn_mul_add_words(&(r[3]), a, n, b[3]);
- if (--n <= 0)
- return;
- bn_mul_add_words(&(r[4]), a, n, b[4]);
- r += 4;
- b += 4;
- }
-}
diff --git a/crypto/bn/bnw_sub.c b/crypto/bn/bnw_sub.c
deleted file mode 100644
index f989878ce0..0000000000
--- a/crypto/bn/bnw_sub.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright 1995-2025 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
- */
-
-#include
-#include "bn_local.h"
-
-#if defined(OPENSSL_NO_ASM) || !defined(OPENSSL_BN_ASM_PART_WORDS)
-/*
- * Here follows specialised variants of bn_add_words() and bn_sub_words().
- * They have the property performing operations on arrays of different sizes.
- * The sizes of those arrays is expressed through cl, which is the common
- * length ( basically, min(len(a),len(b)) ), and dl, which is the delta
- * between the two lengths, calculated as len(a)-len(b). All lengths are the
- * number of BN_ULONGs... For the operations that require a result array as
- * parameter, it must have the length cl+abs(dl).
- *
- * These functions should probably end up in bn_asm.c as soon as there are
- * assembler counterparts for the systems that use assembler files.
- */
-
-BN_ULONG bn_sub_part_words(BN_ULONG *r,
- const BN_ULONG *a, const BN_ULONG *b,
- int cl, int dl)
-{
- BN_ULONG c, t;
-
- assert(cl >= 0);
- c = bn_sub_words(r, a, b, cl);
-
- if (dl == 0)
- return c;
-
- r += cl;
- a += cl;
- b += cl;
-
- if (dl < 0) {
- for (;;) {
- t = b[0];
- r[0] = (0 - t - c) & BN_MASK2;
- if (t != 0)
- c = 1;
- if (++dl >= 0)
- break;
-
- t = b[1];
- r[1] = (0 - t - c) & BN_MASK2;
- if (t != 0)
- c = 1;
- if (++dl >= 0)
- break;
-
- t = b[2];
- r[2] = (0 - t - c) & BN_MASK2;
- if (t != 0)
- c = 1;
- if (++dl >= 0)
- break;
-
- t = b[3];
- r[3] = (0 - t - c) & BN_MASK2;
- if (t != 0)
- c = 1;
- if (++dl >= 0)
- break;
-
- b += 4;
- r += 4;
- }
- } else {
- int save_dl = dl;
- while (c) {
- t = a[0];
- r[0] = (t - c) & BN_MASK2;
- if (t != 0)
- c = 0;
- if (--dl <= 0)
- break;
-
- t = a[1];
- r[1] = (t - c) & BN_MASK2;
- if (t != 0)
- c = 0;
- if (--dl <= 0)
- break;
-
- t = a[2];
- r[2] = (t - c) & BN_MASK2;
- if (t != 0)
- c = 0;
- if (--dl <= 0)
- break;
-
- t = a[3];
- r[3] = (t - c) & BN_MASK2;
- if (t != 0)
- c = 0;
- if (--dl <= 0)
- break;
-
- save_dl = dl;
- a += 4;
- r += 4;
- }
- if (dl > 0) {
- if (save_dl > dl) {
- switch (save_dl - dl) {
- case 1:
- r[1] = a[1];
- if (--dl <= 0)
- break;
- /* fall through */
- case 2:
- r[2] = a[2];
- if (--dl <= 0)
- break;
- /* fall through */
- case 3:
- r[3] = a[3];
- if (--dl <= 0)
- break;
- }
- a += 4;
- r += 4;
- }
- }
- if (dl > 0) {
- for (;;) {
- r[0] = a[0];
- if (--dl <= 0)
- break;
- r[1] = a[1];
- if (--dl <= 0)
- break;
- r[2] = a[2];
- if (--dl <= 0)
- break;
- r[3] = a[3];
- if (--dl <= 0)
- break;
-
- a += 4;
- r += 4;
- }
- }
- }
- return c;
-}
-#endif
diff --git a/crypto/bn/build.info b/crypto/bn/build.info
index 10680e1100..01e98e4544 100644
--- a/crypto/bn/build.info
+++ b/crypto/bn/build.info
@@ -105,18 +105,11 @@ IF[{- !$disabled{asm} -}]
ENDIF
ENDIF
-$COMMON_BN=bn_add.c bn_div.c bn_exp.c bn_lib.c bn_ctx.c bn_mul.c \
+$COMMON=bn_add.c bn_div.c bn_exp.c bn_lib.c bn_ctx.c bn_mul.c \
bn_mod.c bn_conv.c bn_rand.c bn_shift.c bn_word.c bn_blind.c \
bn_kron.c bn_sqrt.c bn_gcd.c bn_prime.c bn_sqr.c \
bn_recp.c bn_mont.c bn_mpi.c bn_exp2.c bn_gf2m.c bn_nist.c \
bn_intern.c bn_dh.c bn_rsa_fips186_5.c bn_const.c
-# bnw_*.c is a growing collection of files with routines that operate on
-# BN_ULONG only. They were helper routines dispersed in bn_*.c, and are
-# often routines that don't have an assembler implementation, and therefore
-# didn't fit into bn_asm.c.
-$COMMON_BNW=bnw_sub.c bnw_mul.c
-$COMMON=$COMMON_BN $COMMON_BNW
-
SOURCE[../../libcrypto]=$COMMON $BNASM bn_print.c bn_err.c bn_srp.c
DEFINE[../../libcrypto]=$BNDEF
IF[{- !$disabled{'deprecated-0.9.8'} -}]
diff --git a/crypto/build.info b/crypto/build.info
index 68ecd2db27..4e9068407c 100644
--- a/crypto/build.info
+++ b/crypto/build.info
@@ -4,7 +4,7 @@ SUBDIRS=objects buffer bio stack lhash hashtable rand evp asn1 pem x509 conf \
txt_db pkcs7 pkcs12 ui kdf store property \
md2 md4 md5 sha mdc2 ml_kem hmac ripemd whrlpool poly1305 \
siphash sm3 des aes rc2 rc4 rc5 idea aria bf cast camellia \
- seed sm4 chacha modes fn bn ec rsa dsa dh sm2 dso \
+ seed sm4 chacha modes bn ec rsa dsa dh sm2 dso \
err comp http ocsp cms ts srp cmac ct async ess crmf cmp encode_decode \
ffc hpke thread lms ml_dsa slh_dsa
@@ -16,7 +16,6 @@ IF[{- !$disabled{uplink} -}]
$UPLINKSRC_common=../ms/uplink.c
$UPLINKSRC_x86=$UPLINKSRC_common uplink-x86.S
$UPLINKSRC_x86_64=$UPLINKSRC_common uplink-x86_64.s
- $UPLINKSRC_ia64=$UPLINKSRC_common uplink-ia64.s
IF[$UPLINKSRC_{- $target{uplink_arch} -}]
$UPLINKSRC=$UPLINKSRC_{- $target{uplink_arch} -}
@@ -99,8 +98,7 @@ $UTIL_COMMON=\
threads_pthread.c threads_win.c threads_none.c threads_common.c \
initthread.c context.c sparse_array.c asn1_dsa.c packet.c \
param_build.c param_build_set.c der_writer.c threads_lib.c \
- params_dup.c time.c array_alloc.c aligned_alloc.c deterministic_nonce.c \
- int.c
+ params_dup.c time.c array_alloc.c aligned_alloc.c deterministic_nonce.c
SOURCE[../libcrypto]=$UTIL_COMMON \
mem.c mem_sec.c \
@@ -119,7 +117,6 @@ GENERATE[buildinf.h]=../util/mkbuildinf.pl "$(CC) $(LIB_CFLAGS) $(CPPFLAGS_Q)" "
GENERATE[uplink-x86.S]=../ms/uplink-x86.pl
GENERATE[uplink-x86_64.s]=../ms/uplink-x86_64.pl
-GENERATE[uplink-ia64.s]=../ms/uplink-ia64.pl
GENERATE[x86cpuid.S]=x86cpuid.pl
DEPEND[x86cpuid.s]=perlasm/x86asm.pl
diff --git a/crypto/chacha/chacha_enc.c b/crypto/chacha/chacha_enc.c
index e9a4d3263a..c7c36b9c54 100644
--- a/crypto/chacha/chacha_enc.c
+++ b/crypto/chacha/chacha_enc.c
@@ -24,7 +24,7 @@ typedef union {
#define ROTATE(v, n) (((v) << (n)) | ((v) >> (32 - (n))))
#ifndef PEDANTIC
-#if defined(__GNUC__) && __GNUC__ >= 2 && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
+#if defined(__GNUC__) && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
#if defined(__riscv_zbb) || defined(__riscv_zbkb)
#if __riscv_xlen == 64
#undef ROTATE
diff --git a/crypto/cmp/cmp_local.h b/crypto/cmp/cmp_local.h
index e664a6ae22..ac892f62bd 100644
--- a/crypto/cmp/cmp_local.h
+++ b/crypto/cmp/cmp_local.h
@@ -819,7 +819,7 @@ int ossl_cmp_X509_STORE_add1_certs(X509_STORE *store, STACK_OF(X509) *certs,
int only_self_issued);
STACK_OF(X509) *ossl_cmp_X509_STORE_get1_certs(X509_STORE *store);
int ossl_cmp_sk_ASN1_UTF8STRING_push_str(STACK_OF(ASN1_UTF8STRING) *sk,
- const char *text, int len);
+ const char *text, size_t len);
int ossl_cmp_asn1_octet_string_set1(ASN1_OCTET_STRING **tgt,
const ASN1_OCTET_STRING *src);
int ossl_cmp_asn1_octet_string_set1_bytes(ASN1_OCTET_STRING **tgt,
diff --git a/crypto/cmp/cmp_msg.c b/crypto/cmp/cmp_msg.c
index fec747458d..abea670ce9 100644
--- a/crypto/cmp/cmp_msg.c
+++ b/crypto/cmp/cmp_msg.c
@@ -824,13 +824,13 @@ OSSL_CMP_MSG *ossl_cmp_error_new(OSSL_CMP_CTX *ctx, const OSSL_CMP_PKISI *si,
goto err;
msg->body->value.error->errorDetails = ft;
if (lib != NULL && *lib != '\0'
- && !ossl_cmp_sk_ASN1_UTF8STRING_push_str(ft, lib, -1))
+ && !ossl_cmp_sk_ASN1_UTF8STRING_push_str(ft, lib, strlen(lib)))
goto err;
if (reason != NULL && *reason != '\0'
- && !ossl_cmp_sk_ASN1_UTF8STRING_push_str(ft, reason, -1))
+ && !ossl_cmp_sk_ASN1_UTF8STRING_push_str(ft, reason, strlen(reason)))
goto err;
if (details != NULL
- && !ossl_cmp_sk_ASN1_UTF8STRING_push_str(ft, details, -1))
+ && !ossl_cmp_sk_ASN1_UTF8STRING_push_str(ft, details, strlen(details)))
goto err;
}
diff --git a/crypto/cmp/cmp_protect.c b/crypto/cmp/cmp_protect.c
index b0f52e9f36..c0dba8392d 100644
--- a/crypto/cmp/cmp_protect.c
+++ b/crypto/cmp/cmp_protect.c
@@ -73,7 +73,11 @@ ASN1_BIT_STRING *ossl_cmp_calc_protection(const OSSL_CMP_CTX *ctx,
pbm_str = (ASN1_STRING *)ppval;
pbm_str_uc = ASN1_STRING_get0_data(pbm_str);
- pbm = d2i_OSSL_CRMF_PBMPARAMETER(NULL, &pbm_str_uc, ASN1_STRING_length(pbm_str));
+ if (ASN1_STRING_length_ex(pbm_str) > INT_MAX) {
+ ERR_raise(ERR_LIB_CMP, CMP_R_WRONG_ALGORITHM_OID);
+ goto end;
+ }
+ pbm = d2i_OSSL_CRMF_PBMPARAMETER(NULL, &pbm_str_uc, (long)ASN1_STRING_length_ex(pbm_str));
if (pbm == NULL) {
ERR_raise(ERR_LIB_CMP, CMP_R_WRONG_ALGORITHM_OID);
goto end;
@@ -81,7 +85,7 @@ ASN1_BIT_STRING *ossl_cmp_calc_protection(const OSSL_CMP_CTX *ctx,
if (!OSSL_CRMF_pbm_new(ctx->libctx, ctx->propq,
pbm, prot_part_der, prot_part_der_len,
- ASN1_STRING_get0_data(ctx->secretValue), ASN1_STRING_length(ctx->secretValue),
+ ASN1_STRING_get0_data(ctx->secretValue), ASN1_STRING_length_ex(ctx->secretValue),
&protection, &sig_len))
goto end;
@@ -202,7 +206,7 @@ static X509_ALGOR *pbmac_algor(const OSSL_CMP_CTX *ctx)
goto err;
if ((pbm_der_len = i2d_OSSL_CRMF_PBMPARAMETER(pbm, &pbm_der)) < 0)
goto err;
- if (!ASN1_STRING_set(pbm_str, pbm_der, pbm_der_len))
+ if (!ASN1_STRING_set_data(pbm_str, pbm_der, pbm_der_len))
goto err;
alg = ossl_X509_ALGOR_from_nid(NID_id_PasswordBasedMAC,
V_ASN1_SEQUENCE, pbm_str);
diff --git a/crypto/cmp/cmp_status.c b/crypto/cmp/cmp_status.c
index 40e1ee671e..063bbe808c 100644
--- a/crypto/cmp/cmp_status.c
+++ b/crypto/cmp/cmp_status.c
@@ -214,7 +214,7 @@ static char *snprint_PKIStatusInfo_parts(int status, int fail_info,
for (i = 0; i < n_status_strings; i++) {
text = sk_ASN1_UTF8STRING_value(status_strings, i);
printed_chars = BIO_snprintf(write_ptr, bufsize, "\"%.*s\"%s",
- ASN1_STRING_length(text),
+ (int)ASN1_STRING_length_ex(text),
ASN1_STRING_get0_data(text),
i < n_status_strings - 1 ? ", " : "");
ADVANCE_BUFFER;
@@ -275,7 +275,7 @@ OSSL_CMP_PKISI *OSSL_CMP_STATUSINFO_new(int status, int fail_info,
if (text != NULL) {
if ((utf8_text = ASN1_UTF8STRING_new()) == NULL
- || !ASN1_STRING_set(utf8_text, text, -1))
+ || !ASN1_STRING_set_string(utf8_text, text))
goto err;
if ((si->statusString = sk_ASN1_UTF8STRING_new_null()) == NULL)
goto err;
diff --git a/crypto/cmp/cmp_util.c b/crypto/cmp/cmp_util.c
index 5c710addf2..f3a0c86d53 100644
--- a/crypto/cmp/cmp_util.c
+++ b/crypto/cmp/cmp_util.c
@@ -219,7 +219,7 @@ int ossl_cmp_X509_STORE_add1_certs(X509_STORE *store, STACK_OF(X509) *certs,
}
int ossl_cmp_sk_ASN1_UTF8STRING_push_str(STACK_OF(ASN1_UTF8STRING) *sk,
- const char *text, int len)
+ const char *text, size_t len)
{
ASN1_UTF8STRING *utf8string;
@@ -227,7 +227,7 @@ int ossl_cmp_sk_ASN1_UTF8STRING_push_str(STACK_OF(ASN1_UTF8STRING) *sk,
return 0;
if ((utf8string = ASN1_UTF8STRING_new()) == NULL)
return 0;
- if (!ASN1_STRING_set(utf8string, text, len))
+ if (!ASN1_STRING_set_data(utf8string, (const uint8_t *)text, len))
goto err;
if (!sk_ASN1_UTF8STRING_push(sk, utf8string))
goto err;
diff --git a/crypto/cms/cms_asn1.c b/crypto/cms/cms_asn1.c
index 63a26de742..96b125e930 100644
--- a/crypto/cms/cms_asn1.c
+++ b/crypto/cms/cms_asn1.c
@@ -306,9 +306,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) = {
diff --git a/crypto/cms/cms_dd.c b/crypto/cms/cms_dd.c
index 2e1dd78f5e..e307460e44 100644
--- a/crypto/cms/cms_dd.c
+++ b/crypto/cms/cms_dd.c
@@ -92,7 +92,7 @@ int ossl_cms_DigestedData_do_final(const CMS_ContentInfo *cms, BIO *chain,
else
r = 1;
} else {
- if (!ASN1_STRING_set(dd->digest, md, mdlen))
+ if (!ASN1_STRING_set_data(dd->digest, md, mdlen))
goto err;
r = 1;
}
diff --git a/crypto/cms/cms_dh.c b/crypto/cms/cms_dh.c
index a3ae620dea..03cef7455a 100644
--- a/crypto/cms/cms_dh.c
+++ b/crypto/cms/cms_dh.c
@@ -29,7 +29,7 @@ static int dh_cms_set_peerkey(EVP_PKEY_CTX *pctx,
BIGNUM *bnpub = NULL;
const unsigned char *p;
unsigned char *buf = NULL;
- int plen;
+ size_t plen;
X509_ALGOR_get0(&aoid, &atype, &aval, alg);
if (OBJ_obj2nid(aoid) != NID_dhpublicnumber)
@@ -43,29 +43,33 @@ static int dh_cms_set_peerkey(EVP_PKEY_CTX *pctx,
goto err;
/* Get public key */
- plen = ASN1_STRING_length(pubkey);
+ plen = ASN1_STRING_length_ex(pubkey);
+ if (plen > INT_MAX)
+ goto err;
p = ASN1_STRING_get0_data(pubkey);
if (p == NULL || plen == 0)
goto err;
- if ((public_key = d2i_ASN1_INTEGER(NULL, &p, plen)) == NULL)
+ if ((public_key = d2i_ASN1_INTEGER(NULL, &p, (int)plen)) == NULL)
goto err;
/*
* Pad to full p parameter size as that is checked by
* EVP_PKEY_set1_encoded_public_key()
*/
plen = EVP_PKEY_get_size(pk);
+ if (plen > INT_MAX)
+ goto err;
if ((bnpub = ASN1_INTEGER_to_BN(public_key, NULL)) == NULL)
goto err;
if ((buf = OPENSSL_malloc(plen)) == NULL)
goto err;
- if (BN_bn2binpad(bnpub, buf, plen) < 0)
+ if (BN_bn2binpad(bnpub, buf, (int)plen) < 0)
goto err;
pkpeer = EVP_PKEY_new();
if (pkpeer == NULL
|| !EVP_PKEY_copy_parameters(pkpeer, pk)
- || EVP_PKEY_set1_encoded_public_key(pkpeer, buf, plen) <= 0)
+ || EVP_PKEY_set1_encoded_public_key(pkpeer, buf, (int)plen) <= 0)
goto err;
if (EVP_PKEY_derive_set_peer(pctx, pkpeer) > 0)
@@ -85,8 +89,9 @@ static int dh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri)
ASN1_OCTET_STRING *ukm;
const unsigned char *p;
unsigned char *dukm = NULL;
- int dukmlen = 0;
- int keylen, plen;
+ size_t dukmlen = 0;
+ int keylen;
+ size_t plen;
EVP_CIPHER *kekcipher = NULL;
EVP_CIPHER_CTX *kekctx;
const ASN1_OBJECT *aoid;
@@ -116,8 +121,10 @@ static int dh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri)
goto err;
p = ASN1_STRING_get0_data(parameter);
- plen = ASN1_STRING_length(parameter);
- kekalg = d2i_X509_ALGOR(NULL, &p, plen);
+ plen = ASN1_STRING_length_ex(parameter);
+ if (plen > INT_MAX)
+ goto err;
+ kekalg = d2i_X509_ALGOR(NULL, &p, (int)plen);
if (kekalg == NULL)
goto err;
kekctx = CMS_RecipientInfo_kari_get0_ctx(ri);
@@ -146,13 +153,15 @@ static int dh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri)
goto err;
if (ukm != NULL) {
- dukmlen = ASN1_STRING_length(ukm);
- dukm = OPENSSL_memdup(ASN1_STRING_get0_data(ukm), dukmlen);
+ dukmlen = ASN1_STRING_length_ex(ukm);
+ if (dukmlen > INT_MAX)
+ goto err;
+ dukm = OPENSSL_memdup(ASN1_STRING_get0_data(ukm), (int)dukmlen);
if (dukm == NULL)
goto err;
}
- if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, dukmlen) <= 0)
+ if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, (int)dukmlen) <= 0)
goto err;
dukm = NULL;
@@ -206,7 +215,7 @@ static int dh_cms_encrypt(CMS_RecipientInfo *ri)
ASN1_OCTET_STRING *ukm;
unsigned char *penc = NULL, *dukm = NULL;
int penclen;
- int dukmlen = 0;
+ size_t dukmlen = 0;
int rv = 0;
int kdf_type, wrap_nid;
const EVP_MD *kdf_md;
@@ -298,13 +307,15 @@ static int dh_cms_encrypt(CMS_RecipientInfo *ri)
goto err;
if (ukm != NULL) {
- dukmlen = ASN1_STRING_length(ukm);
+ dukmlen = ASN1_STRING_length_ex(ukm);
+ if (dukmlen > INT_MAX)
+ goto err;
dukm = OPENSSL_memdup(ASN1_STRING_get0_data(ukm), dukmlen);
if (dukm == NULL)
goto err;
}
- if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, dukmlen) <= 0)
+ if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, (int)dukmlen) <= 0)
goto err;
dukm = NULL;
diff --git a/crypto/cms/cms_ec.c b/crypto/cms/cms_ec.c
index 8a8fe3f912..98ab266779 100644
--- a/crypto/cms/cms_ec.c
+++ b/crypto/cms/cms_ec.c
@@ -79,7 +79,7 @@ static int ecdh_cms_set_peerkey(EVP_PKEY_CTX *pctx,
int rv = 0;
EVP_PKEY *pkpeer = NULL;
const unsigned char *p;
- int plen;
+ size_t plen;
X509_ALGOR_get0(&aoid, &atype, &aval, alg);
if (OBJ_obj2nid(aoid) != NID_X9_62_id_ecPublicKey)
@@ -106,12 +106,14 @@ static int ecdh_cms_set_peerkey(EVP_PKEY_CTX *pctx,
goto err;
}
/* We have parameters now set public key */
- plen = ASN1_STRING_length(pubkey);
+ plen = ASN1_STRING_length_ex(pubkey);
+ if (plen > INT_MAX)
+ goto err;
p = ASN1_STRING_get0_data(pubkey);
if (p == NULL || plen == 0)
goto err;
- if (EVP_PKEY_set1_encoded_public_key(pkpeer, p, plen) <= 0)
+ if (EVP_PKEY_set1_encoded_public_key(pkpeer, p, (int)plen) <= 0)
goto err;
if (EVP_PKEY_derive_set_peer(pctx, pkpeer) > 0)
@@ -163,7 +165,8 @@ static int ecdh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri)
ASN1_OCTET_STRING *ukm;
const unsigned char *p;
unsigned char *der = NULL;
- int plen, keylen;
+ int keylen, plen_i;
+ size_t plen;
EVP_CIPHER *kekcipher = NULL;
EVP_CIPHER_CTX *kekctx;
const ASN1_OBJECT *aoid = NULL;
@@ -186,8 +189,10 @@ static int ecdh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri)
return 0;
p = ASN1_STRING_get0_data(parameter);
- plen = ASN1_STRING_length(parameter);
- kekalg = d2i_X509_ALGOR(NULL, &p, plen);
+ plen = ASN1_STRING_length_ex(parameter);
+ if (plen > INT_MAX)
+ goto err;
+ kekalg = d2i_X509_ALGOR(NULL, &p, (int)plen);
if (kekalg == NULL)
goto err;
kekctx = CMS_RecipientInfo_kari_get0_ctx(ri);
@@ -206,12 +211,12 @@ static int ecdh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri)
if (EVP_PKEY_CTX_set_ecdh_kdf_outlen(pctx, keylen) <= 0)
goto err;
- plen = CMS_SharedInfo_encode(&der, kekalg, ukm, keylen);
+ plen_i = CMS_SharedInfo_encode(&der, kekalg, ukm, keylen);
- if (plen <= 0)
+ if (plen_i <= 0)
goto err;
- if (EVP_PKEY_CTX_set0_ecdh_kdf_ukm(pctx, der, plen) <= 0)
+ if (EVP_PKEY_CTX_set0_ecdh_kdf_ukm(pctx, der, plen_i) <= 0)
goto err;
der = NULL;
diff --git a/crypto/cms/cms_env.c b/crypto/cms/cms_env.c
index e702703758..c29e2019ee 100644
--- a/crypto/cms/cms_env.c
+++ b/crypto/cms/cms_env.c
@@ -278,12 +278,17 @@ BIO *CMS_EnvelopedData_decrypt(CMS_EnvelopedData *env, BIO *detached_data,
CMS_ContentInfo *ci;
BIO *bio = NULL;
int res = 0;
+ size_t secret_len = 0;
if (env == NULL) {
ERR_raise(ERR_LIB_CMS, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
+ if (secret != NULL
+ && (secret_len = ASN1_STRING_length_ex(secret)) > INT_MAX)
+ return NULL;
+
if ((ci = CMS_ContentInfo_new_ex(libctx, propq)) == NULL
|| (bio = BIO_new(BIO_s_mem())) == NULL)
goto end;
@@ -291,7 +296,7 @@ BIO *CMS_EnvelopedData_decrypt(CMS_EnvelopedData *env, BIO *detached_data,
ci->d.envelopedData = env;
if (secret != NULL
&& CMS_decrypt_set1_password(ci, (unsigned char *)ASN1_STRING_get0_data(secret),
- ASN1_STRING_length(secret))
+ (int)secret_len)
!= 1)
goto end;
res = CMS_decrypt(ci, secret == NULL ? pkey : NULL,
@@ -1236,6 +1241,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;
@@ -1252,9 +1286,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;
- /* If error or no cipher end of processing */
- if (ret == NULL || ec->cipher == NULL)
+ /* authAttrs, if present, are the AEAD associated data */
+ if (aenv->authAttrs != NULL
+ && !cms_AuthEnvelopedData_set_aad(ret, aenv->authAttrs))
+ goto err;
+
+ /* If no cipher end of processing */
+ if (ec->cipher == NULL)
return ret;
/* Now encrypt content key according to each RecipientInfo type */
diff --git a/crypto/cms/cms_ess.c b/crypto/cms/cms_ess.c
index cafb827394..bfe0ccbf3d 100644
--- a/crypto/cms/cms_ess.c
+++ b/crypto/cms/cms_ess.c
@@ -131,7 +131,7 @@ CMS_ReceiptRequest *CMS_ReceiptRequest_create0_ex(
if (id)
ASN1_STRING_set0(rr->signedContentIdentifier, id, idlen);
else {
- if (!ASN1_STRING_set(rr->signedContentIdentifier, NULL, 32)) {
+ if (!ASN1_STRING_set_data(rr->signedContentIdentifier, NULL, 32)) {
ERR_raise(ERR_LIB_CMS, ERR_R_ASN1_LIB);
goto err;
}
diff --git a/crypto/cms/cms_kemri.c b/crypto/cms/cms_kemri.c
index 1d867c0db1..3284ebc23a 100644
--- a/crypto/cms/cms_kemri.c
+++ b/crypto/cms/cms_kemri.c
@@ -388,7 +388,7 @@ int ossl_cms_RecipientInfo_kemri_decrypt(const CMS_ContentInfo *cms,
goto err;
kem_ct = ASN1_STRING_get0_data(kemri->kemct);
- kem_ct_len = ASN1_STRING_length(kemri->kemct);
+ kem_ct_len = ASN1_STRING_length_ex(kemri->kemct);
if (EVP_PKEY_decapsulate(kemri->pctx, NULL, &kem_secret_len, kem_ct, kem_ct_len) <= 0)
return 0;
diff --git a/crypto/cms/cms_local.h b/crypto/cms/cms_local.h
index 5e0ac3907f..bfb0ca729b 100644
--- a/crypto/cms/cms_local.h
+++ b/crypto/cms/cms_local.h
@@ -401,6 +401,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/crypto/cms/cms_rsa.c b/crypto/cms/cms_rsa.c
index fc7fc6c284..1b351f6cd1 100644
--- a/crypto/cms/cms_rsa.c
+++ b/crypto/cms/cms_rsa.c
@@ -43,7 +43,7 @@ static int rsa_cms_decrypt(CMS_RecipientInfo *ri)
int nid;
int rv = -1;
const unsigned char *label = NULL;
- int labellen = 0;
+ size_t labellen = 0;
const EVP_MD *mgf1md = NULL, *md = NULL;
RSA_OAEP_PARAMS *oaep;
const ASN1_OBJECT *aoid;
@@ -90,7 +90,9 @@ static int rsa_cms_decrypt(CMS_RecipientInfo *ri)
}
label = ASN1_STRING_get0_data(parameter);
- labellen = ASN1_STRING_length(parameter);
+ labellen = ASN1_STRING_length_ex(parameter);
+ if (labellen > INT_MAX)
+ goto err;
}
if (EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_OAEP_PADDING) <= 0)
@@ -105,7 +107,7 @@ static int rsa_cms_decrypt(CMS_RecipientInfo *ri)
if (dup_label == NULL)
goto err;
- if (EVP_PKEY_CTX_set0_rsa_oaep_label(pkctx, dup_label, labellen) <= 0) {
+ if (EVP_PKEY_CTX_set0_rsa_oaep_label(pkctx, dup_label, (int)labellen) <= 0) {
OPENSSL_free(dup_label);
goto err;
}
diff --git a/crypto/cms/cms_sd.c b/crypto/cms/cms_sd.c
index 6466aacec1..352f75a45c 100644
--- a/crypto/cms/cms_sd.c
+++ b/crypto/cms/cms_sd.c
@@ -304,7 +304,7 @@ static int ossl_cms_add1_signing_cert(CMS_SignerInfo *si,
p = pp;
i2d_ESS_SIGNING_CERT(sc, &p);
- if (!(seq = ASN1_STRING_new()) || !ASN1_STRING_set(seq, pp, len)) {
+ if (!(seq = ASN1_STRING_new()) || !ASN1_STRING_set_data(seq, pp, len)) {
ASN1_STRING_free(seq);
OPENSSL_free(pp);
return 0;
@@ -329,7 +329,7 @@ static int ossl_cms_add1_signing_cert_v2(CMS_SignerInfo *si,
p = pp;
i2d_ESS_SIGNING_CERT_V2(sc, &p);
- if (!(seq = ASN1_STRING_new()) || !ASN1_STRING_set(seq, pp, len)) {
+ if (!(seq = ASN1_STRING_new()) || !ASN1_STRING_set_data(seq, pp, len)) {
ASN1_STRING_free(seq);
OPENSSL_free(pp);
return 0;
diff --git a/crypto/cms/cms_smime.c b/crypto/cms/cms_smime.c
index 659c033482..044cb2326f 100644
--- a/crypto/cms/cms_smime.c
+++ b/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/crypto/comp/c_brotli.c b/crypto/comp/c_brotli.c
index d262ec6a4e..9c99e066b7 100644
--- a/crypto/comp/c_brotli.c
+++ b/crypto/comp/c_brotli.c
@@ -13,6 +13,7 @@
#include
#include
#include
+#include "internal/e_os.h"
#include "internal/comp.h"
#include
#include "crypto/cryptlib.h"
@@ -46,10 +47,6 @@ static void brotli_free(void *opaque, void *address)
* work. Therefore, all BROTLI routines are loaded at run time
* and we do not link to a .LIB file when BROTLI_SHARED is set.
*/
-#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
-#include
-#endif
-
#ifdef BROTLI_SHARED
#include "internal/dso.h"
diff --git a/crypto/comp/c_zlib.c b/crypto/comp/c_zlib.c
index c90c7b090d..4af4e30b64 100644
--- a/crypto/comp/c_zlib.c
+++ b/crypto/comp/c_zlib.c
@@ -11,6 +11,7 @@
#include
#include
#include
+#include "internal/e_os.h"
#include "internal/comp.h"
#include
#include "crypto/cryptlib.h"
@@ -64,10 +65,6 @@ static COMP_METHOD zlib_stateful_method = {
* work. Therefore, all ZLIB routines are loaded at run time
* and we do not link to a .LIB file when ZLIB_SHARED is set.
*/
-#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
-#include
-#endif /* !(OPENSSL_SYS_WINDOWS || \
- * OPENSSL_SYS_WIN32) */
#ifdef ZLIB_SHARED
#include "internal/dso.h"
diff --git a/crypto/comp/c_zstd.c b/crypto/comp/c_zstd.c
index a9c881f8f9..c5c6cd6eef 100644
--- a/crypto/comp/c_zstd.c
+++ b/crypto/comp/c_zstd.c
@@ -16,6 +16,7 @@
#include
#include
#include
+#include "internal/e_os.h"
#include "internal/comp.h"
#include
#include "crypto/cryptlib.h"
@@ -62,16 +63,6 @@ static ZSTD_customMem zstd_mem_funcs = {
};
#endif
-/*
- * When OpenSSL is built on Windows, we do not want to require that
- * the LIBZSTD.DLL be available in order for the OpenSSL DLLs to
- * work. Therefore, all ZSTD routines are loaded at run time
- * and we do not link to a .LIB file when ZSTD_SHARED is set.
- */
-#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
-#include
-#endif
-
#ifdef ZSTD_SHARED
#include "internal/dso.h"
diff --git a/crypto/context.c b/crypto/context.c
index 3596c0e068..66d7e42955 100644
--- a/crypto/context.c
+++ b/crypto/context.c
@@ -255,12 +255,6 @@ err:
static void context_deinit_objs(OSSL_LIB_CTX *ctx)
{
- /* P2. We want evp_method_store to be cleaned up before the provider store */
- if (ctx->evp_method_store != NULL) {
- ossl_method_store_free(ctx->evp_method_store);
- ctx->evp_method_store = NULL;
- }
-
/* P2. */
if (ctx->drbg != NULL) {
ossl_rand_ctx_free(ctx->drbg);
@@ -278,14 +272,14 @@ static void context_deinit_objs(OSSL_LIB_CTX *ctx)
* P2. We want decoder_store/decoder_cache to be cleaned up before the
* provider store
*/
- if (ctx->decoder_store != NULL) {
- ossl_method_store_free(ctx->decoder_store);
- ctx->decoder_store = NULL;
- }
if (ctx->decoder_cache != NULL) {
ossl_decoder_cache_free(ctx->decoder_cache);
ctx->decoder_cache = NULL;
}
+ if (ctx->decoder_store != NULL) {
+ ossl_method_store_free(ctx->decoder_store);
+ ctx->decoder_store = NULL;
+ }
/* P2. We want encoder_store to be cleaned up before the provider store */
if (ctx->encoder_store != NULL) {
@@ -306,6 +300,12 @@ static void context_deinit_objs(OSSL_LIB_CTX *ctx)
ctx->provider_store = NULL;
}
+ /* P2. We want evp_method_store to be cleaned up before the provider store */
+ if (ctx->evp_method_store != NULL) {
+ ossl_method_store_free(ctx->evp_method_store);
+ ctx->evp_method_store = NULL;
+ }
+
/* Default priority. */
if (ctx->property_string_data != NULL) {
ossl_property_string_data_free(ctx->property_string_data);
diff --git a/crypto/core_fetch.c b/crypto/core_fetch.c
index 3293f70372..3d09b384aa 100644
--- a/crypto/core_fetch.c
+++ b/crypto/core_fetch.c
@@ -107,7 +107,7 @@ static void ossl_method_construct_this(OSSL_PROVIDER *provider,
struct construct_data_st *data = cbdata;
void *method = NULL;
- if ((method = data->mcm->construct(algo, provider, data->mcm_data))
+ if ((method = data->mcm->construct(algo, provider, data->mcm_data, no_store))
== NULL)
return;
diff --git a/crypto/cryptlib.c b/crypto/cryptlib.c
index 7624574103..07b244cb35 100644
--- a/crypto/cryptlib.c
+++ b/crypto/cryptlib.c
@@ -15,13 +15,6 @@
#if defined(_WIN32) && !defined(OPENSSL_SYS_UEFI)
#include
#include
-#ifdef __WATCOMC__
-#if defined(_UNICODE) || defined(__UNICODE__)
-#define _vsntprintf _vsnwprintf
-#else
-#define _vsntprintf _vsnprintf
-#endif
-#endif
#ifdef _MSC_VER
#define alloca _alloca
#endif
@@ -110,8 +103,6 @@ void OPENSSL_showfatal(const char *fmta, ...)
/*
* First check if it's a console application, in which case the
* error message would be printed to standard error.
- * Windows CE does not have a concept of a console application,
- * so we need to guard the check.
*/
#ifdef STD_ERROR_HANDLE
HANDLE h;
@@ -260,9 +251,7 @@ void OPENSSL_die(const char *message, const char *file, int line)
/*
* Win32 abort() customarily shows a dialog, but we just did that...
*/
-#if !defined(_WIN32_WCE)
raise(SIGABRT);
-#endif
_exit(3);
#endif
}
diff --git a/crypto/ct/ct_oct.c b/crypto/ct/ct_oct.c
index b8bef582a9..4f5fd8d027 100644
--- a/crypto/ct/ct_oct.c
+++ b/crypto/ct/ct_oct.c
@@ -381,7 +381,7 @@ STACK_OF(SCT) *d2i_SCT_LIST(STACK_OF(SCT) **a, const unsigned char **pp,
return NULL;
p = ASN1_STRING_get0_data(oct);
- if ((sk = o2i_SCT_LIST(a, &p, ASN1_STRING_length(oct))) != NULL)
+ if ((sk = o2i_SCT_LIST(a, &p, ASN1_STRING_length_ex(oct))) != NULL)
*pp += len;
ASN1_OCTET_STRING_free(oct);
diff --git a/crypto/ctype.c b/crypto/ctype.c
index 686fe64165..75192b11f4 100644
--- a/crypto/ctype.c
+++ b/crypto/ctype.c
@@ -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/crypto/des/des_local.h b/crypto/des/des_local.h
index 0fee059ec4..fa368c359c 100644
--- a/crypto/des/des_local.h
+++ b/crypto/des/des_local.h
@@ -32,7 +32,7 @@
#define ROTATE(a, n) (_lrotr(a, n))
#elif defined(__ICC)
#define ROTATE(a, n) (_rotr(a, n))
-#elif defined(__GNUC__) && __GNUC__ >= 2 && !defined(__STRICT_ANSI__) && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM) && !defined(PEDANTIC)
+#elif defined(__GNUC__) && !defined(__STRICT_ANSI__) && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM) && !defined(PEDANTIC)
#if defined(__i386) || defined(__i386__) || defined(__x86_64) || defined(__x86_64__)
#define ROTATE(a, n) ({ \
register unsigned int ret; \
diff --git a/crypto/dh/dh_lib.c b/crypto/dh/dh_lib.c
index 27ca94d1a6..1934c71080 100644
--- a/crypto/dh/dh_lib.c
+++ b/crypto/dh/dh_lib.c
@@ -142,7 +142,7 @@ int DH_up_ref(DH *r)
{
int i;
- if (CRYPTO_UP_REF(&r->references, &i) <= 0)
+ if (!CRYPTO_UP_REF(&r->references, &i))
return 0;
REF_PRINT_COUNT("DH", i, r);
diff --git a/crypto/dsa/dsa_lib.c b/crypto/dsa/dsa_lib.c
index 834d271346..5936b84098 100644
--- a/crypto/dsa/dsa_lib.c
+++ b/crypto/dsa/dsa_lib.c
@@ -215,7 +215,7 @@ int DSA_up_ref(DSA *r)
{
int i;
- if (CRYPTO_UP_REF(&r->references, &i) <= 0)
+ if (!CRYPTO_UP_REF(&r->references, &i))
return 0;
REF_PRINT_COUNT("DSA", i, r);
diff --git a/crypto/dso/dso_lib.c b/crypto/dso/dso_lib.c
index 6f51e4d35a..1366bea66d 100644
--- a/crypto/dso/dso_lib.c
+++ b/crypto/dso/dso_lib.c
@@ -93,7 +93,7 @@ int DSO_up_ref(DSO *dso)
return 0;
}
- if (CRYPTO_UP_REF(&dso->references, &i) <= 0)
+ if (!CRYPTO_UP_REF(&dso->references, &i))
return 0;
REF_PRINT_COUNT("DSO", i, dso);
diff --git a/crypto/dso/dso_win32.c b/crypto/dso/dso_win32.c
index 78cc649324..6ac6727fda 100644
--- a/crypto/dso/dso_win32.c
+++ b/crypto/dso/dso_win32.c
@@ -12,49 +12,6 @@
#if defined(DSO_WIN32)
-#ifdef _WIN32_WCE
-#if _WIN32_WCE < 300
-static FARPROC GetProcAddressA(HMODULE hModule, LPCSTR lpProcName)
-{
- WCHAR lpProcNameW[64];
- int i;
-
- for (i = 0; lpProcName[i] && i < 64; i++)
- lpProcNameW[i] = (WCHAR)lpProcName[i];
- if (i == 64)
- return NULL;
- lpProcNameW[i] = 0;
-
- return GetProcAddressW(hModule, lpProcNameW);
-}
-#endif
-#undef GetProcAddress
-#define GetProcAddress GetProcAddressA
-
-static HINSTANCE LoadLibraryA(LPCSTR lpLibFileName)
-{
- WCHAR *fnamw;
- size_t len_0 = strlen(lpLibFileName) + 1, i;
-
-#ifdef _MSC_VER
- fnamw = (WCHAR *)_alloca(len_0 * sizeof(WCHAR));
-#else
- fnamw = (WCHAR *)alloca(len_0 * sizeof(WCHAR));
-#endif
- if (fnamw == NULL) {
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return NULL;
- }
-#if defined(_WIN32_WCE) && _WIN32_WCE >= 101
- if (!MultiByteToWideChar(CP_ACP, 0, lpLibFileName, len_0, fnamw, len_0))
-#endif
- for (i = 0; i < len_0; i++)
- fnamw[i] = (WCHAR)lpLibFileName[i];
-
- return LoadLibraryW(fnamw);
-}
-#endif
-
#define GETPROCADDRESS(h, name, type) ((type)(void (*)(void))GetProcAddress((h), (name)))
/* Part of the hack in "win32_load" ... */
@@ -472,14 +429,10 @@ static const char *openssl_strnchr(const char *string, int c, size_t len)
}
#include
-#ifdef _WIN32_WCE
-#define DLLNAME "TOOLHELP.DLL"
-#else
#ifdef MODULEENTRY32
#undef MODULEENTRY32 /* unmask the ASCII version! */
#endif
#define DLLNAME "KERNEL32.DLL"
-#endif
typedef HANDLE(WINAPI *CREATETOOLHELP32SNAPSHOT)(DWORD, DWORD);
typedef BOOL(WINAPI *CLOSETOOLHELP32SNAPSHOT)(HANDLE);
@@ -582,11 +535,7 @@ static void *win32_globallookup(const char *name)
return NULL;
}
/* We take the rest for granted... */
-#ifdef _WIN32_WCE
- close_snap = GETPROCADDRESS(dll, "CloseToolhelp32Snapshot", CLOSETOOLHELP32SNAPSHOT);
-#else
close_snap = (CLOSETOOLHELP32SNAPSHOT)CloseHandle;
-#endif
module_first = GETPROCADDRESS(dll, "Module32First", MODULE32);
module_next = GETPROCADDRESS(dll, "Module32Next", MODULE32);
diff --git a/crypto/ec/asm/ecp_sm2p256-riscv64.pl b/crypto/ec/asm/ecp_sm2p256-riscv64.pl
index 2a17e124dc..40938e75c0 100644
--- a/crypto/ec/asm/ecp_sm2p256-riscv64.pl
+++ b/crypto/ec/asm/ecp_sm2p256-riscv64.pl
@@ -366,7 +366,7 @@ $code.=<<___;
.type .Lord_div_2,\@object
.Lord_div_2:
.dword 0xa9ddfa049ceaa092,0xb901efb590e30295,0xffffffffffffffff,0x7fffffff7fffffff
-
+.previous
// void bn_rshift1(BN_ULONG *a);
.globl bn_rshift1
diff --git a/crypto/ec/curve25519.c b/crypto/ec/curve25519.c
index c6886763ab..53c8bff5ed 100644
--- a/crypto/ec/curve25519.c
+++ b/crypto/ec/curve25519.c
@@ -236,6 +236,13 @@ static void x25519_scalar_mulx(uint8_t out[32], const uint8_t scalar[32],
fe64_sub(tmp1, x2, z2);
fe64_add(x2, x2, z2);
fe64_add(z2, x3, z3);
+ /* The original copy in x25519_scalar_mult_generic uses argument order
+ * fe_mul(z3, tmp0, x2), with the input arguments swapped.
+ *
+ * The assembly implementation of fe64_mul used here runs faster in
+ * parallel with its nearby instructions when an earlier-computable
+ * input (like tmp0) is passed as the 2nd input because it consumes
+ * the 2nd input at a faster rate than the 1st input. */
fe64_mul(z3, x2, tmp0);
fe64_mul(z2, z2, tmp1);
fe64_sqr(tmp0, tmp1);
diff --git a/crypto/ec/curve448/curve448.c b/crypto/ec/curve448/curve448.c
index 1a31f86355..29edb317f1 100644
--- a/crypto/ec/curve448/curve448.c
+++ b/crypto/ec/curve448/curve448.c
@@ -502,7 +502,7 @@ struct smvt_control {
int power, addend;
};
-#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3))
+#if defined(__GNUC__)
#define NUMTRAILINGZEROS __builtin_ctz
#else
#define NUMTRAILINGZEROS numtrailingzeros
diff --git a/crypto/ec/curve448/eddsa.c b/crypto/ec/curve448/eddsa.c
index 8615b19dfc..1c375413ab 100644
--- a/crypto/ec/curve448/eddsa.c
+++ b/crypto/ec/curve448/eddsa.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2024 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2017-2026 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 2015-2016 Cryptography Research, Inc.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
@@ -94,6 +94,7 @@ static c448_error_t hash_init_with_dom(OSSL_LIB_CTX *ctx, EVP_MD_CTX *hashctx,
*
* pubkey (out): The public key.
* privkey (in): The private key.
+ * propq (in): The property query used to fetch SHAKE256.
*/
static c448_error_t
c448_ed448_derive_public_key(
@@ -155,6 +156,7 @@ c448_ed448_derive_public_key(
* you want to sign.
* context (in): A "context" for this signature of up to 255 bytes.
* context_len (in): Length of the context.
+ * propq (in): The property query used to fetch SHAKE256.
*
* For Ed25519, it is unsafe to use the same key for both prehashed and
* non-prehashed messages, at least without some very careful protocol-level
@@ -292,6 +294,7 @@ c448_ed448_pubkey_verify(const uint8_t *pub, size_t pub_len)
* want to verify.
* context (in): A "context" for this signature of up to 255 bytes.
* context_len (in): Length of the context.
+ * propq (in): The property query used to fetch SHAKE256.
*
* For Ed25519, it is unsafe to use the same key for both prehashed and
* non-prehashed messages, at least without some very careful protocol-level
diff --git a/crypto/ec/ec_asn1.c b/crypto/ec/ec_asn1.c
index b839e9d2a2..835f759935 100644
--- a/crypto/ec/ec_asn1.c
+++ b/crypto/ec/ec_asn1.c
@@ -966,9 +966,10 @@ EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const unsigned char **in, long len)
if (priv_key->privateKey) {
ASN1_OCTET_STRING *pkey = priv_key->privateKey;
- if (EC_KEY_oct2priv(ret, ASN1_STRING_get0_data(pkey),
- ASN1_STRING_length(pkey))
- == 0)
+ size_t pkey_len = ASN1_STRING_length_ex(pkey);
+ if (pkey_len > INT_MAX)
+ goto err;
+ if (EC_KEY_oct2priv(ret, ASN1_STRING_get0_data(pkey), (int)pkey_len) == 0)
goto err;
} else {
ERR_raise(ERR_LIB_EC, EC_R_MISSING_PRIVATE_KEY);
@@ -987,11 +988,13 @@ EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const unsigned char **in, long len)
if (priv_key->publicKey) {
const unsigned char *pub_oct;
- int pub_oct_len;
+ size_t pub_oct_len;
pub_oct = ASN1_STRING_get0_data(priv_key->publicKey);
- pub_oct_len = ASN1_STRING_length(priv_key->publicKey);
- if (!EC_KEY_oct2key(ret, pub_oct, pub_oct_len, NULL)) {
+ pub_oct_len = ASN1_STRING_length_ex(priv_key->publicKey);
+ if (pub_oct_len > INT_MAX)
+ goto err;
+ if (!EC_KEY_oct2key(ret, pub_oct, (int)pub_oct_len, NULL)) {
ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB);
goto err;
}
@@ -1063,7 +1066,7 @@ int i2d_ECPrivateKey(const EC_KEY *a, unsigned char **out)
goto err;
}
- publen = EC_KEY_key2buf(a, a->conv_form, &pub, NULL);
+ publen = EC_KEY_key2buf(a, EC_KEY_get_conv_form(a), &pub, NULL);
if (publen == 0 || publen > INT_MAX) {
ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB);
@@ -1084,7 +1087,7 @@ err:
OPENSSL_clear_free(priv, privlen);
OPENSSL_free(pub);
EC_PRIVATEKEY_free(priv_key);
- return (ok ? ret : 0);
+ return ok ? ret : 0;
}
int i2d_ECParameters(const EC_KEY *a, unsigned char **out)
@@ -1164,7 +1167,7 @@ int i2o_ECPublicKey(const EC_KEY *a, unsigned char **out)
}
buf_len = EC_POINT_point2oct(a->group, a->pub_key,
- a->conv_form, NULL, 0, NULL);
+ EC_KEY_get_conv_form(a), NULL, 0, NULL);
if (buf_len > INT_MAX) {
ERR_raise(ERR_LIB_EC, ERR_R_PASSED_INVALID_ARGUMENT);
@@ -1179,7 +1182,7 @@ int i2o_ECPublicKey(const EC_KEY *a, unsigned char **out)
return 0;
new_buffer = 1;
}
- if (!EC_POINT_point2oct(a->group, a->pub_key, a->conv_form,
+ if (!EC_POINT_point2oct(a->group, a->pub_key, EC_KEY_get_conv_form(a),
*out, buf_len, NULL)) {
ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB);
if (new_buffer) {
diff --git a/crypto/ec/ec_backend.c b/crypto/ec/ec_backend.c
index 0d1de52dbb..764ab7558b 100644
--- a/crypto/ec/ec_backend.c
+++ b/crypto/ec/ec_backend.c
@@ -655,7 +655,6 @@ EC_KEY *ossl_ec_key_dup(const EC_KEY *src, int selection)
/* copy the rest */
if ((selection & OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS) != 0) {
ret->enc_flag = src->enc_flag;
- ret->conv_form = src->conv_form;
}
ret->version = src->version;
diff --git a/crypto/ec/ec_key.c b/crypto/ec/ec_key.c
index 8deaa3b930..4a84933bb6 100644
--- a/crypto/ec/ec_key.c
+++ b/crypto/ec/ec_key.c
@@ -146,7 +146,6 @@ EC_KEY *EC_KEY_copy(EC_KEY *dest, const EC_KEY *src)
/* copy the rest */
dest->enc_flag = src->enc_flag;
- dest->conv_form = src->conv_form;
dest->version = src->version;
dest->flags = src->flags;
#ifndef FIPS_MODULE
@@ -176,7 +175,7 @@ int EC_KEY_up_ref(EC_KEY *r)
{
int i;
- if (CRYPTO_UP_REF(&r->references, &i) <= 0)
+ if (!CRYPTO_UP_REF(&r->references, &i))
return 0;
REF_PRINT_COUNT("EC_KEY", i, r);
@@ -214,56 +213,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"
@@ -360,8 +309,7 @@ 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. */
@@ -883,12 +831,13 @@ void EC_KEY_set_enc_flags(EC_KEY *key, unsigned int flags)
point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *key)
{
- return key->conv_form;
+ return key->group != NULL
+ ? EC_GROUP_get_point_conversion_form(key->group)
+ : POINT_CONVERSION_UNCOMPRESSED;
}
void EC_KEY_set_conv_form(EC_KEY *key, point_conversion_form_t cform)
{
- key->conv_form = cform;
if (key->group != NULL)
EC_GROUP_set_point_conversion_form(key->group, cform);
}
@@ -959,8 +908,10 @@ int EC_KEY_oct2key(EC_KEY *key, const unsigned char *buf, size_t len,
* EC_POINT_oct2point() has already performed sanity checking of
* the buffer so we know it is valid.
*/
- if ((key->group->meth->flags & EC_FLAGS_CUSTOM_CURVE) == 0)
- key->conv_form = (point_conversion_form_t)(buf[0] & ~0x01);
+ if ((key->group->meth->flags & EC_FLAGS_CUSTOM_CURVE) == 0) {
+ EC_GROUP_set_point_conversion_form(key->group,
+ (point_conversion_form_t)(buf[0] & ~0x01));
+ }
return 1;
}
diff --git a/crypto/ec/ec_kmeth.c b/crypto/ec/ec_kmeth.c
index b98bdd578e..b27a40519d 100644
--- a/crypto/ec/ec_kmeth.c
+++ b/crypto/ec/ec_kmeth.c
@@ -90,7 +90,6 @@ EC_KEY *ossl_ec_key_new_method_int(OSSL_LIB_CTX *libctx, const char *propq)
ret->meth = EC_KEY_get_default_method();
ret->version = 1;
- ret->conv_form = POINT_CONVERSION_UNCOMPRESSED;
/* No ex_data inside the FIPS provider */
#ifndef FIPS_MODULE
diff --git a/crypto/ec/ec_local.h b/crypto/ec/ec_local.h
index 16adfbb92f..0be3c5529e 100644
--- a/crypto/ec/ec_local.h
+++ b/crypto/ec/ec_local.h
@@ -301,7 +301,6 @@ struct ec_key_st {
EC_POINT *pub_key;
BIGNUM *priv_key;
unsigned int enc_flag;
- point_conversion_form_t conv_form;
CRYPTO_REF_COUNT references;
int flags;
#ifndef FIPS_MODULE
diff --git a/crypto/ec/ec_mult.c b/crypto/ec/ec_mult.c
index 4771789151..f5c6ac7893 100644
--- a/crypto/ec/ec_mult.c
+++ b/crypto/ec/ec_mult.c
@@ -72,8 +72,8 @@ static EC_PRE_COMP *ec_pre_comp_new(const EC_GROUP *group)
EC_PRE_COMP *EC_ec_pre_comp_dup(EC_PRE_COMP *pre)
{
int i;
- if (pre != NULL)
- CRYPTO_UP_REF(&pre->references, &i);
+ if (pre == NULL || !CRYPTO_UP_REF(&pre->references, &i))
+ return NULL;
return pre;
}
diff --git a/crypto/ec/ecp_nistp224.c b/crypto/ec/ecp_nistp224.c
index 7183131622..1a0952083c 100644
--- a/crypto/ec/ecp_nistp224.c
+++ b/crypto/ec/ecp_nistp224.c
@@ -1234,8 +1234,8 @@ static NISTP224_PRE_COMP *nistp224_pre_comp_new(void)
NISTP224_PRE_COMP *EC_nistp224_pre_comp_dup(NISTP224_PRE_COMP *p)
{
int i;
- if (p != NULL)
- CRYPTO_UP_REF(&p->references, &i);
+ if (p == NULL || !CRYPTO_UP_REF(&p->references, &i))
+ return NULL;
return p;
}
diff --git a/crypto/ec/ecp_nistp256.c b/crypto/ec/ecp_nistp256.c
index e247e51c9c..fba197a8c7 100644
--- a/crypto/ec/ecp_nistp256.c
+++ b/crypto/ec/ecp_nistp256.c
@@ -1852,8 +1852,8 @@ static NISTP256_PRE_COMP *nistp256_pre_comp_new(void)
NISTP256_PRE_COMP *EC_nistp256_pre_comp_dup(NISTP256_PRE_COMP *p)
{
int i;
- if (p != NULL)
- CRYPTO_UP_REF(&p->references, &i);
+ if (p == NULL || !CRYPTO_UP_REF(&p->references, &i))
+ return NULL;
return p;
}
diff --git a/crypto/ec/ecp_nistp384.c b/crypto/ec/ecp_nistp384.c
index e03bda2178..3d212dcc15 100644
--- a/crypto/ec/ecp_nistp384.c
+++ b/crypto/ec/ecp_nistp384.c
@@ -1576,8 +1576,8 @@ NISTP384_PRE_COMP *ossl_ec_nistp384_pre_comp_dup(NISTP384_PRE_COMP *p)
{
int i;
- if (p != NULL)
- CRYPTO_UP_REF(&p->references, &i);
+ if (p == NULL || !CRYPTO_UP_REF(&p->references, &i))
+ return NULL;
return p;
}
diff --git a/crypto/ec/ecp_nistp521.c b/crypto/ec/ecp_nistp521.c
index 7ea8d00c14..f7315f136c 100644
--- a/crypto/ec/ecp_nistp521.c
+++ b/crypto/ec/ecp_nistp521.c
@@ -1667,8 +1667,8 @@ static NISTP521_PRE_COMP *nistp521_pre_comp_new(void)
NISTP521_PRE_COMP *EC_nistp521_pre_comp_dup(NISTP521_PRE_COMP *p)
{
int i;
- if (p != NULL)
- CRYPTO_UP_REF(&p->references, &i);
+ if (p == NULL || !CRYPTO_UP_REF(&p->references, &i))
+ return NULL;
return p;
}
diff --git a/crypto/ec/ecp_nistz256.c b/crypto/ec/ecp_nistz256.c
index 301f90188a..df467b948f 100644
--- a/crypto/ec/ecp_nistz256.c
+++ b/crypto/ec/ecp_nistz256.c
@@ -1208,8 +1208,8 @@ static NISTZ256_PRE_COMP *ecp_nistz256_pre_comp_new(const EC_GROUP *group)
NISTZ256_PRE_COMP *EC_nistz256_pre_comp_dup(NISTZ256_PRE_COMP *p)
{
int i;
- if (p != NULL)
- CRYPTO_UP_REF(&p->references, &i);
+ if (p == NULL || !CRYPTO_UP_REF(&p->references, &i))
+ return NULL;
return p;
}
diff --git a/crypto/ec/ecx_backend.c b/crypto/ec/ecx_backend.c
index 710ad31a66..d95e8bb084 100644
--- a/crypto/ec/ecx_backend.c
+++ b/crypto/ec/ecx_backend.c
@@ -230,15 +230,19 @@ ECX_KEY *ossl_ecx_key_from_pkcs8(const PKCS8_PRIV_KEY_INFO *p8inf,
const X509_ALGOR *palg;
if (!PKCS8_pkey_get0(NULL, &p, &plen, &palg, p8inf))
- return 0;
+ goto err;
oct = d2i_ASN1_OCTET_STRING(NULL, &p, plen);
if (oct == NULL) {
p = NULL;
plen = 0;
} else {
+ size_t tmp;
p = ASN1_STRING_get0_data(oct);
- plen = ASN1_STRING_length(oct);
+ tmp = ASN1_STRING_length_ex(oct);
+ if (tmp > INT_MAX)
+ goto err;
+ plen = (int)tmp;
}
/*
@@ -247,6 +251,7 @@ ECX_KEY *ossl_ecx_key_from_pkcs8(const PKCS8_PRIV_KEY_INFO *p8inf,
*/
ecx = ossl_ecx_key_op(palg, p, plen, EVP_PKEY_NONE, KEY_OP_PRIVATE,
libctx, propq);
+err:
ASN1_OCTET_STRING_free(oct);
return ecx;
}
diff --git a/crypto/ec/ecx_key.c b/crypto/ec/ecx_key.c
index 4d8c945755..036e308e8b 100644
--- a/crypto/ec/ecx_key.c
+++ b/crypto/ec/ecx_key.c
@@ -92,7 +92,7 @@ int ossl_ecx_key_up_ref(ECX_KEY *key)
{
int i;
- if (CRYPTO_UP_REF(&key->references, &i) <= 0)
+ if (!CRYPTO_UP_REF(&key->references, &i))
return 0;
REF_PRINT_COUNT("ECX_KEY", i, key);
diff --git a/crypto/encode_decode/decoder_meth.c b/crypto/encode_decode/decoder_meth.c
index 4d460af1c2..632d20c996 100644
--- a/crypto/encode_decode/decoder_meth.c
+++ b/crypto/encode_decode/decoder_meth.c
@@ -26,39 +26,7 @@
static void ossl_decoder_free(void *data)
{
- OSSL_DECODER_free(data);
-}
-
-static int ossl_decoder_up_ref(void *data)
-{
- return OSSL_DECODER_up_ref(data);
-}
-
-/* Simple method structure constructor and destructor */
-static OSSL_DECODER *ossl_decoder_new(void)
-{
- OSSL_DECODER *decoder = NULL;
-
- if ((decoder = OPENSSL_zalloc(sizeof(*decoder))) == NULL)
- return NULL;
- if (!CRYPTO_NEW_REF(&decoder->base.refcnt, 1)) {
- OSSL_DECODER_free(decoder);
- return NULL;
- }
-
- return decoder;
-}
-
-int OSSL_DECODER_up_ref(OSSL_DECODER *decoder)
-{
- int ref = 0;
-
- CRYPTO_UP_REF(&decoder->base.refcnt, &ref);
- return 1;
-}
-
-void OSSL_DECODER_free(OSSL_DECODER *decoder)
-{
+ OSSL_DECODER *decoder = (OSSL_DECODER *)data;
int ref = 0;
if (decoder == NULL)
@@ -74,6 +42,58 @@ void OSSL_DECODER_free(OSSL_DECODER *decoder)
OPENSSL_free(decoder);
}
+static int ossl_decoder_up_ref(void *data)
+{
+ OSSL_DECODER *decoder = (OSSL_DECODER *)data;
+ int ref = 0;
+
+ return CRYPTO_UP_REF(&decoder->base.refcnt, &ref);
+}
+
+/* Simple method structure constructor and destructor */
+static OSSL_DECODER *ossl_decoder_new(void)
+{
+ OSSL_DECODER *decoder = NULL;
+
+ if ((decoder = OPENSSL_zalloc(sizeof(*decoder))) == NULL)
+ return NULL;
+ if (!CRYPTO_NEW_REF(&decoder->base.refcnt, 1)) {
+ ossl_decoder_free(decoder);
+ return NULL;
+ }
+
+ return decoder;
+}
+
+int OSSL_DECODER_up_ref(OSSL_DECODER *decoder)
+{
+#ifdef OPENSSL_NO_CACHED_FETCH
+ return ossl_decoder_up_ref(decoder);
+#else
+ /*
+ * DECODERS do something weird. They manually build methods rather than
+ * attempt to fetch them from the method store or construct them through
+ * the ossl_generic_fetch mechanism. As such they don't make use of the refcounting
+ * that we rely on in the method store, and so we always need to refcount them here
+ * We can identify them based on the fact that they never have a registered nid (i.e.
+ * its always zero)
+ */
+ if (decoder->base.id == 0 || decoder->base.no_store != 0)
+ return ossl_decoder_up_ref(decoder);
+ return 1;
+#endif
+}
+
+void OSSL_DECODER_free(OSSL_DECODER *decoder)
+{
+#ifdef OPENSSL_NO_CACHED_FETCH
+ ossl_decoder_free(decoder);
+#else
+ if (decoder != NULL && (decoder->base.id == 0 || decoder->base.no_store != 0))
+ ossl_decoder_free(decoder);
+#endif
+}
+
/* Data to be passed through ossl_method_construct() */
struct decoder_data_st {
OSSL_LIB_CTX *libctx;
@@ -207,7 +227,7 @@ static int put_decoder_in_store(void *store, void *method,
/* Create and populate a decoder method */
void *ossl_decoder_from_algorithm(int id, const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov)
+ OSSL_PROVIDER *prov, int no_store)
{
OSSL_DECODER *decoder = NULL;
const OSSL_DISPATCH *fns = algodef->implementation;
@@ -216,15 +236,16 @@ void *ossl_decoder_from_algorithm(int id, const OSSL_ALGORITHM *algodef,
if ((decoder = ossl_decoder_new()) == NULL)
return NULL;
decoder->base.id = id;
+ decoder->base.no_store = no_store;
if ((decoder->base.name = ossl_algorithm_get1_first_name(algodef)) == NULL) {
- OSSL_DECODER_free(decoder);
+ ossl_decoder_free(decoder);
return NULL;
}
decoder->base.algodef = algodef;
if ((decoder->base.parsed_propdef
= ossl_parse_property(libctx, algodef->property_definition))
== NULL) {
- OSSL_DECODER_free(decoder);
+ ossl_decoder_free(decoder);
return NULL;
}
@@ -276,13 +297,13 @@ void *ossl_decoder_from_algorithm(int id, const OSSL_ALGORITHM *algodef,
if (!((decoder->newctx == NULL && decoder->freectx == NULL)
|| (decoder->newctx != NULL && decoder->freectx != NULL))
|| decoder->decode == NULL) {
- OSSL_DECODER_free(decoder);
+ ossl_decoder_free(decoder);
ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_INVALID_PROVIDER_FUNCTIONS);
return NULL;
}
if (prov != NULL && !ossl_provider_up_ref(prov)) {
- OSSL_DECODER_free(decoder);
+ ossl_decoder_free(decoder);
return NULL;
}
@@ -296,7 +317,7 @@ void *ossl_decoder_from_algorithm(int id, const OSSL_ALGORITHM *algodef,
* then call ossl_decoder_from_algorithm() with that identity number.
*/
static void *construct_decoder(const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov, void *data)
+ OSSL_PROVIDER *prov, void *data, int no_store)
{
/*
* This function is only called if get_decoder_from_store() returned
@@ -312,7 +333,7 @@ static void *construct_decoder(const OSSL_ALGORITHM *algodef,
void *method = NULL;
if (id != 0)
- method = ossl_decoder_from_algorithm(id, algodef, prov);
+ method = ossl_decoder_from_algorithm(id, algodef, prov, no_store);
/*
* Flag to indicate that there was actual construction errors. This
@@ -328,17 +349,7 @@ static void *construct_decoder(const OSSL_ALGORITHM *algodef,
/* Intermediary function to avoid ugly casts, used below */
static void destruct_decoder(void *method, void *data)
{
- OSSL_DECODER_free(method);
-}
-
-static int up_ref_decoder(void *method)
-{
- return OSSL_DECODER_up_ref(method);
-}
-
-static void free_decoder(void *method)
-{
- OSSL_DECODER_free(method);
+ ossl_decoder_free(method);
}
/* Fetching support. Can fetch by numeric identity or by name */
@@ -394,9 +405,22 @@ inner_ossl_decoder_fetch(struct decoder_data_st *methdata,
*/
if (id == 0 && name != NULL)
id = ossl_namemap_name2num(namemap, name);
- if (id != 0)
+ if (id != 0 && methdata->tmp_store == NULL) {
ossl_method_store_cache_set(store, prov, id, propq, method,
- up_ref_decoder, free_decoder);
+ ossl_decoder_up_ref, ossl_decoder_free);
+ } else {
+ /*
+ * Like with EVP methods, if the provider requests no caching we need
+ * to take an extra refcount here so that the tmp_stored decoder
+ * lives beyond the freeing of that tmp_store
+ */
+#ifndef OPENSSL_NO_CACHED_FETCH
+ if (!OSSL_DECODER_up_ref((OSSL_DECODER *)method)) {
+ ossl_decoder_free(method);
+ method = NULL;
+ }
+#endif
+ }
}
/*
diff --git a/crypto/encode_decode/encoder_local.h b/crypto/encode_decode/encoder_local.h
index 789212746b..6ebbe1c513 100644
--- a/crypto/encode_decode/encoder_local.h
+++ b/crypto/encode_decode/encoder_local.h
@@ -24,6 +24,7 @@
struct ossl_endecode_base_st {
OSSL_PROVIDER *prov;
int id;
+ int no_store;
char *name;
const OSSL_ALGORITHM *algodef;
OSSL_PROPERTY_LIST *parsed_propdef;
diff --git a/crypto/encode_decode/encoder_meth.c b/crypto/encode_decode/encoder_meth.c
index 74ba83fc3d..cb167004ab 100644
--- a/crypto/encode_decode/encoder_meth.c
+++ b/crypto/encode_decode/encoder_meth.c
@@ -27,12 +27,28 @@
static void ossl_encoder_free(void *data)
{
- OSSL_ENCODER_free(data);
+ OSSL_ENCODER *encoder = (OSSL_ENCODER *)data;
+ int ref = 0;
+
+ if (encoder == NULL)
+ return;
+
+ CRYPTO_DOWN_REF(&encoder->base.refcnt, &ref);
+ if (ref > 0)
+ return;
+ OPENSSL_free(encoder->base.name);
+ ossl_property_free(encoder->base.parsed_propdef);
+ ossl_provider_free(encoder->base.prov);
+ CRYPTO_FREE_REF(&encoder->base.refcnt);
+ OPENSSL_free(encoder);
}
static int ossl_encoder_up_ref(void *data)
{
- return OSSL_ENCODER_up_ref(data);
+ OSSL_ENCODER *encoder = (OSSL_ENCODER *)data;
+ int ref = 0;
+
+ return CRYPTO_UP_REF(&encoder->base.refcnt, &ref);
}
/* Simple method structure constructor and destructor */
@@ -52,27 +68,23 @@ static OSSL_ENCODER *ossl_encoder_new(void)
int OSSL_ENCODER_up_ref(OSSL_ENCODER *encoder)
{
- int ref = 0;
-
- CRYPTO_UP_REF(&encoder->base.refcnt, &ref);
+#ifdef OPENSSL_NO_CACHED_FETCH
+ return ossl_encoder_up_ref(encoder);
+#else
+ if (encoder->base.no_store != 0)
+ return ossl_encoder_up_ref(encoder);
return 1;
+#endif
}
void OSSL_ENCODER_free(OSSL_ENCODER *encoder)
{
- int ref = 0;
-
- if (encoder == NULL)
- return;
-
- CRYPTO_DOWN_REF(&encoder->base.refcnt, &ref);
- if (ref > 0)
- return;
- OPENSSL_free(encoder->base.name);
- ossl_property_free(encoder->base.parsed_propdef);
- ossl_provider_free(encoder->base.prov);
- CRYPTO_FREE_REF(&encoder->base.refcnt);
- OPENSSL_free(encoder);
+#ifdef OPENSSL_NO_CACHED_FETCH
+ ossl_encoder_free(encoder);
+#else
+ if (encoder != NULL && (encoder->base.no_store != 0))
+ ossl_encoder_free(encoder);
+#endif
}
/* Data to be passed through ossl_method_construct() */
@@ -208,7 +220,7 @@ static int put_encoder_in_store(void *store, void *method,
/* Create and populate a encoder method */
static void *encoder_from_algorithm(int id, const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov)
+ OSSL_PROVIDER *prov, int no_store)
{
OSSL_ENCODER *encoder = NULL;
const OSSL_DISPATCH *fns = algodef->implementation;
@@ -217,15 +229,16 @@ static void *encoder_from_algorithm(int id, const OSSL_ALGORITHM *algodef,
if ((encoder = ossl_encoder_new()) == NULL)
return NULL;
encoder->base.id = id;
+ encoder->base.no_store = no_store;
if ((encoder->base.name = ossl_algorithm_get1_first_name(algodef)) == NULL) {
- OSSL_ENCODER_free(encoder);
+ ossl_encoder_free(encoder);
return NULL;
}
encoder->base.algodef = algodef;
if ((encoder->base.parsed_propdef
= ossl_parse_property(libctx, algodef->property_definition))
== NULL) {
- OSSL_ENCODER_free(encoder);
+ ossl_encoder_free(encoder);
return NULL;
}
@@ -283,13 +296,13 @@ static void *encoder_from_algorithm(int id, const OSSL_ALGORITHM *algodef,
|| (encoder->import_object != NULL && encoder->free_object != NULL)
|| (encoder->import_object == NULL && encoder->free_object == NULL))
|| encoder->encode == NULL) {
- OSSL_ENCODER_free(encoder);
+ ossl_encoder_free(encoder);
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INVALID_PROVIDER_FUNCTIONS);
return NULL;
}
if (prov != NULL && !ossl_provider_up_ref(prov)) {
- OSSL_ENCODER_free(encoder);
+ ossl_encoder_free(encoder);
return NULL;
}
@@ -303,7 +316,7 @@ static void *encoder_from_algorithm(int id, const OSSL_ALGORITHM *algodef,
* then call encoder_from_algorithm() with that identity number.
*/
static void *construct_encoder(const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov, void *data)
+ OSSL_PROVIDER *prov, void *data, int no_store)
{
/*
* This function is only called if get_encoder_from_store() returned
@@ -319,7 +332,7 @@ static void *construct_encoder(const OSSL_ALGORITHM *algodef,
void *method = NULL;
if (id != 0)
- method = encoder_from_algorithm(id, algodef, prov);
+ method = encoder_from_algorithm(id, algodef, prov, no_store);
/*
* Flag to indicate that there was actual construction errors. This
@@ -335,17 +348,7 @@ static void *construct_encoder(const OSSL_ALGORITHM *algodef,
/* Intermediary function to avoid ugly casts, used below */
static void destruct_encoder(void *method, void *data)
{
- OSSL_ENCODER_free(method);
-}
-
-static int up_ref_encoder(void *method)
-{
- return OSSL_ENCODER_up_ref(method);
-}
-
-static void free_encoder(void *method)
-{
- OSSL_ENCODER_free(method);
+ ossl_encoder_free(method);
}
/* Fetching support. Can fetch by numeric identity or by name */
@@ -401,8 +404,19 @@ inner_ossl_encoder_fetch(struct encoder_data_st *methdata,
*/
if (id == 0)
id = ossl_namemap_name2num(namemap, name);
- ossl_method_store_cache_set(store, prov, id, propq, method,
- up_ref_encoder, free_encoder);
+ if (id != 0 && methdata->tmp_store == NULL) {
+ ossl_method_store_cache_set(store, prov, id, propq, method,
+ ossl_encoder_up_ref, ossl_encoder_free);
+ } else {
+ /*
+ * Like with EVP methods, if the provider requests no caching we need
+ * to take an extra refcount here so that the tmp_stored encoder
+ * lives beyond the freeing of that tmp_store
+ */
+#ifndef OPENSSL_NO_CACHED_FETCH
+ OSSL_ENCODER_up_ref((OSSL_ENCODER *)method);
+#endif
+ }
}
/*
diff --git a/crypto/err/err_all.c b/crypto/err/err_all.c
index e614f4229d..7761410f2d 100644
--- a/crypto/err/err_all.c
+++ b/crypto/err/err_all.c
@@ -13,7 +13,6 @@
#include "crypto/cryptoerr.h"
#include "crypto/asn1err.h"
#include "crypto/bnerr.h"
-#include "crypto/fnerr.h"
#include "crypto/ecerr.h"
#include "crypto/buffererr.h"
#include "crypto/bioerr.h"
@@ -52,7 +51,6 @@ int ossl_err_load_crypto_strings(void)
#ifndef OPENSSL_NO_ERR
|| ossl_err_load_ERR_strings() == 0 /* include error strings for SYSerr */
|| ossl_err_load_BN_strings() == 0
- || ossl_err_load_OSSL_FN_strings() == 0
|| ossl_err_load_RSA_strings() == 0
#ifndef OPENSSL_NO_DH
|| ossl_err_load_DH_strings() == 0
diff --git a/crypto/err/openssl.ec b/crypto/err/openssl.ec
index ca1fae106f..91aa11d1a6 100644
--- a/crypto/err/openssl.ec
+++ b/crypto/err/openssl.ec
@@ -43,7 +43,6 @@ L PROV include/openssl/proverr.h providers/common/provider_err.c
L OSSL_ENCODER include/openssl/encodererr.h crypto/encode_decode/encoder_err.c include/crypto/encodererr.h
L OSSL_DECODER include/openssl/decodererr.h crypto/encode_decode/decoder_err.c include/crypto/decodererr.h
L HTTP include/openssl/httperr.h crypto/http/http_err.c include/crypto/httperr.h
-L OSSL_FN NONE crypto/fn/fn_err.c include/crypto/fnerr.h
# SSL/TLS alerts
R SSL_R_TLS_ALERT_UNEXPECTED_MESSAGE 1010
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 95d968db1f..8b6c912977 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -888,13 +888,6 @@ OSSL_ENCODER_R_ENCODER_NOT_FOUND:101:encoder not found
OSSL_ENCODER_R_INCORRECT_PROPERTY_QUERY:100:incorrect property query
OSSL_ENCODER_R_MISSING_GET_PARAMS:102:missing get params
OSSL_ENCODER_R_UNKNOWN_PARAMETER_NAME:104:unknown parameter name
-OSSL_FN_R_DIV_BY_ZERO:101:div by zero
-OSSL_FN_R_INPUT_NOT_REDUCED:103:input not reduced
-OSSL_FN_R_BITS_TOO_SMALL:105:bits too small
-OSSL_FN_R_INVALID_RANGE:106:invalid range
-OSSL_FN_R_INVALID_SHIFT:102:invalid shift
-OSSL_FN_R_RESULT_ARG_TOO_SMALL:100:result arg too small
-OSSL_FN_R_TOO_MANY_ITERATIONS:107:too many iterations
OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE:107:ambiguous content type
OSSL_STORE_R_BAD_PASSWORD_READ:115:bad password read
OSSL_STORE_R_ERROR_VERIFYING_PKCS12_MAC:113:error verifying pkcs12 mac
@@ -1113,6 +1106,7 @@ PROV_R_INVALID_THREAD_POOL_SIZE:234:invalid thread pool size
PROV_R_INVALID_UKM_LENGTH:200:invalid ukm length
PROV_R_INVALID_X931_DIGEST:170:invalid x931 digest
PROV_R_IN_ERROR_STATE:192:in error state
+PROV_R_KEY_IMMUTABLE_ONCE_SET:266:key immutable once set
PROV_R_KEY_SETUP_FAILED:101:key setup failed
PROV_R_KEY_SIZE_TOO_SMALL:171:key size too small
PROV_R_LENGTH_TOO_LARGE:202:length too large
@@ -1651,25 +1645,24 @@ SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE:1113:\
SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE:1111:tlsv1 certificate unobtainable
SSL_R_TLSV1_UNRECOGNIZED_NAME:1112:tlsv1 unrecognized name
SSL_R_TLSV1_UNSUPPORTED_EXTENSION:1110:tlsv1 unsupported extension
-SSL_R_TLS_ALERT_BAD_CERTIFICATE:1042:ssl/tls alert bad certificate
-SSL_R_TLS_ALERT_BAD_RECORD_MAC:1020:ssl/tls alert bad record mac
-SSL_R_TLS_ALERT_CERTIFICATE_EXPIRED:1045:ssl/tls alert certificate expired
-SSL_R_TLS_ALERT_CERTIFICATE_REVOKED:1044:ssl/tls alert certificate revoked
-SSL_R_TLS_ALERT_CERTIFICATE_UNKNOWN:1046:ssl/tls alert certificate unknown
-SSL_R_TLS_ALERT_DECOMPRESSION_FAILURE:1030:ssl/tls alert decompression failure
-SSL_R_TLS_ALERT_HANDSHAKE_FAILURE:1040:ssl/tls alert handshake failure
-SSL_R_TLS_ALERT_ILLEGAL_PARAMETER:1047:ssl/tls alert illegal parameter
-SSL_R_TLS_ALERT_NO_CERTIFICATE:1041:ssl/tls alert no certificate
-SSL_R_TLS_ALERT_UNEXPECTED_MESSAGE:1010:ssl/tls alert unexpected message
-SSL_R_TLS_ALERT_UNSUPPORTED_CERTIFICATE:1043:\
- ssl/tls alert unsupported certificate
+SSL_R_TLS_ALERT_BAD_CERTIFICATE:1042:tls alert bad certificate
+SSL_R_TLS_ALERT_BAD_RECORD_MAC:1020:tls alert bad record mac
+SSL_R_TLS_ALERT_CERTIFICATE_EXPIRED:1045:tls alert certificate expired
+SSL_R_TLS_ALERT_CERTIFICATE_REVOKED:1044:tls alert certificate revoked
+SSL_R_TLS_ALERT_CERTIFICATE_UNKNOWN:1046:tls alert certificate unknown
+SSL_R_TLS_ALERT_DECOMPRESSION_FAILURE:1030:tls alert decompression failure
+SSL_R_TLS_ALERT_HANDSHAKE_FAILURE:1040:tls alert handshake failure
+SSL_R_TLS_ALERT_ILLEGAL_PARAMETER:1047:tls alert illegal parameter
+SSL_R_TLS_ALERT_NO_CERTIFICATE:1041:tls alert no certificate
+SSL_R_TLS_ALERT_UNEXPECTED_MESSAGE:1010:tls alert unexpected message
+SSL_R_TLS_ALERT_UNSUPPORTED_CERTIFICATE:1043:tls alert unsupported certificate
SSL_R_TLS_EXT_INVALID_MAX_FRAGMENT_LENGTH:232:\
- ssl3 ext invalid max fragment length
-SSL_R_TLS_EXT_INVALID_SERVERNAME:319:ssl3 ext invalid servername
-SSL_R_TLS_EXT_INVALID_SERVERNAME_TYPE:320:ssl3 ext invalid servername type
+ tls ext invalid max fragment length
+SSL_R_TLS_EXT_INVALID_SERVERNAME:319:tls ext invalid servername
+SSL_R_TLS_EXT_INVALID_SERVERNAME_TYPE:320:tls ext invalid servername type
SSL_R_TLS_ILLEGAL_EXPORTER_LABEL:367:tls illegal exporter label
SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST:157:tls invalid ecpointformat list
-SSL_R_TLS_SESSION_ID_TOO_LONG:300:ssl3 session id too long
+SSL_R_TLS_SESSION_ID_TOO_LONG:300:tls session id too long
SSL_R_TOO_MANY_KEY_UPDATES:132:too many key updates
SSL_R_TOO_MANY_WARN_ALERTS:409:too many warn alerts
SSL_R_TOO_MUCH_EARLY_DATA:164:too much early data
diff --git a/crypto/evp/asymcipher.c b/crypto/evp/asymcipher.c
index e31e601c63..ec643bec9e 100644
--- a/crypto/evp/asymcipher.c
+++ b/crypto/evp/asymcipher.c
@@ -19,12 +19,26 @@
static void evp_asym_cipher_free(void *data)
{
- EVP_ASYM_CIPHER_free(data);
+ EVP_ASYM_CIPHER *cipher = (EVP_ASYM_CIPHER *)data;
+ int i;
+
+ if (cipher == NULL)
+ return;
+ CRYPTO_DOWN_REF(&cipher->refcnt, &i);
+ if (i > 0)
+ return;
+ OPENSSL_free(cipher->type_name);
+ ossl_provider_free(cipher->prov);
+ CRYPTO_FREE_REF(&cipher->refcnt);
+ OPENSSL_free(cipher);
}
static int evp_asym_cipher_up_ref(void *data)
{
- return EVP_ASYM_CIPHER_up_ref(data);
+ EVP_ASYM_CIPHER *cipher = (EVP_ASYM_CIPHER *)data;
+ int ref = 0;
+
+ return CRYPTO_UP_REF(&cipher->refcnt, &ref);
}
static int evp_pkey_asym_cipher_init(EVP_PKEY_CTX *ctx, int operation,
@@ -327,7 +341,7 @@ static EVP_ASYM_CIPHER *evp_asym_cipher_new(OSSL_PROVIDER *prov)
static void *evp_asym_cipher_from_algorithm(int name_id,
const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov)
+ OSSL_PROVIDER *prov, int no_store)
{
const OSSL_DISPATCH *fns = algodef->implementation;
EVP_ASYM_CIPHER *cipher = NULL;
@@ -340,6 +354,7 @@ static void *evp_asym_cipher_from_algorithm(int name_id,
}
cipher->name_id = name_id;
+ cipher->no_store = no_store;
if ((cipher->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL)
goto err;
cipher->description = algodef->algorithm_description;
@@ -438,31 +453,29 @@ static void *evp_asym_cipher_from_algorithm(int name_id,
return cipher;
err:
- EVP_ASYM_CIPHER_free(cipher);
+ evp_asym_cipher_free(cipher);
return NULL;
}
void EVP_ASYM_CIPHER_free(EVP_ASYM_CIPHER *cipher)
{
- int i;
-
- if (cipher == NULL)
- return;
- CRYPTO_DOWN_REF(&cipher->refcnt, &i);
- if (i > 0)
- return;
- OPENSSL_free(cipher->type_name);
- ossl_provider_free(cipher->prov);
- CRYPTO_FREE_REF(&cipher->refcnt);
- OPENSSL_free(cipher);
+#ifdef OPENSSL_NO_CACHED_FETCH
+ evp_asym_cipher_free(cipher);
+#else
+ if (cipher != NULL && (cipher->no_store != 0))
+ evp_asym_cipher_free(cipher);
+#endif
}
int EVP_ASYM_CIPHER_up_ref(EVP_ASYM_CIPHER *cipher)
{
- int ref = 0;
-
- CRYPTO_UP_REF(&cipher->refcnt, &ref);
+#ifdef OPENSSL_NO_CACHED_FETCH
+ return evp_asym_cipher_up_ref(cipher);
+#else
+ if (cipher->no_store != 0)
+ return evp_asym_cipher_up_ref(cipher);
return 1;
+#endif
}
OSSL_PROVIDER *EVP_ASYM_CIPHER_get0_provider(const EVP_ASYM_CIPHER *cipher)
diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c
index b6c01daeee..db7121f0a4 100644
--- a/crypto/evp/digest.c
+++ b/crypto/evp/digest.c
@@ -23,6 +23,8 @@
#include
+static void evp_md_free(void *m);
+
void evp_md_ctx_clear_digest(EVP_MD_CTX *ctx, int force, int keep_fetched)
{
if (ctx->algctx != NULL) {
@@ -492,7 +494,8 @@ int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in)
return 0;
}
- if (out->digest == in->digest && in->digest->copyctx != NULL) {
+ if (out->digest == in->digest && in->digest->copyctx != NULL
+ && out->algctx != NULL && in->algctx != NULL) {
in->digest->copyctx(out->algctx, in->algctx);
@@ -829,7 +832,7 @@ static int evp_md_cache_constants(EVP_MD *md)
static void *evp_md_from_algorithm(int name_id,
const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov)
+ OSSL_PROVIDER *prov, int no_store)
{
const OSSL_DISPATCH *fns = algodef->implementation;
EVP_MD *md = NULL;
@@ -841,6 +844,9 @@ static void *evp_md_from_algorithm(int name_id,
return NULL;
}
+ if (no_store != 0)
+ md->flags |= EVP_MD_FLAG_NO_STORE;
+
#ifndef FIPS_MODULE
md->type = NID_undef;
if (!evp_names_do_all(prov, name_id, set_legacy_nid, &md->type)
@@ -965,40 +971,23 @@ static void *evp_md_from_algorithm(int name_id,
return md;
err:
- EVP_MD_free(md);
+ evp_md_free(md);
return NULL;
}
-static int evp_md_up_ref(void *md)
-{
- return EVP_MD_up_ref(md);
-}
-
-static void evp_md_free(void *md)
-{
- EVP_MD_free(md);
-}
-
-EVP_MD *EVP_MD_fetch(OSSL_LIB_CTX *ctx, const char *algorithm,
- const char *properties)
-{
- EVP_MD *md = evp_generic_fetch(ctx, OSSL_OP_DIGEST, algorithm, properties,
- evp_md_from_algorithm, evp_md_up_ref, evp_md_free);
-
- return md;
-}
-
-int EVP_MD_up_ref(EVP_MD *md)
+static int evp_md_up_ref(void *m)
{
+ EVP_MD *md = (EVP_MD *)m;
int ref = 0;
if (md->origin == EVP_ORIG_DYNAMIC)
- CRYPTO_UP_REF(&md->refcnt, &ref);
+ return CRYPTO_UP_REF(&md->refcnt, &ref);
return 1;
}
-void EVP_MD_free(EVP_MD *md)
+static void evp_md_free(void *m)
{
+ EVP_MD *md = (EVP_MD *)m;
int i;
if (md == NULL || md->origin != EVP_ORIG_DYNAMIC)
@@ -1014,6 +1003,37 @@ void EVP_MD_free(EVP_MD *md)
OPENSSL_free(md);
}
+EVP_MD *EVP_MD_fetch(OSSL_LIB_CTX *ctx, const char *algorithm,
+ const char *properties)
+{
+ EVP_MD *md = evp_generic_fetch(ctx, OSSL_OP_DIGEST, algorithm, properties,
+ evp_md_from_algorithm, evp_md_up_ref, evp_md_free);
+
+ return md;
+}
+
+int EVP_MD_up_ref(EVP_MD *md)
+{
+#ifdef OPENSSL_NO_CACHED_FETCH
+ return evp_md_up_ref(md);
+#else
+ if (md->flags & EVP_MD_FLAG_NO_STORE)
+ return evp_md_up_ref(md);
+ return 1;
+#endif
+}
+
+void EVP_MD_free(EVP_MD *md)
+{
+#ifdef OPENSSL_NO_CACHED_FETCH
+ evp_md_free(md);
+#else
+ if (md != NULL && (md->flags & EVP_MD_FLAG_NO_STORE))
+ evp_md_free(md);
+ return;
+#endif
+}
+
void EVP_MD_do_all_provided(OSSL_LIB_CTX *libctx,
void (*fn)(EVP_MD *mac, void *arg),
void *arg)
diff --git a/crypto/evp/e_chacha20_poly1305.c b/crypto/evp/e_chacha20_poly1305.c
index 628f89bbdc..78dbe45ce4 100644
--- a/crypto/evp/e_chacha20_poly1305.c
+++ b/crypto/evp/e_chacha20_poly1305.c
@@ -41,7 +41,7 @@ static const EVP_CIPHER chacha20_poly1305 = {
const EVP_CIPHER *EVP_chacha20_poly1305(void)
{
- return (&chacha20_poly1305);
+ return &chacha20_poly1305;
}
#endif
#else
diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c
index a23846fdf1..a5c513db0d 100644
--- a/crypto/evp/evp_enc.c
+++ b/crypto/evp/evp_enc.c
@@ -1340,9 +1340,33 @@ static void set_legacy_nid(const char *name, void *vlegacy_nid)
}
#endif
+static int evp_cipher_up_ref(void *c)
+{
+ EVP_CIPHER *cipher = (EVP_CIPHER *)c;
+ int ref = 0;
+
+ if (cipher->origin == EVP_ORIG_DYNAMIC)
+ return CRYPTO_UP_REF(&cipher->refcnt, &ref);
+ return 1;
+}
+
+static void evp_cipher_free(void *c)
+{
+ EVP_CIPHER *cipher = (EVP_CIPHER *)c;
+ int i;
+
+ if (cipher == NULL || cipher->origin != EVP_ORIG_DYNAMIC)
+ return;
+
+ CRYPTO_DOWN_REF(&cipher->refcnt, &i);
+ if (i > 0)
+ return;
+ evp_cipher_free_int(cipher);
+}
+
static void *evp_cipher_from_algorithm(const int name_id,
const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov)
+ OSSL_PROVIDER *prov, int no_store)
{
const OSSL_DISPATCH *fns = algodef->implementation;
EVP_CIPHER *cipher = NULL;
@@ -1353,6 +1377,9 @@ static void *evp_cipher_from_algorithm(const int name_id,
return NULL;
}
+ if (no_store != 0)
+ cipher->flags |= EVP_CIPH_FLAG_NO_STORE;
+
#ifndef FIPS_MODULE
cipher->nid = NID_undef;
if (!evp_names_do_all(prov, name_id, set_legacy_nid, &cipher->nid)
@@ -1511,20 +1538,10 @@ static void *evp_cipher_from_algorithm(const int name_id,
return cipher;
err:
- EVP_CIPHER_free(cipher);
+ evp_cipher_free(cipher);
return NULL;
}
-static int evp_cipher_up_ref(void *cipher)
-{
- return EVP_CIPHER_up_ref(cipher);
-}
-
-static void evp_cipher_free(void *cipher)
-{
- EVP_CIPHER_free(cipher);
-}
-
EVP_CIPHER *EVP_CIPHER_fetch(OSSL_LIB_CTX *ctx, const char *algorithm,
const char *properties)
{
@@ -1557,11 +1574,13 @@ int EVP_CIPHER_can_pipeline(const EVP_CIPHER *cipher, int enc)
int EVP_CIPHER_up_ref(EVP_CIPHER *cipher)
{
- int ref = 0;
-
- if (cipher->origin == EVP_ORIG_DYNAMIC)
- CRYPTO_UP_REF(&cipher->refcnt, &ref);
+#ifdef OPENSSL_NO_CACHED_FETCH
+ return evp_cipher_up_ref(cipher);
+#else
+ if (cipher->flags & EVP_CIPH_FLAG_NO_STORE)
+ return evp_cipher_up_ref(cipher);
return 1;
+#endif
}
void evp_cipher_free_int(EVP_CIPHER *cipher)
@@ -1574,15 +1593,12 @@ void evp_cipher_free_int(EVP_CIPHER *cipher)
void EVP_CIPHER_free(EVP_CIPHER *cipher)
{
- int i;
-
- if (cipher == NULL || cipher->origin != EVP_ORIG_DYNAMIC)
- return;
-
- CRYPTO_DOWN_REF(&cipher->refcnt, &i);
- if (i > 0)
- return;
- evp_cipher_free_int(cipher);
+#ifdef OPENSSL_NO_CACHED_FETCH
+ evp_cipher_free(cipher);
+#else
+ if (cipher != NULL && (cipher->flags & EVP_CIPH_FLAG_NO_STORE))
+ evp_cipher_free(cipher);
+#endif
}
void EVP_CIPHER_do_all_provided(OSSL_LIB_CTX *libctx,
diff --git a/crypto/evp/evp_fetch.c b/crypto/evp/evp_fetch.c
index a446f976df..15204628db 100644
--- a/crypto/evp/evp_fetch.c
+++ b/crypto/evp/evp_fetch.c
@@ -11,6 +11,7 @@
#include
#include
#include
+#include
#include "internal/cryptlib.h"
#include "internal/thread_once.h"
#include "internal/property.h"
@@ -36,7 +37,7 @@ struct evp_method_data_st {
unsigned int flag_construct_error_occurred : 1;
void *(*method_from_algorithm)(int name_id, const OSSL_ALGORITHM *,
- OSSL_PROVIDER *);
+ OSSL_PROVIDER *, int);
int (*refcnt_up_method)(void *method);
void (*destruct_method)(void *method);
};
@@ -208,7 +209,7 @@ static int put_evp_method_in_store(void *store, void *method,
* This function is responsible to getting an identity number for it.
*/
static void *construct_evp_method(const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov, void *data)
+ OSSL_PROVIDER *prov, void *data, int no_store)
{
/*
* This function is only called if get_evp_method_from_store() returned
@@ -227,7 +228,7 @@ static void *construct_evp_method(const OSSL_ALGORITHM *algodef,
if (name_id == 0)
return NULL;
- method = methdata->method_from_algorithm(name_id, algodef, prov);
+ method = methdata->method_from_algorithm(name_id, algodef, prov, no_store);
/*
* Flag to indicate that there was actual construction errors. This
@@ -253,7 +254,7 @@ inner_evp_generic_fetch(struct evp_method_data_st *methdata,
const char *name, ossl_unused const char *properties,
void *(*new_method)(int name_id,
const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov),
+ OSSL_PROVIDER *prov, int no_store),
int (*up_ref_method)(void *),
void (*free_method)(void *))
{
@@ -351,7 +352,9 @@ inner_evp_generic_fetch(struct evp_method_data_st *methdata,
if (name_id == 0) {
ERR_raise_data(ERR_LIB_EVP, ERR_R_FETCH_FAILED,
"Algorithm %s cannot be found", name != NULL ? name : "");
+#ifdef OPENSSL_NO_CACHED_FETCH
free_method(method);
+#endif
method = NULL;
} else {
meth_id = evp_method_id(name_id, operation_id);
@@ -361,9 +364,70 @@ inner_evp_generic_fetch(struct evp_method_data_st *methdata,
* cached end up in ->tmp_store when provider asks not
* to cache the result (see ossl_method_construct_reserve_store())
*/
- if (meth_id != 0 && methdata->tmp_store == NULL)
+ if (meth_id != 0 && methdata->tmp_store == NULL) {
ossl_method_store_cache_set(store, prov, meth_id, propq,
method, up_ref_method, free_method);
+ } else {
+#ifndef OPENSSL_NO_CACHED_FETCH
+ /*
+ * There is a corner case we need to handle here. IF:
+ * 1) we are fetching an algorithm and plan to return it to the caller
+ * 2) The provider we fetched from requested no_cache
+ * Then we are in a situation in which this method that was constructed
+ * only lives in the tmp_store, and has a reference count of 1.
+ * On return from this function, that tmp_store is going to be deallocated,
+ * Which will drop the methods ref count to 0 and free it, after which the
+ * method will be returned to the called, as an already freed object.
+ *
+ * That's bad. We need to grab an extra ref count on the method before returning
+ * so that the requestor via EVP_*_fetch has ownership.
+ *
+ * BUT we only want to do this in the event that the algorithm is uncached.
+ * Unfortunately, we don't know that here, because it was the provider that
+ * made that request. However, each algorithm type does store that information
+ * so we have a path forward. Based on the operation id, call the appropriate
+ * up_ref method. That implementation knows how to query its algorithm type and
+ * decide if a reference needs to be taken here
+ */
+ switch (operation_id) {
+ case OSSL_OP_DIGEST:
+ EVP_MD_up_ref((EVP_MD *)method);
+ break;
+ case OSSL_OP_CIPHER:
+ EVP_CIPHER_up_ref((EVP_CIPHER *)method);
+ break;
+ case OSSL_OP_MAC:
+ EVP_MAC_up_ref((EVP_MAC *)method);
+ break;
+ case OSSL_OP_KDF:
+ EVP_KDF_up_ref((EVP_KDF *)method);
+ break;
+ case OSSL_OP_RAND:
+ EVP_RAND_up_ref((EVP_RAND *)method);
+ break;
+ case OSSL_OP_KEYMGMT:
+ EVP_KEYMGMT_up_ref((EVP_KEYMGMT *)method);
+ break;
+ case OSSL_OP_KEYEXCH:
+ EVP_KEYEXCH_up_ref((EVP_KEYEXCH *)method);
+ break;
+ case OSSL_OP_SIGNATURE:
+ EVP_SIGNATURE_up_ref((EVP_SIGNATURE *)method);
+ break;
+ case OSSL_OP_ASYM_CIPHER:
+ EVP_ASYM_CIPHER_up_ref((EVP_ASYM_CIPHER *)method);
+ break;
+ case OSSL_OP_KEM:
+ EVP_KEM_up_ref((EVP_KEM *)method);
+ break;
+ case OSSL_OP_SKEYMGMT:
+ EVP_SKEYMGMT_up_ref((EVP_SKEYMGMT *)method);
+ break;
+ default:
+ break;
+ }
+#endif
+ }
}
}
@@ -398,7 +462,7 @@ void *evp_generic_fetch(OSSL_LIB_CTX *libctx, int operation_id,
const char *name, const char *properties,
void *(*new_method)(int name_id,
const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov),
+ OSSL_PROVIDER *prov, int no_store),
int (*up_ref_method)(void *),
void (*free_method)(void *))
{
@@ -424,7 +488,7 @@ void *evp_generic_fetch_from_prov(OSSL_PROVIDER *prov, int operation_id,
const char *name, const char *properties,
void *(*new_method)(int name_id,
const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov),
+ OSSL_PROVIDER *prov, int no_store),
int (*up_ref_method)(void *),
void (*free_method)(void *))
{
@@ -638,7 +702,7 @@ void evp_generic_do_all(OSSL_LIB_CTX *libctx, int operation_id,
void *user_arg,
void *(*new_method)(int name_id,
const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov),
+ OSSL_PROVIDER *prov, int no_store),
int (*up_ref_method)(void *),
void (*free_method)(void *))
{
diff --git a/crypto/evp/evp_lib.c b/crypto/evp/evp_lib.c
index 076efb30d1..644772bf37 100644
--- a/crypto/evp/evp_lib.c
+++ b/crypto/evp/evp_lib.c
@@ -310,6 +310,7 @@ int evp_cipher_cache_constants(EVP_CIPHER *cipher)
size_t blksz = 0;
size_t keylen = 0;
unsigned int mode = 0;
+ int no_store = cipher->flags & EVP_CIPH_FLAG_NO_STORE;
OSSL_PARAM params[11];
params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_BLOCK_SIZE, &blksz);
@@ -332,7 +333,7 @@ int evp_cipher_cache_constants(EVP_CIPHER *cipher)
cipher->block_size = (int)blksz;
cipher->iv_len = (int)ivlen;
cipher->key_len = (int)keylen;
- cipher->flags = mode;
+ cipher->flags = mode | no_store;
if (aead)
cipher->flags |= EVP_CIPH_FLAG_AEAD_CIPHER;
if (custom_iv)
diff --git a/crypto/evp/evp_local.h b/crypto/evp/evp_local.h
index d4a72b7527..1f41cfe644 100644
--- a/crypto/evp/evp_local.h
+++ b/crypto/evp/evp_local.h
@@ -102,6 +102,7 @@ struct evp_keymgmt_st {
int id; /* libcrypto internal */
int name_id;
+ int no_store;
/* NID for the legacy alg if there is one */
int legacy_alg;
char *type_name;
@@ -148,6 +149,7 @@ struct evp_keymgmt_st {
struct evp_keyexch_st {
int name_id;
+ int no_store;
char *type_name;
const char *description;
OSSL_PROVIDER *prov;
@@ -168,6 +170,7 @@ struct evp_keyexch_st {
struct evp_signature_st {
int name_id;
+ int no_store;
char *type_name;
const char *description;
OSSL_PROVIDER *prov;
@@ -211,6 +214,7 @@ struct evp_signature_st {
struct evp_skeymgmt_st {
int name_id;
+ int no_store;
char *type_name;
const char *description;
OSSL_PROVIDER *prov;
@@ -234,6 +238,7 @@ struct evp_skeymgmt_st {
struct evp_asym_cipher_st {
int name_id;
+ int no_store;
char *type_name;
const char *description;
OSSL_PROVIDER *prov;
@@ -254,6 +259,7 @@ struct evp_asym_cipher_st {
struct evp_kem_st {
int name_id;
+ int no_store;
char *type_name;
const char *description;
OSSL_PROVIDER *prov;
@@ -305,14 +311,14 @@ void *evp_generic_fetch(OSSL_LIB_CTX *ctx, int operation_id,
const char *name, const char *properties,
void *(*new_method)(int name_id,
const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov),
+ OSSL_PROVIDER *prov, int no_store),
int (*up_ref_method)(void *),
void (*free_method)(void *));
void *evp_generic_fetch_from_prov(OSSL_PROVIDER *prov, int operation_id,
const char *name, const char *properties,
void *(*new_method)(int name_id,
const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov),
+ OSSL_PROVIDER *prov, int no_store),
int (*up_ref_method)(void *),
void (*free_method)(void *));
void evp_generic_do_all_prefetched(OSSL_LIB_CTX *libctx, int operation_id,
@@ -323,7 +329,7 @@ void evp_generic_do_all(OSSL_LIB_CTX *libctx, int operation_id,
void *user_arg,
void *(*new_method)(int name_id,
const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov),
+ OSSL_PROVIDER *prov, int no_store),
int (*up_ref_method)(void *),
void (*free_method)(void *));
diff --git a/crypto/evp/evp_rand.c b/crypto/evp/evp_rand.c
index 623b87135a..a0041719b5 100644
--- a/crypto/evp/evp_rand.c
+++ b/crypto/evp/evp_rand.c
@@ -24,6 +24,7 @@
struct evp_rand_st {
OSSL_PROVIDER *prov;
int name_id;
+ int no_store;
char *type_name;
const char *description;
CRYPTO_REF_COUNT refcnt;
@@ -116,7 +117,7 @@ static void evp_rand_unlock(EVP_RAND_CTX *rand)
static void *evp_rand_from_algorithm(int name_id,
const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov)
+ OSSL_PROVIDER *prov, int no_store)
{
const OSSL_DISPATCH *fns = algodef->implementation;
EVP_RAND *rand = NULL;
@@ -130,6 +131,7 @@ static void *evp_rand_from_algorithm(int name_id,
return NULL;
}
rand->name_id = name_id;
+ rand->no_store = no_store;
if ((rand->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL) {
evp_rand_free(rand);
return NULL;
@@ -289,12 +291,23 @@ EVP_RAND *EVP_RAND_fetch(OSSL_LIB_CTX *libctx, const char *algorithm,
int EVP_RAND_up_ref(EVP_RAND *rand)
{
+#ifdef OPENSSL_NO_CACHED_FETCH
return evp_rand_up_ref(rand);
+#else
+ if (rand->no_store != 0)
+ return evp_rand_up_ref(rand);
+ return 1;
+#endif
}
void EVP_RAND_free(EVP_RAND *rand)
{
+#ifdef OPENSSL_NO_CACHED_FETCH
evp_rand_free(rand);
+#else
+ if (rand != NULL && (rand->no_store != 0))
+ evp_rand_free(rand);
+#endif
}
int evp_rand_get_number(const EVP_RAND *rand)
diff --git a/crypto/evp/exchange.c b/crypto/evp/exchange.c
index 849bc21514..8718726076 100644
--- a/crypto/evp/exchange.c
+++ b/crypto/evp/exchange.c
@@ -21,12 +21,26 @@
static void evp_keyexch_free(void *data)
{
- EVP_KEYEXCH_free(data);
+ EVP_KEYEXCH *exchange = (EVP_KEYEXCH *)data;
+ int i;
+
+ if (exchange == NULL)
+ return;
+ CRYPTO_DOWN_REF(&exchange->refcnt, &i);
+ if (i > 0)
+ return;
+ OPENSSL_free(exchange->type_name);
+ ossl_provider_free(exchange->prov);
+ CRYPTO_FREE_REF(&exchange->refcnt);
+ OPENSSL_free(exchange);
}
static int evp_keyexch_up_ref(void *data)
{
- return EVP_KEYEXCH_up_ref(data);
+ EVP_KEYEXCH *exchange = (EVP_KEYEXCH *)data;
+ int ref = 0;
+
+ return CRYPTO_UP_REF(&exchange->refcnt, &ref);
}
static EVP_KEYEXCH *evp_keyexch_new(OSSL_PROVIDER *prov)
@@ -49,7 +63,7 @@ static EVP_KEYEXCH *evp_keyexch_new(OSSL_PROVIDER *prov)
static void *evp_keyexch_from_algorithm(int name_id,
const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov)
+ OSSL_PROVIDER *prov, int no_store)
{
const OSSL_DISPATCH *fns = algodef->implementation;
EVP_KEYEXCH *exchange = NULL;
@@ -61,6 +75,7 @@ static void *evp_keyexch_from_algorithm(int name_id,
}
exchange->name_id = name_id;
+ exchange->no_store = no_store;
if ((exchange->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL)
goto err;
exchange->description = algodef->algorithm_description;
@@ -154,31 +169,29 @@ static void *evp_keyexch_from_algorithm(int name_id,
return exchange;
err:
- EVP_KEYEXCH_free(exchange);
+ evp_keyexch_free(exchange);
return NULL;
}
void EVP_KEYEXCH_free(EVP_KEYEXCH *exchange)
{
- int i;
-
- if (exchange == NULL)
- return;
- CRYPTO_DOWN_REF(&exchange->refcnt, &i);
- if (i > 0)
- return;
- OPENSSL_free(exchange->type_name);
- ossl_provider_free(exchange->prov);
- CRYPTO_FREE_REF(&exchange->refcnt);
- OPENSSL_free(exchange);
+#ifdef OPENSSL_NO_CACHED_FETCH
+ evp_keyexch_free(exchange);
+#else
+ if (exchange != NULL && (exchange->no_store != 0))
+ evp_keyexch_free(exchange);
+#endif
}
int EVP_KEYEXCH_up_ref(EVP_KEYEXCH *exchange)
{
- int ref = 0;
-
- CRYPTO_UP_REF(&exchange->refcnt, &ref);
+#ifdef OPENSSL_NO_CACHED_FETCH
+ return evp_keyexch_up_ref(exchange);
+#else
+ if (exchange->no_store != 0)
+ return evp_keyexch_up_ref(exchange);
return 1;
+#endif
}
OSSL_PROVIDER *EVP_KEYEXCH_get0_provider(const EVP_KEYEXCH *exchange)
diff --git a/crypto/evp/kdf_lib.c b/crypto/evp/kdf_lib.c
index 4c98942992..67351044fb 100644
--- a/crypto/evp/kdf_lib.c
+++ b/crypto/evp/kdf_lib.c
@@ -104,11 +104,25 @@ const OSSL_PROVIDER *EVP_KDF_get0_provider(const EVP_KDF *kdf)
return kdf->prov;
}
-const EVP_KDF *EVP_KDF_CTX_kdf(EVP_KDF_CTX *ctx)
+const EVP_KDF *EVP_KDF_CTX_get0_kdf(const EVP_KDF_CTX *ctx)
{
return ctx->meth;
}
+#if !defined(OPENSSL_NO_DEPRECATED_4_1)
+const EVP_KDF *EVP_KDF_CTX_kdf(const EVP_KDF_CTX *ctx)
+{
+ return EVP_KDF_CTX_get0_kdf(ctx);
+}
+#endif /* !OPENSSL_NO_DEPRECATED_4_1 */
+
+EVP_KDF *EVP_KDF_CTX_get1_kdf(const EVP_KDF_CTX *ctx)
+{
+ if (!EVP_KDF_up_ref(ctx->meth))
+ return NULL;
+ return ctx->meth;
+}
+
void EVP_KDF_CTX_reset(EVP_KDF_CTX *ctx)
{
if (ctx == NULL)
diff --git a/crypto/evp/kdf_meth.c b/crypto/evp/kdf_meth.c
index 31680ee664..c6df2971db 100644
--- a/crypto/evp/kdf_meth.c
+++ b/crypto/evp/kdf_meth.c
@@ -22,8 +22,7 @@ static int evp_kdf_up_ref(void *vkdf)
EVP_KDF *kdf = (EVP_KDF *)vkdf;
int ref = 0;
- CRYPTO_UP_REF(&kdf->refcnt, &ref);
- return 1;
+ return CRYPTO_UP_REF(&kdf->refcnt, &ref);
}
static void evp_kdf_free(void *vkdf)
@@ -57,7 +56,7 @@ static void *evp_kdf_new(void)
static void *evp_kdf_from_algorithm(int name_id,
const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov)
+ OSSL_PROVIDER *prov, int no_store)
{
const OSSL_DISPATCH *fns = algodef->implementation;
EVP_KDF *kdf = NULL;
@@ -68,6 +67,8 @@ static void *evp_kdf_from_algorithm(int name_id,
return NULL;
}
kdf->name_id = name_id;
+ kdf->no_store = no_store;
+
if ((kdf->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL)
goto err;
@@ -176,12 +177,23 @@ EVP_KDF *EVP_KDF_fetch(OSSL_LIB_CTX *libctx, const char *algorithm,
int EVP_KDF_up_ref(EVP_KDF *kdf)
{
+#ifdef OPENSSL_NO_CACHED_FETCH
return evp_kdf_up_ref(kdf);
+#else
+ if (kdf->no_store != 0)
+ return evp_kdf_up_ref(kdf);
+ return 1;
+#endif
}
void EVP_KDF_free(EVP_KDF *kdf)
{
+#ifdef OPENSSL_NO_CACHED_FETCH
evp_kdf_free(kdf);
+#else
+ if (kdf != NULL && (kdf->no_store != 0))
+ evp_kdf_free(kdf);
+#endif
}
const OSSL_PARAM *EVP_KDF_gettable_params(const EVP_KDF *kdf)
diff --git a/crypto/evp/kem.c b/crypto/evp/kem.c
index 92db961892..8ae968d5a5 100644
--- a/crypto/evp/kem.c
+++ b/crypto/evp/kem.c
@@ -19,12 +19,27 @@
static void evp_kem_free(void *data)
{
- EVP_KEM_free(data);
+ EVP_KEM *kem = (EVP_KEM *)data;
+ int i;
+
+ if (kem == NULL)
+ return;
+
+ CRYPTO_DOWN_REF(&kem->refcnt, &i);
+ if (i > 0)
+ return;
+ OPENSSL_free(kem->type_name);
+ ossl_provider_free(kem->prov);
+ CRYPTO_FREE_REF(&kem->refcnt);
+ OPENSSL_free(kem);
}
static int evp_kem_up_ref(void *data)
{
- return EVP_KEM_up_ref(data);
+ EVP_KEM *kem = (EVP_KEM *)data;
+ int ref = 0;
+
+ return CRYPTO_UP_REF(&kem->refcnt, &ref);
}
static int evp_kem_init(EVP_PKEY_CTX *ctx, int operation,
@@ -301,7 +316,7 @@ static EVP_KEM *evp_kem_new(OSSL_PROVIDER *prov)
}
static void *evp_kem_from_algorithm(int name_id, const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov)
+ OSSL_PROVIDER *prov, int no_store)
{
const OSSL_DISPATCH *fns = algodef->implementation;
EVP_KEM *kem = NULL;
@@ -314,6 +329,8 @@ static void *evp_kem_from_algorithm(int name_id, const OSSL_ALGORITHM *algodef,
}
kem->name_id = name_id;
+ kem->no_store = no_store;
+
if ((kem->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL)
goto err;
kem->description = algodef->algorithm_description;
@@ -426,32 +443,29 @@ static void *evp_kem_from_algorithm(int name_id, const OSSL_ALGORITHM *algodef,
return kem;
err:
- EVP_KEM_free(kem);
+ evp_kem_free(kem);
return NULL;
}
void EVP_KEM_free(EVP_KEM *kem)
{
- int i;
-
- if (kem == NULL)
- return;
-
- CRYPTO_DOWN_REF(&kem->refcnt, &i);
- if (i > 0)
- return;
- OPENSSL_free(kem->type_name);
- ossl_provider_free(kem->prov);
- CRYPTO_FREE_REF(&kem->refcnt);
- OPENSSL_free(kem);
+#ifdef OPENSSL_NO_CACHED_FETCH
+ evp_kem_free(kem);
+#else
+ if (kem != NULL && (kem->no_store != 0))
+ evp_kem_free(kem);
+#endif
}
int EVP_KEM_up_ref(EVP_KEM *kem)
{
- int ref = 0;
-
- CRYPTO_UP_REF(&kem->refcnt, &ref);
+#ifdef OPENSSL_NO_CACHED_FETCH
+ return evp_kem_up_ref(kem);
+#else
+ if (kem->no_store != 0)
+ return evp_kem_up_ref(kem);
return 1;
+#endif
}
OSSL_PROVIDER *EVP_KEM_get0_provider(const EVP_KEM *kem)
diff --git a/crypto/evp/keymgmt_meth.c b/crypto/evp/keymgmt_meth.c
index e7f00d091f..9cf4ef5e4f 100644
--- a/crypto/evp/keymgmt_meth.c
+++ b/crypto/evp/keymgmt_meth.c
@@ -19,12 +19,27 @@
static void evp_keymgmt_free(void *data)
{
- EVP_KEYMGMT_free(data);
+ EVP_KEYMGMT *keymgmt = (EVP_KEYMGMT *)data;
+ int ref = 0;
+
+ if (keymgmt == NULL)
+ return;
+
+ CRYPTO_DOWN_REF(&keymgmt->refcnt, &ref);
+ if (ref > 0)
+ return;
+ OPENSSL_free(keymgmt->type_name);
+ ossl_provider_free(keymgmt->prov);
+ CRYPTO_FREE_REF(&keymgmt->refcnt);
+ OPENSSL_free(keymgmt);
}
static int evp_keymgmt_up_ref(void *data)
{
- return EVP_KEYMGMT_up_ref(data);
+ EVP_KEYMGMT *keymgmt = (EVP_KEYMGMT *)data;
+ int ref = 0;
+
+ return CRYPTO_UP_REF(&keymgmt->refcnt, &ref);
}
static void *keymgmt_new(void)
@@ -34,7 +49,7 @@ static void *keymgmt_new(void)
if ((keymgmt = OPENSSL_zalloc(sizeof(*keymgmt))) == NULL)
return NULL;
if (!CRYPTO_NEW_REF(&keymgmt->refcnt, 1)) {
- EVP_KEYMGMT_free(keymgmt);
+ OPENSSL_free(keymgmt);
return NULL;
}
return keymgmt;
@@ -62,7 +77,7 @@ static int get_legacy_alg_type_from_keymgmt(const EVP_KEYMGMT *keymgmt)
static void *keymgmt_from_algorithm(int name_id,
const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov)
+ OSSL_PROVIDER *prov, int no_store)
{
const OSSL_DISPATCH *fns = algodef->implementation;
EVP_KEYMGMT *keymgmt = NULL;
@@ -76,8 +91,10 @@ static void *keymgmt_from_algorithm(int name_id,
return NULL;
keymgmt->name_id = name_id;
+ keymgmt->no_store = no_store;
+
if ((keymgmt->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL) {
- EVP_KEYMGMT_free(keymgmt);
+ evp_keymgmt_free(keymgmt);
return NULL;
}
keymgmt->description = algodef->algorithm_description;
@@ -253,13 +270,13 @@ static void *keymgmt_from_algorithm(int name_id,
|| (keymgmt->gen != NULL
&& (keymgmt->gen_init == NULL
|| keymgmt->gen_cleanup == NULL))) {
- EVP_KEYMGMT_free(keymgmt);
+ evp_keymgmt_free(keymgmt);
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS);
return NULL;
}
keymgmt->prov = prov;
if (prov != NULL && !ossl_provider_up_ref(prov)) {
- EVP_KEYMGMT_free(keymgmt);
+ evp_keymgmt_free(keymgmt);
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
return NULL;
}
@@ -293,26 +310,23 @@ EVP_KEYMGMT *EVP_KEYMGMT_fetch(OSSL_LIB_CTX *ctx, const char *algorithm,
int EVP_KEYMGMT_up_ref(EVP_KEYMGMT *keymgmt)
{
- int ref = 0;
-
- CRYPTO_UP_REF(&keymgmt->refcnt, &ref);
+#ifdef OPENSSL_NO_CACHED_FETCH
+ return evp_keymgmt_up_ref(keymgmt);
+#else
+ if (keymgmt->no_store != 0)
+ return evp_keymgmt_up_ref(keymgmt);
return 1;
+#endif
}
void EVP_KEYMGMT_free(EVP_KEYMGMT *keymgmt)
{
- int ref = 0;
-
- if (keymgmt == NULL)
- return;
-
- CRYPTO_DOWN_REF(&keymgmt->refcnt, &ref);
- if (ref > 0)
- return;
- OPENSSL_free(keymgmt->type_name);
- ossl_provider_free(keymgmt->prov);
- CRYPTO_FREE_REF(&keymgmt->refcnt);
- OPENSSL_free(keymgmt);
+#ifdef OPENSSL_NO_CACHED_FETCH
+ evp_keymgmt_free(keymgmt);
+#else
+ if (keymgmt != NULL && (keymgmt->no_store != 0))
+ evp_keymgmt_free(keymgmt);
+#endif
}
const OSSL_PROVIDER *EVP_KEYMGMT_get0_provider(const EVP_KEYMGMT *keymgmt)
diff --git a/crypto/evp/mac_meth.c b/crypto/evp/mac_meth.c
index ba47e95870..2a6fb0abe5 100644
--- a/crypto/evp/mac_meth.c
+++ b/crypto/evp/mac_meth.c
@@ -21,8 +21,7 @@ static int evp_mac_up_ref(void *vmac)
EVP_MAC *mac = vmac;
int ref = 0;
- CRYPTO_UP_REF(&mac->refcnt, &ref);
- return 1;
+ return CRYPTO_UP_REF(&mac->refcnt, &ref);
}
static void evp_mac_free(void *vmac)
@@ -56,7 +55,7 @@ static void *evp_mac_new(void)
static void *evp_mac_from_algorithm(int name_id,
const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov)
+ OSSL_PROVIDER *prov, int no_store)
{
const OSSL_DISPATCH *fns = algodef->implementation;
EVP_MAC *mac = NULL;
@@ -67,6 +66,7 @@ static void *evp_mac_from_algorithm(int name_id,
goto err;
}
mac->name_id = name_id;
+ mac->no_store = no_store;
if ((mac->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL)
goto err;
@@ -182,12 +182,23 @@ EVP_MAC *EVP_MAC_fetch(OSSL_LIB_CTX *libctx, const char *algorithm,
int EVP_MAC_up_ref(EVP_MAC *mac)
{
+#ifdef OPENSSL_NO_CACHED_FETCH
return evp_mac_up_ref(mac);
+#else
+ if (mac->no_store != 0)
+ return evp_mac_up_ref(mac);
+ return 1;
+#endif
}
void EVP_MAC_free(EVP_MAC *mac)
{
+#ifdef OPENSSL_NO_CACHED_FETCH
evp_mac_free(mac);
+#else
+ if (mac != NULL && (mac->no_store != 0))
+ evp_mac_free(mac);
+#endif
}
const OSSL_PROVIDER *EVP_MAC_get0_provider(const EVP_MAC *mac)
diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c
index fcf64ed004..f13390b54e 100644
--- a/crypto/evp/p_lib.c
+++ b/crypto/evp/p_lib.c
@@ -1630,7 +1630,7 @@ int EVP_PKEY_up_ref(EVP_PKEY *pkey)
{
int i;
- if (CRYPTO_UP_REF(&pkey->references, &i) <= 0)
+ if (!CRYPTO_UP_REF(&pkey->references, &i))
return 0;
REF_PRINT_COUNT("EVP_PKEY", i, pkey);
@@ -2405,13 +2405,10 @@ int EVP_PKEY_get_ec_point_conv_form(const EVP_PKEY *pkey)
/* Might work through the legacy route */
const EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey);
- if (ec == NULL)
- return 0;
-
- return EC_KEY_get_conv_form(ec);
-#else
- return 0;
+ if (ec != NULL)
+ return EC_KEY_get_conv_form(ec);
#endif
+ return 0;
}
if (!EVP_PKEY_get_utf8_string_param(pkey,
diff --git a/crypto/evp/s_lib.c b/crypto/evp/s_lib.c
index 5594dc81c5..3f76136324 100644
--- a/crypto/evp/s_lib.c
+++ b/crypto/evp/s_lib.c
@@ -196,7 +196,7 @@ int EVP_SKEY_up_ref(EVP_SKEY *skey)
{
int i;
- if (CRYPTO_UP_REF(&skey->references, &i) <= 0)
+ if (!CRYPTO_UP_REF(&skey->references, &i))
return 0;
REF_PRINT_COUNT("EVP_SKEY", i, skey);
diff --git a/crypto/evp/signature.c b/crypto/evp/signature.c
index 3737bc6ba4..6c6aad7e92 100644
--- a/crypto/evp/signature.c
+++ b/crypto/evp/signature.c
@@ -22,12 +22,26 @@
static void evp_signature_free(void *data)
{
- EVP_SIGNATURE_free(data);
+ EVP_SIGNATURE *signature = (EVP_SIGNATURE *)data;
+ int i;
+
+ if (signature == NULL)
+ return;
+ CRYPTO_DOWN_REF(&signature->refcnt, &i);
+ if (i > 0)
+ return;
+ OPENSSL_free(signature->type_name);
+ ossl_provider_free(signature->prov);
+ CRYPTO_FREE_REF(&signature->refcnt);
+ OPENSSL_free(signature);
}
static int evp_signature_up_ref(void *data)
{
- return EVP_SIGNATURE_up_ref(data);
+ EVP_SIGNATURE *signature = (EVP_SIGNATURE *)data;
+ int ref = 0;
+
+ return CRYPTO_UP_REF(&signature->refcnt, &ref);
}
static EVP_SIGNATURE *evp_signature_new(OSSL_PROVIDER *prov)
@@ -51,7 +65,7 @@ static EVP_SIGNATURE *evp_signature_new(OSSL_PROVIDER *prov)
static void *evp_signature_from_algorithm(int name_id,
const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov)
+ OSSL_PROVIDER *prov, int no_store)
{
const OSSL_DISPATCH *fns = algodef->implementation;
EVP_SIGNATURE *signature = NULL;
@@ -70,6 +84,7 @@ static void *evp_signature_from_algorithm(int name_id,
}
signature->name_id = name_id;
+ signature->no_store = no_store;
if ((signature->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL)
goto err;
signature->description = algodef->algorithm_description;
@@ -448,31 +463,29 @@ static void *evp_signature_from_algorithm(int name_id,
return signature;
err:
- EVP_SIGNATURE_free(signature);
+ evp_signature_free(signature);
return NULL;
}
void EVP_SIGNATURE_free(EVP_SIGNATURE *signature)
{
- int i;
-
- if (signature == NULL)
- return;
- CRYPTO_DOWN_REF(&signature->refcnt, &i);
- if (i > 0)
- return;
- OPENSSL_free(signature->type_name);
- ossl_provider_free(signature->prov);
- CRYPTO_FREE_REF(&signature->refcnt);
- OPENSSL_free(signature);
+#ifdef OPENSSL_NO_CACHED_FETCH
+ evp_signature_free(signature);
+#else
+ if (signature != NULL && (signature->no_store != 0))
+ evp_signature_free(signature);
+#endif
}
int EVP_SIGNATURE_up_ref(EVP_SIGNATURE *signature)
{
- int ref = 0;
-
- CRYPTO_UP_REF(&signature->refcnt, &ref);
+#ifdef OPENSSL_NO_CACHED_FETCH
+ return evp_signature_up_ref(signature);
+#else
+ if (signature->no_store != 0)
+ return evp_signature_up_ref(signature);
return 1;
+#endif
}
OSSL_PROVIDER *EVP_SIGNATURE_get0_provider(const EVP_SIGNATURE *signature)
diff --git a/crypto/evp/skeymgmt_meth.c b/crypto/evp/skeymgmt_meth.c
index 75c4fef675..dbc14c0e0d 100644
--- a/crypto/evp/skeymgmt_meth.c
+++ b/crypto/evp/skeymgmt_meth.c
@@ -17,6 +17,8 @@
#include "crypto/evp.h"
#include "evp_local.h"
+static void evp_skeymgmt_free(void *s);
+
void *evp_skeymgmt_generate(const EVP_SKEYMGMT *skeymgmt, const OSSL_PARAM params[])
{
void *provctx = ossl_provider_ctx(EVP_SKEYMGMT_get0_provider(skeymgmt));
@@ -45,16 +47,6 @@ void evp_skeymgmt_freedata(const EVP_SKEYMGMT *skeymgmt, void *keydata)
skeymgmt->free(keydata);
}
-static int evp_skeymgmt_up_ref(void *skeymgmt)
-{
- return EVP_SKEYMGMT_up_ref(skeymgmt);
-}
-
-static void evp_skeymgmt_free(void *skeymgmt)
-{
- EVP_SKEYMGMT_free(skeymgmt);
-}
-
static void *skeymgmt_new(void)
{
EVP_SKEYMGMT *skeymgmt = NULL;
@@ -62,7 +54,7 @@ static void *skeymgmt_new(void)
if ((skeymgmt = OPENSSL_zalloc(sizeof(*skeymgmt))) == NULL)
return NULL;
if (!CRYPTO_NEW_REF(&skeymgmt->refcnt, 1)) {
- EVP_SKEYMGMT_free(skeymgmt);
+ evp_skeymgmt_free(skeymgmt);
return NULL;
}
return skeymgmt;
@@ -70,7 +62,7 @@ static void *skeymgmt_new(void)
static void *skeymgmt_from_algorithm(int name_id,
const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov)
+ OSSL_PROVIDER *prov, int no_store)
{
const OSSL_DISPATCH *fns = algodef->implementation;
EVP_SKEYMGMT *skeymgmt = NULL;
@@ -79,8 +71,9 @@ static void *skeymgmt_from_algorithm(int name_id,
return NULL;
skeymgmt->name_id = name_id;
+ skeymgmt->no_store = no_store;
if ((skeymgmt->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL) {
- EVP_SKEYMGMT_free(skeymgmt);
+ evp_skeymgmt_free(skeymgmt);
return NULL;
}
skeymgmt->description = algodef->algorithm_description;
@@ -122,13 +115,13 @@ static void *skeymgmt_from_algorithm(int name_id,
if (skeymgmt->free == NULL
|| skeymgmt->import == NULL
|| skeymgmt->export == NULL) {
- EVP_SKEYMGMT_free(skeymgmt);
+ evp_skeymgmt_free(skeymgmt);
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS);
return NULL;
}
if (!ossl_provider_up_ref(prov)) {
- EVP_SKEYMGMT_free(skeymgmt);
+ evp_skeymgmt_free(skeymgmt);
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
return NULL;
}
@@ -137,6 +130,31 @@ static void *skeymgmt_from_algorithm(int name_id,
return skeymgmt;
}
+static int evp_skeymgmt_up_ref(void *s)
+{
+ EVP_SKEYMGMT *skeymgmt = (EVP_SKEYMGMT *)s;
+ int ref = 0;
+
+ return CRYPTO_UP_REF(&skeymgmt->refcnt, &ref);
+}
+
+static void evp_skeymgmt_free(void *s)
+{
+ EVP_SKEYMGMT *skeymgmt = (EVP_SKEYMGMT *)s;
+ int ref = 0;
+
+ if (skeymgmt == NULL)
+ return;
+
+ CRYPTO_DOWN_REF(&skeymgmt->refcnt, &ref);
+ if (ref > 0)
+ return;
+ OPENSSL_free(skeymgmt->type_name);
+ ossl_provider_free(skeymgmt->prov);
+ CRYPTO_FREE_REF(&skeymgmt->refcnt);
+ OPENSSL_free(skeymgmt);
+}
+
EVP_SKEYMGMT *evp_skeymgmt_fetch_from_prov(OSSL_PROVIDER *prov,
const char *name,
const char *properties)
@@ -160,26 +178,23 @@ EVP_SKEYMGMT *EVP_SKEYMGMT_fetch(OSSL_LIB_CTX *ctx, const char *algorithm,
int EVP_SKEYMGMT_up_ref(EVP_SKEYMGMT *skeymgmt)
{
- int ref = 0;
-
- CRYPTO_UP_REF(&skeymgmt->refcnt, &ref);
+#ifdef OPENSSL_NO_CACHED_FETCH
+ return evp_skeymgmt_up_ref(skeymgmt);
+#else
+ if (skeymgmt->no_store != 0)
+ return evp_skeymgmt_up_ref(skeymgmt);
return 1;
+#endif
}
void EVP_SKEYMGMT_free(EVP_SKEYMGMT *skeymgmt)
{
- int ref = 0;
-
- if (skeymgmt == NULL)
- return;
-
- CRYPTO_DOWN_REF(&skeymgmt->refcnt, &ref);
- if (ref > 0)
- return;
- OPENSSL_free(skeymgmt->type_name);
- ossl_provider_free(skeymgmt->prov);
- CRYPTO_FREE_REF(&skeymgmt->refcnt);
- OPENSSL_free(skeymgmt);
+#ifdef OPENSSL_NO_CACHED_FETCH
+ evp_skeymgmt_free(skeymgmt);
+#else
+ if (skeymgmt != NULL && (skeymgmt->no_store != 0))
+ evp_skeymgmt_free(skeymgmt);
+#endif
}
const OSSL_PROVIDER *EVP_SKEYMGMT_get0_provider(const EVP_SKEYMGMT *skeymgmt)
diff --git a/crypto/fn/build.info b/crypto/fn/build.info
deleted file mode 100644
index cee3d11f66..0000000000
--- a/crypto/fn/build.info
+++ /dev/null
@@ -1,9 +0,0 @@
-$LIBCRYPTO=../../libcrypto
-$LIBFIPS=../../providers/libfips.a
-LIBS=$LIBCRYPTO
-
-$COMMON=fn_err.c fn_lib.c fn_ctx.c fn_intern.c fn_addsub.c fn_shift.c fn_mul.c \
- fn_sqr.c fn_div.c fn_rand.c fn_mod.c
-
-SOURCE[$LIBCRYPTO]=$COMMON
-SOURCE[$LIBFIPS]=$COMMON
diff --git a/crypto/fn/fn_addsub.c b/crypto/fn/fn_addsub.c
deleted file mode 100644
index ee1c2b2aa1..0000000000
--- a/crypto/fn/fn_addsub.c
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * Copyright 1995-2025 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
- */
-
-#include "internal/cryptlib.h"
-#include "crypto/fnerr.h"
-#include "../bn/bn_local.h" /* For using the low level bignum functions */
-#include "fn_local.h"
-
-/*
- * ossl_fn_add_words and ossl_fn_sub_words perform fixed-width unsigned
- * addition and subtraction of multi-limb integers.
- *
- * The carry or borrow is always propagated through every limb of both
- * operands (and through any extra result limbs when rl exceeds the operand
- * sizes). The operation is effectively performed at the precision of the
- * wider operand, then truncated to rl limbs — analogous to performing an
- * unsigned operation in the wider of the operand types and then casting
- * the result to a narrower type.
- *
- * The returned carry (addition) or borrow (subtraction) is the true
- * overflow / borrow out of the most significant processed limb:
- *
- * - When rl <= max(al, bl), it is the carry / borrow out of max(al, bl)
- * limbs. Note that this does NOT indicate whether the result fits in
- * rl limbs; non-zero high limbs may have been truncated without
- * generating a carry. If the caller needs the exact magnitude, rl
- * must be at least max(al, bl).
- *
- * - For addition, when rl > max(al, bl), the carry is absorbed into the
- * result (written to r[max(al,bl)], higher limbs zeroed) and the
- * function returns 0.
- *
- * - For subtraction, when rl > max(al, bl), the borrow is propagated
- * through all remaining result limbs (two's complement sign extension)
- * and the function returns the borrow out of rl limbs.
- */
-
-/* unsigned addition of a and b, returns carry if there is one past the result size */
-OSSL_FN_ULONG ossl_fn_add_words(OSSL_FN_ULONG *r, size_t rl,
- const OSSL_FN_ULONG *a, size_t al,
- const OSSL_FN_ULONG *b, size_t bl)
-{
- /*
- * Addition is commutative, so we switch 'a' and 'b' around to
- * ensure that 'a' is physically the largest, so a maximum of
- * work is done with 'bn_add_words'
- */
- if (al < bl) {
- const OSSL_FN_ULONG *tmp;
- size_t tmpl;
-
- tmp = a;
- tmpl = al;
- a = b;
- al = bl;
- b = tmp;
- bl = tmpl;
- }
-
- /*
- * Four stages.
- *
- * For each stage, |stage_limbs| is used to hold the number
- * of limbs being treated in that stage, |i| is used as an
- * index into the arrays, and |carry| is used to transport
- * the carry from one stage to the other.
- *
- * Note: |stage_limbs| is passed cast to 'int' when calling
- * bn_add_words(). This is fine because the maximum size of
- * any OSSL_FN_ULONG is BN_MAX_WORDS, which is small enough.
- * Should that change some day, there's trouble ahead.
- */
- size_t stage_limbs;
- OSSL_FN_ULONG carry;
- size_t i;
-
- /*
- * Stage 1: calculate the least min(rl,bl) limbs
- *
- * This uses bn_add_words, with what performance benefits that gives.
- */
-
- stage_limbs = (bl > rl) ? rl : bl;
- carry = bn_add_words(r, a, b, (int)stage_limbs);
-
- /* Record the array position past what bn_add_words calculated */
- i = stage_limbs;
-
- /*
- * Stage 2: calculate min(rl,bl) to bl limbs
- *
- * Because this loop only engages when rl < bl, it cannot affect r.
- * The only purpose of this loop is to propagate carry in this particular
- * scenario.
- */
-
- stage_limbs = bl - stage_limbs;
-
- for (size_t dif = stage_limbs; dif > 0; dif--, i++) {
- OSSL_FN_ULONG t1, t2;
-
- t1 = (a[i] + carry) & OSSL_FN_MASK;
- carry = (t1 < carry);
- t2 = (b[i] + t1) & OSSL_FN_MASK;
- carry |= (t2 < t1);
- }
-
- assert(i == bl);
-
- /*
- * Stage 3: calculate bl to al limbs
- *
- * Note: at any time, the end of r may be reached. This is solved
- * with a temporary pointer that's set appropriately inside the loop.
- */
-
- stage_limbs = al - bl;
-
- for (size_t dif = stage_limbs; dif > 0; dif--, i++) {
- OSSL_FN_ULONG tmp = 0;
- OSSL_FN_ULONG *rp = (i < rl) ? &r[i] : &tmp;
- OSSL_FN_ULONG t1;
-
- t1 = (a[i] + carry) & OSSL_FN_MASK;
- carry = (t1 < carry);
-
- *rp = t1;
- }
-
- assert(i == al);
-
- /* If |r| is exhausted, there's nothing more to do */
- if (i >= rl)
- return carry;
-
- /*
- * Stage 4: calculate a final carry, for when rl > al
- *
- * This is relatively simple, compare to earlier loops.
- */
-
- stage_limbs = rl - al;
-
- for (size_t dif = stage_limbs; dif > 0; dif--, i++) {
- r[i] = carry;
- carry = 0;
- }
-
- return carry;
-}
-
-int OSSL_FN_add(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b)
-{
- (void)ossl_fn_add_words(r->d, r->dsize, a->d, a->dsize, b->d, b->dsize);
- return 1;
-}
-
-/*-
- * Adds the single-limb word |w| to |a| in place, propagating the carry
- * through |a|'s limbs and truncating any carry out past a->dsize (OSSL_FN is
- * fixed-size, so a carry past the last limb is discarded rather than grown
- * into). The degenerate w == 0 case is a no-op.
- *
- * Not constant-time: the carry-propagation loop stops early once the carry
- * is exhausted, so the number of limbs touched depends on the operand's
- * value.
- */
-int OSSL_FN_add_word(OSSL_FN *a, OSSL_FN_ULONG w)
-{
- size_t i;
- size_t dsize = (size_t)a->dsize;
-
- if (w == 0)
- return 1;
-
- for (i = 0; i < dsize && w != 0; i++) {
- OSSL_FN_ULONG l = (a->d[i] + w) & OSSL_FN_MASK;
-
- a->d[i] = l;
- w = (w > l);
- }
- /* Any remaining carry out past dsize is truncated. */
- return 1;
-}
-
-/* unsigned subtraction of b from a, returns borrow if there is one past the result size */
-OSSL_FN_ULONG ossl_fn_sub_words(OSSL_FN_ULONG *r, size_t rl,
- const OSSL_FN_ULONG *a, size_t al,
- const OSSL_FN_ULONG *b, size_t bl)
-{
- size_t max = (al >= bl) ? al : bl;
- size_t min = (al <= bl) ? al : bl;
-
- /*
- * Four stages.
- *
- * For each stage, |stage_limbs| is used to hold the number
- * of limbs being treated in that stage, |i| is used as an
- * index into the arrays, and |borrow| is used to transport
- * the borrow from one stage to the other.
- *
- * Note: |stage_limbs| is passed cast to 'int' when calling
- * bn_sub_words(). This is fine because the maximum size of
- * any OSSL_FN_ULONG is BN_MAX_WORDS, which is small enough.
- * Should that change some day, there's trouble ahead.
- */
- size_t stage_limbs;
- OSSL_FN_ULONG borrow;
- size_t i;
-
- /*
- * Stage 1: calculate the least min(rl,al,bl) limbs
- *
- * This uses bn_sub_words, with what performance benefits that gives.
- */
-
- stage_limbs = (min > rl) ? rl : min;
- borrow = bn_sub_words(r, a, b, (int)stage_limbs);
-
- /* Record the array position past what bn_sub_words calculated */
- i = stage_limbs;
-
- /*
- * Stage 2: calculate the min(rl,al,bl) to min(al,bl) limbs
- *
- * Because this loop only engages when rl < min(al,bl), it cannot affect r.
- * The only purpose of this loop is to propagate borrow in this particular
- * scenario.
- */
-
- stage_limbs = min - stage_limbs;
-
- for (size_t dif = stage_limbs; dif > 0; dif--, i++) {
- OSSL_FN_ULONG t1, t2;
-
- t1 = a[i];
- t2 = (t1 - borrow) & OSSL_FN_MASK;
- borrow = (t2 > t1);
- t1 = b[i];
- t1 = (t2 - t1) & OSSL_FN_MASK;
- borrow |= (t1 > t2);
- }
-
- assert(i == min);
-
- /*
- * Stage 3: calculate the min(al,bl) to max(al,bl) limbs
- *
- * Note: at any time, the end of r may be reached. This is solved
- * with a temporary pointer that's set appropriately inside the loop.
- */
-
- const OSSL_FN_ULONG *maxp = (al >= bl) ? a : b;
- const OSSL_FN_ULONG s2_mask1 = (al >= bl) ? OSSL_FN_MASK : 0;
- const OSSL_FN_ULONG s2_mask2 = ~s2_mask1;
-
- stage_limbs = max - min;
-
- /* calculate the result of borrowing from more significant limbs */
- for (size_t dif = stage_limbs; dif > 0; dif--, i++) {
- OSSL_FN_ULONG tmp = 0;
- OSSL_FN_ULONG *rp = (i < rl) ? &r[i] : &tmp;
- OSSL_FN_ULONG t1, t2;
-
- t1 = maxp[i] & s2_mask1;
- t2 = (t1 - borrow) & OSSL_FN_MASK;
- borrow = (t2 > t1);
- t1 = maxp[i] & s2_mask2;
- t1 = (t2 - t1) & OSSL_FN_MASK;
- borrow |= (t1 > t2);
-
- *rp = t1;
- }
-
- assert(i == max);
-
- /* If |r| is exhausted, there's nothing more to do */
- if (i >= rl)
- return borrow;
-
- /*
- * Stage 4: calculate a final borrow, for when rl > max
- *
- * This is relatively simple, compare to earlier loops.
- */
-
- stage_limbs = rl - max;
-
- /* Finally, fill in the rest of the result array by borrowing from zeros */
- for (size_t dif = stage_limbs; dif > 0; dif--, i++) {
- OSSL_FN_ULONG t1 = (0 - borrow) & OSSL_FN_MASK;
-
- borrow = (t1 > 0);
-
- r[i] = t1;
- }
-
- return borrow;
-}
-
-int OSSL_FN_sub(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b)
-{
- (void)ossl_fn_sub_words(r->d, r->dsize, a->d, a->dsize, b->d, b->dsize);
- return 1;
-}
-
-/*-
- * Subtracts the single-limb word |w| from |a| in place, propagating the
- * borrow through |a|'s limbs. If the borrow runs past a->dsize (i.e. the
- * unsigned value of |a| is less than |w|), the result is the 2's-complement
- * wrap-around truncated to dsize, per OSSL_FN's fixed-size unsigned
- * semantics: there is no sign to record, so the wrapped value is kept. The
- * degenerate w == 0 case is a no-op.
- *
- * Not constant-time: the borrow-propagation loop returns early once the
- * borrow is repaid, so the number of limbs touched depends on the operand's
- * value.
- */
-int OSSL_FN_sub_word(OSSL_FN *a, OSSL_FN_ULONG w)
-{
- size_t i;
- size_t dsize = (size_t)a->dsize;
-
- if (w == 0)
- return 1;
-
- for (i = 0; i < dsize; i++) {
- if (a->d[i] >= w) {
- a->d[i] -= w;
- return 1; /* borrow repaid */
- }
- a->d[i] = (a->d[i] - w) & OSSL_FN_MASK;
- w = 1;
- }
- /* Borrow out past dsize is truncated (2's complement). */
- return 1;
-}
diff --git a/crypto/fn/fn_ctx.c b/crypto/fn/fn_ctx.c
deleted file mode 100644
index fc510e03fd..0000000000
--- a/crypto/fn/fn_ctx.c
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Copyright 2025 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
- */
-
-#include
-#include
-#include "internal/safe_math.h"
-#include "crypto/fn.h"
-#include "fn_local.h"
-
-OSSL_SAFE_MATH_ADDU(size_t, size_t, OSSL_SAFE_MATH_MAXU(size_t))
-OSSL_SAFE_MATH_MULU(size_t, size_t, OSSL_SAFE_MATH_MAXU(size_t))
-
-/*
- * An OSSL_FN_CTX is a large pre-allocated chunk of memory that can be used
- * to quickly allocate OSSL_FN instances. The organization of memory is as
- * a fairly typical arena, where OSSL_FN instances are "stacked" one after
- * the other.
- *
- * However, there is also the concept of frames, which are arenas within an
- * arena. This allows easily passing an OSSL_FN_CTX to a function, and for
- * that function to allocate such a frame for itself, and easily deallocate
- * it when it's done.
- */
-
-size_t OSSL_FN_CTX_size(size_t max_n_frames, size_t max_n_numbers,
- size_t max_n_limbs)
-{
- int err = 0;
- size_t frames, numbers, limbs, total;
-
- /*
- * A context always needs at least one frame, since every use of an
- * OSSL_FN_CTX calls OSSL_FN_CTX_start(), which carves out a frame.
- */
- if (max_n_frames == 0)
- return 0;
- /*
- * Number-header and limb budgets must both be present or both absent.
- * OSSL_FN_CTX_get_limbs() allocates an OSSL_FN header and its limbs
- * together, so a context with one budget but not the other can never
- * produce a usable number.
- */
- if ((max_n_numbers == 0) != (max_n_limbs == 0))
- return 0;
-
- frames = safe_mul_size_t(max_n_frames,
- sizeof(struct ossl_fn_ctx_frame_st), &err);
- numbers = safe_mul_size_t(max_n_numbers, sizeof(OSSL_FN), &err);
- limbs = safe_mul_size_t(max_n_limbs, OSSL_FN_BYTES, &err);
- total = safe_add_size_t(frames, numbers, &err);
- total = safe_add_size_t(total, limbs, &err);
-
- return err == 0 ? total : 0;
-}
-
-OSSL_FN_CTX *OSSL_FN_CTX_new(OSSL_LIB_CTX *libctx, size_t max_n_frames,
- size_t max_n_numbers, size_t max_n_limbs)
-{
- return OSSL_FN_CTX_new_size(libctx,
- OSSL_FN_CTX_size(max_n_frames, max_n_numbers, max_n_limbs));
-}
-
-OSSL_FN_CTX *OSSL_FN_CTX_new_size(OSSL_LIB_CTX *libctx, size_t size)
-{
- size_t total_size;
- OSSL_FN_CTX *ctx;
-
- int err = 0;
-
- /*
- * A size of 0 is the error return of OSSL_FN_CTX_size() (and the
- * per-operation ctx-size helpers). Treat it as an error here too, so a
- * caller does not get back a context with a zero-size arena that it
- * would then hand to an operation expecting usable scratch space.
- */
- if (size == 0)
- return NULL;
-
- total_size = safe_add_size_t(sizeof(*ctx), size, &err);
- if (err != 0)
- return NULL;
-
- ctx = OPENSSL_zalloc(total_size);
-
- if (ctx != NULL)
- ctx->msize = size;
-
- return ctx;
-}
-
-OSSL_FN_CTX *OSSL_FN_CTX_secure_new(OSSL_LIB_CTX *libctx, size_t max_n_frames,
- size_t max_n_numbers, size_t max_n_limbs)
-{
- return OSSL_FN_CTX_secure_new_size(libctx,
- OSSL_FN_CTX_size(max_n_frames, max_n_numbers, max_n_limbs));
-}
-
-OSSL_FN_CTX *OSSL_FN_CTX_secure_new_size(OSSL_LIB_CTX *libctx, size_t size)
-{
- size_t total_size;
- OSSL_FN_CTX *ctx;
-
- int err = 0;
-
- /* As in OSSL_FN_CTX_new_size(), a size of 0 is an error. */
- if (size == 0)
- return NULL;
-
- total_size = safe_add_size_t(sizeof(*ctx), size, &err);
- if (err != 0)
- return NULL;
-
- ctx = OPENSSL_secure_zalloc(total_size);
-
- if (ctx != NULL) {
- ctx->msize = size;
- ctx->is_securely_allocated = 1;
- }
-
- return ctx;
-}
-
-void OSSL_FN_CTX_peak_usage(const OSSL_FN_CTX *ctx, size_t *peak_n_frames,
- size_t *peak_n_numbers, size_t *peak_n_limbs)
-{
- if (ctx == NULL) {
- if (peak_n_frames != NULL)
- *peak_n_frames = 0;
- if (peak_n_numbers != NULL)
- *peak_n_numbers = 0;
- if (peak_n_limbs != NULL)
- *peak_n_limbs = 0;
- return;
- }
- if (peak_n_frames != NULL)
- *peak_n_frames = ctx->peak_n_frames;
- if (peak_n_numbers != NULL)
- *peak_n_numbers = ctx->peak_n_numbers;
- if (peak_n_limbs != NULL)
- *peak_n_limbs = ctx->peak_n_limbs;
-}
-
-void OSSL_FN_CTX_free(OSSL_FN_CTX *ctx)
-{
- if (ctx == NULL)
- return;
-
- assert(ctx->last_frame == NULL);
-
- if (ctx->is_securely_allocated)
- OPENSSL_secure_free(ctx);
- else
- OPENSSL_free(ctx);
-}
-
-const void *OSSL_FN_CTX_start(OSSL_FN_CTX *ctx)
-{
- if (!ossl_assert(ctx != NULL))
- return NULL;
-
- struct ossl_fn_ctx_frame_st *last_frame = ctx->last_frame;
- size_t used = (last_frame == NULL) ? 0 : last_frame->free_memory - ctx->memory;
-
- if (ctx->msize - used < sizeof(struct ossl_fn_ctx_frame_st))
- return NULL;
-
- if (ctx->last_frame == NULL)
- ctx->last_frame = (struct ossl_fn_ctx_frame_st *)ctx->memory;
- else
- ctx->last_frame = (struct ossl_fn_ctx_frame_st *)last_frame->free_memory;
-
- struct ossl_fn_ctx_frame_st *frame = ctx->last_frame;
- frame->arena = ctx;
- frame->previous_frame = last_frame;
- frame->free_memory = frame->memory;
- frame->msize = ctx->msize - used - sizeof(*frame);
- frame->n_numbers = 0;
- frame->n_limbs = 0;
-
- ctx->n_frames++;
- if (ctx->n_frames > ctx->peak_n_frames)
- ctx->peak_n_frames = ctx->n_frames;
-
- return ctx->last_frame;
-}
-
-int OSSL_FN_CTX_end(OSSL_FN_CTX *ctx, const void *token)
-{
- if (!ossl_assert(ctx != NULL) || !ossl_assert(ctx->last_frame != NULL))
- return 0;
-
- struct ossl_fn_ctx_frame_st *last_frame = ctx->last_frame;
-
- if (last_frame != token)
- return 0;
-
- ctx->n_numbers -= last_frame->n_numbers;
- ctx->n_limbs -= last_frame->n_limbs;
- ctx->n_frames--;
- ctx->last_frame = last_frame->previous_frame;
-
- return 1;
-}
-
-OSSL_FN *OSSL_FN_CTX_get_limbs(OSSL_FN_CTX *ctx, size_t limbs)
-{
- if (!ossl_assert(ctx != NULL))
- return NULL;
-
- struct ossl_fn_ctx_frame_st *frame = ctx->last_frame;
-
- if (!ossl_assert(frame != NULL))
- return NULL;
-
- size_t totalsize = ossl_fn_totalsize(limbs);
- size_t used = frame->free_memory - frame->memory;
- if (totalsize == 0 || frame->msize - used < totalsize)
- return NULL;
-
- OSSL_FN *fn = (OSSL_FN *)frame->free_memory;
- frame->free_memory += totalsize;
- frame->n_numbers++;
- frame->n_limbs += limbs;
-
- ctx->n_numbers++;
- ctx->n_limbs += limbs;
- if (ctx->n_numbers > ctx->peak_n_numbers)
- ctx->peak_n_numbers = ctx->n_numbers;
- if (ctx->n_limbs > ctx->peak_n_limbs)
- ctx->peak_n_limbs = ctx->n_limbs;
-
- memset(fn, 0, totalsize);
- fn->dsize = (int)limbs;
- fn->is_securely_allocated = ctx->is_securely_allocated;
-
- return fn;
-}
-
-OSSL_FN *OSSL_FN_CTX_get_bytes(OSSL_FN_CTX *ctx, size_t bytes)
-{
- return OSSL_FN_CTX_get_limbs(ctx, ossl_fn_bytes_to_limbs(bytes));
-}
-
-OSSL_FN *OSSL_FN_CTX_get_bits(OSSL_FN_CTX *ctx, size_t bits)
-{
- return OSSL_FN_CTX_get_bytes(ctx, ossl_fn_bits_to_bytes(bits));
-}
diff --git a/crypto/fn/fn_div.c b/crypto/fn/fn_div.c
deleted file mode 100644
index 9e0f67d20d..0000000000
--- a/crypto/fn/fn_div.c
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * Copyright 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
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
-
-#include
-#include
-#include "internal/safe_math.h"
-#include "crypto/cryptlib.h"
-#include "crypto/fnerr.h"
-#include "../bn/bn_local.h" /* For using the low level bignum functions */
-#include "fn_local.h"
-
-OSSL_SAFE_MATH_ADDU(size_t, size_t, OSSL_SAFE_MATH_MAXU(size_t))
-
-#if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM) \
- && !defined(PEDANTIC) && !defined(BN_DIV3W)
-#if defined(__GNUC__) && __GNUC__ >= 2
-#if defined(__i386) || defined(__i386__)
-/*-
- * There were two reasons for implementing this template:
- * - GNU C generates a call to a function (__udivdi3 to be exact)
- * in reply to ((((BN_ULLONG)n0)< */
-#endif /* __GNUC__ */
-#endif /* OPENSSL_NO_ASM */
-
-/*
- * Copy src to dst and align it to the left using lshift.
- * lshift is assumed to be less than OSSL_FN_BITS.
- */
-static inline void copy_align_left(OSSL_FN *dst, const OSSL_FN *src, OSSL_FN_ULONG lshift)
-{
- OSSL_FN_ULONG rshift = OSSL_FN_BITS - lshift;
- OSSL_FN_ULONG rmask;
- OSSL_FN_ULONG m;
- const OSSL_FN_ULONG *s = src->d;
- size_t sl = src->dsize;
- OSSL_FN_ULONG *d = dst->d;
- size_t dl = dst->dsize;
- size_t l = (dl < sl) ? dl : sl;
- size_t i;
-
- rshift %= OSSL_FN_BITS;
-
- /* rmask = 0 - (rshift != 0) */
- rmask = (OSSL_FN_ULONG)0 - rshift;
- rmask |= rmask >> 8;
-
- /* src and dst may be the same, that's why this loop is made this way */
- for (i = 0, m = 0; i < l; i++) {
- OSSL_FN_ULONG tmp = s[i];
- d[i] = ((tmp << lshift) | m) & OSSL_FN_MASK;
- m = (tmp >> rshift) & rmask;
- }
-
- for (; i < dl; i++) {
- d[i] = m;
- m = 0;
- }
-}
-
-/*
- * Copy src to dst and align it to the right using rshift.
- * rshift is assumed to be less than OSSL_FN_BITS.
- */
-static inline void copy_align_right(OSSL_FN *dst, const OSSL_FN *src, OSSL_FN_ULONG rshift)
-{
- OSSL_FN_ULONG lshift = OSSL_FN_BITS - rshift;
- OSSL_FN_ULONG lmask;
- const OSSL_FN_ULONG *s = src->d;
- size_t sl = src->dsize;
- OSSL_FN_ULONG *d = dst->d;
- size_t dl = dst->dsize;
- size_t i;
- size_t l = (dl < sl) ? dl : sl;
-
- lshift %= OSSL_FN_BITS;
-
- /* lmask = 0 - (lshift != 0) */
- lmask = (OSSL_FN_ULONG)0 - lshift;
- lmask |= lmask >> 8;
-
- /* Just to be safe */
- for (i = dl; i-- > l;)
- d[i] = 0;
-
- /*
- * m is a set of bits passed to the next limb down when shifting,
- * and needs proper bootstrapping: if the source is larger than the
- * destination, we must consider one source limb beyond the destination
- * size. If not, m is simply starts with zero.
- */
- OSSL_FN_ULONG m = (dl < sl) ? (s[dl] << lshift) & lmask : 0;
-
- /* src and dst may be the same, that's why this loop is made this way */
- for (i = l; i-- > 0;) {
- OSSL_FN_ULONG tmp = s[i];
- d[i] = m | ((tmp >> rshift) & OSSL_FN_MASK);
- m = (tmp << lshift) & lmask;
- }
-}
-
-static inline OSSL_FN_ULONG div_words(OSSL_FN_ULONG *wnumtop, OSSL_FN_ULONG *wnum,
- OSSL_FN_ULONG d1, OSSL_FN_ULONG d0)
-{
-#if defined(BN_DIV3W)
- return bn_div_3_words(wnumtop, d1, d0);
-#else
- OSSL_FN_ULONG n0 = wnumtop[0], n1 = wnumtop[-1], quo = 0, rem = 0;
-
- if (n0 == d0)
- quo = OSSL_FN_MASK;
- else { /* n0 < d0 */
- OSSL_FN_ULONG n2 = (wnumtop == wnum) ? 0 : wnumtop[-2];
-#ifdef BN_LLONG
- BN_ULLONG t2;
-
-#if defined(BN_LLONG) && defined(BN_DIV2W) && !defined(bn_div_words)
- quo = (OSSL_FN_ULONG)(((((BN_ULLONG)n0) << OSSL_FN_BITS) | n1) / d0);
-#else
- quo = bn_div_words(n0, n1, d0);
-#endif
-
-#ifndef REMAINDER_IS_ALREADY_CALCULATED
- /*
- * rem doesn't have to be BN_ULLONG. The least we
- * know it's less that d0, isn't it?
- */
- rem = (n1 - quo * d0) & BN_MASK2;
-#endif
- t2 = (BN_ULLONG)d1 * quo;
-
- for (;;) {
- if (t2 <= ((((BN_ULLONG)rem) << OSSL_FN_BITS) | n2))
- break;
- quo--;
- rem += d0;
- if (rem < d0)
- break; /* don't let rem overflow */
- t2 -= d1;
- }
-#else /* !BN_LLONG */
- OSSL_FN_ULONG t2l, t2h;
-
- quo = bn_div_words(n0, n1, d0);
-#ifndef REMAINDER_IS_ALREADY_CALCULATED
- rem = (n1 - quo * d0) & OSSL_FN_MASK;
-#endif
-
-#if defined(BN_UMULT_LOHI)
- BN_UMULT_LOHI(t2l, t2h, d1, quo);
-#elif defined(BN_UMULT_HIGH)
- t2l = d1 * quo;
- t2h = BN_UMULT_HIGH(d1, quo);
-#else
- {
- OSSL_FN_ULONG ql, qh;
- t2l = LBITS(d1);
- t2h = HBITS(d1);
- ql = LBITS(quo);
- qh = HBITS(quo);
- mul64(t2l, t2h, ql, qh); /* t2=(BN_ULLONG)d1*q; */
- }
-#endif
-
- for (;;) {
- if ((t2h < rem) || ((t2h == rem) && (t2l <= n2)))
- break;
- quo--;
- rem += d0;
- if (rem < d0)
- break; /* don't let rem overflow */
- if (t2l < d1)
- t2h--;
- t2l -= d1;
- }
-#endif /* !BN_LLONG */
- }
-
- return quo;
-#endif /* !BN_DIV3W */
-}
-
-size_t OSSL_FN_div_ctx_size(const OSSL_FN *q, const OSSL_FN *r,
- const OSSL_FN *n, const OSSL_FN *d)
-{
- if ((q == NULL && r == NULL) || n == NULL || d == NULL)
- return 0;
-
- size_t nl = n->dsize;
- size_t dl = d->dsize;
- size_t snuml, tmp;
- int err = 0;
-
- snuml = safe_add_size_t(nl > dl ? nl : dl, 1, &err);
- tmp = safe_add_size_t(dl, 1, &err);
-
- size_t max_ql = nl == 0 ? 1 : nl;
- size_t ql = (q == NULL || (size_t)q->dsize < max_ql) ? max_ql : 0;
- size_t max_n_numbers = 3 + (ql != 0);
- size_t max_n_limbs;
-
- max_n_limbs = safe_add_size_t(snuml, dl, &err);
- max_n_limbs = safe_add_size_t(max_n_limbs, tmp, &err);
- max_n_limbs = safe_add_size_t(max_n_limbs, ql, &err);
-
- return err == 0 ? OSSL_FN_CTX_size(1, max_n_numbers, max_n_limbs) : 0;
-}
-
-/* Trivia: this function implements Knuth's algorithm D */
-int OSSL_FN_div(OSSL_FN *q, OSSL_FN *r, const OSSL_FN *n, const OSSL_FN *d, OSSL_FN_CTX *ctx)
-{
- const void *token = OSSL_FN_CTX_start(ctx);
- if (token == NULL)
- return 0;
-
- size_t nl = n->dsize;
- size_t dl = d->dsize;
- size_t ql = (q == NULL) ? 0 : q->dsize;
-
- /*
- * We need to figure out the significant size of |d|, to avoid division by
- * zero if the highest limb(s) are zero.
- *
- * This doesn't quite give a sense that division can be constant time.
- * However, in the use cases where constant time is interesting (cryptosystems),
- * it can be argued that the denominator would have a constant enough size
- * within each cryptosystem (and size therein), so it's assumed that time
- * will be constant because of that.
- */
- while (dl > 0 && d->d[dl - 1] == 0)
- dl--;
-
- if (dl == 0) {
- ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_DIV_BY_ZERO);
- goto err;
- }
-
- /*
- * Because some assembler language instructions have those requirements,
- * the denominator need to be shifted "left" so the top bit is always 1.
- * To ensure that we still get correct results, the numerator will have
- * to be shifted left as many bits. The resulting quotient will end up
- * correct, but the remainder will have to be shifted "right" before the
- * end of this function.
- */
- OSSL_FN_ULONG norm_shift = OSSL_FN_BITS - BN_num_bits_word(d->d[dl - 1]);
-
- /*
- * Store a copy the numerator in snum, padded with extra zeros if nl <= dl
- * eventually, this will contain the remainder. Because it may be shifted
- * up to almost a full limb to the left (worst case scenario), an extra limb
- * need to be allocated.
- */
- size_t snuml = ((nl <= dl) ? dl : nl) + 1;
- OSSL_FN *snum = OSSL_FN_CTX_get_limbs(ctx, snuml);
- if (!ossl_assert(snuml <= INT_MAX && snum != NULL))
- goto err;
- copy_align_left(snum, n, norm_shift);
-
- /*
- * Store a copy of the denominator in sdiv, shifted left so that its top bit
- * is always 1. This is necessary to avoid gnarly arithmetic exceptions when
- * the denominator's highest limb is a very small number.
- */
- size_t sdivl = dl;
- OSSL_FN *sdiv = OSSL_FN_CTX_get_limbs(ctx, sdivl);
- if (!ossl_assert(sdivl <= INT_MAX && sdiv != NULL))
- goto err;
- copy_align_left(sdiv, d, norm_shift);
-
- /*
- * The number of times we will iterate to perform division, i.e.
- * how often we will "shift" the divisor "window" over the numerator.
- * This also determines the size of the result.
- *
- * For the math oriented:
- *
- * snuml - sdivl = ((nl <= dl) ? dl : nl) + 1 - dl
- * => snuml - sdivl = ((nl <= dl) ? 0 : nl - dl) + 1
- * => snuml - sdivl = (nl <= dl) ? 1 : nl - dl + 1
- */
- size_t loop = snuml - sdivl;
-
- /*
- * Set up the quotient. It will be stored directly in |q| if it has
- * enough space, otherwise temporary storage is allocated.
- */
- OSSL_FN *res = (ql < loop) ? OSSL_FN_CTX_get_limbs(ctx, loop) : q;
- if (!ossl_assert(res != NULL))
- goto err;
-
- /* Position of the next quotient limb to be calculated, plus one */
- OSSL_FN_ULONG *resp = &(res->d[loop]);
-
- /* Intermediary storage */
- OSSL_FN *tmp = OSSL_FN_CTX_get_limbs(ctx, sdivl + 1);
- if (!ossl_assert(tmp != NULL))
- goto err;
-
- /* Set up the "window" position in snum. */
- OSSL_FN_ULONG *wnum = &(snum->d[loop]);
- OSSL_FN_ULONG *wnumtop = &(snum->d[snuml - 1]);
-
- /* Get the top 2 words of the denominator */
- OSSL_FN_ULONG d0 = sdiv->d[sdivl - 1];
- OSSL_FN_ULONG d1 = (sdivl == 1) ? 0 : sdiv->d[sdivl - 2];
-
- size_t i;
-
- /* If res is larger than the expected result, zero the limbs above */
- for (i = res->dsize; i > loop;)
- res->d[--i] = 0;
- for (i = 0; i < loop; i++, wnumtop--) {
- OSSL_FN_ULONG quo, l0;
- /*
- * the first part of the loop uses the top two words of snum and sdiv
- * to calculate a OSSL_FN_ULONG quo such that | wnum - d * q | < d
- */
- quo = div_words(wnumtop, wnum, d1, d0);
-
- l0 = bn_mul_words(tmp->d, sdiv->d, (int)sdivl, quo);
- tmp->d[sdivl] = l0;
- wnum--;
-
- /*
- * ignore top values of the bignums just sub the two OSSL_FN_ULONG
- * arrays with bn_sub_words
- */
- l0 = bn_sub_words(wnum, wnum, tmp->d, (int)sdivl + 1);
- quo -= l0;
-
- /*
- * Note: As we have considered only the leading two OSSL_FN_ULONGs
- * in the calculation of q, d * q might be greater than wnum
- * (but then (q-1) * d is less than or equal to wnum)
- */
- size_t j;
- for (l0 = 0 - l0, j = 0; j < sdivl; j++)
- tmp->d[j] = sdiv->d[j] & l0;
- l0 = bn_add_words(wnum, wnum, tmp->d, (int)sdivl);
- (*wnumtop) += l0;
- assert((*wnumtop) == 0);
-
- /* store part of the result */
- *--resp = quo;
- }
- /* snum holds remainder, it's as wide as divisor */
- if (r != NULL)
- copy_align_right(r, snum, norm_shift);
- /* res holds the quotient for a total of loop limbs, and is separate from q if ql < loop */
- if (q != NULL && q != res && OSSL_FN_copy_truncate(q, res) == 0)
- goto err;
-
- OSSL_FN_CTX_end(ctx, token);
- return 1;
-err:
- OSSL_FN_CTX_end(ctx, token);
- return 0;
-}
diff --git a/crypto/fn/fn_err.c b/crypto/fn/fn_err.c
deleted file mode 100644
index 69c137feac..0000000000
--- a/crypto/fn/fn_err.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Generated by util/mkerr.pl DO NOT EDIT
- * 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
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
-
-#include
-#include "crypto/fnerr.h"
-
-#ifndef OPENSSL_NO_ERR
-
-static const ERR_STRING_DATA OSSL_FN_str_reasons[] = {
- { ERR_PACK(ERR_LIB_OSSL_FN, 0, OSSL_FN_R_DIV_BY_ZERO), "div by zero" },
- { ERR_PACK(ERR_LIB_OSSL_FN, 0, OSSL_FN_R_INVALID_RANGE),
- "invalid range" },
- { ERR_PACK(ERR_LIB_OSSL_FN, 0, OSSL_FN_R_INPUT_NOT_REDUCED),
- "input not reduced" },
- { ERR_PACK(ERR_LIB_OSSL_FN, 0, OSSL_FN_R_INVALID_SHIFT),
- "invalid shift" },
- { ERR_PACK(ERR_LIB_OSSL_FN, 0, OSSL_FN_R_RESULT_ARG_TOO_SMALL),
- "result arg too small" },
- { ERR_PACK(ERR_LIB_OSSL_FN, 0, OSSL_FN_R_BITS_TOO_SMALL),
- "bits too small" },
- { ERR_PACK(ERR_LIB_OSSL_FN, 0, OSSL_FN_R_TOO_MANY_ITERATIONS),
- "too many iterations" },
- { 0, NULL }
-};
-
-#endif
-
-int ossl_err_load_OSSL_FN_strings(void)
-{
-#ifndef OPENSSL_NO_ERR
- if (ERR_reason_error_string(OSSL_FN_str_reasons[0].error) == NULL)
- ERR_load_strings_const(OSSL_FN_str_reasons);
-#endif
- return 1;
-}
diff --git a/crypto/fn/fn_intern.c b/crypto/fn/fn_intern.c
deleted file mode 100644
index 6113ccd215..0000000000
--- a/crypto/fn/fn_intern.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2025 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
- */
-
-#include "internal/cryptlib.h"
-#include "crypto/fn_intern.h"
-#include "crypto/fnerr.h"
-#include "fn_local.h"
-#include
-
-int ossl_fn_set_words(OSSL_FN *f, const OSSL_FN_ULONG *words, size_t limbs)
-{
- if (ossl_unlikely(f == NULL)) {
- ERR_raise(ERR_LIB_OSSL_FN, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
-
- if ((size_t)f->dsize < limbs) {
- ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_RESULT_ARG_TOO_SMALL);
- return 0;
- }
-
- memcpy(f->d, words, sizeof(OSSL_FN_ULONG) * limbs);
- memset(f->d + limbs, 0, sizeof(OSSL_FN_ULONG) * (f->dsize - limbs));
- return 1;
-}
-
-const OSSL_FN_ULONG *ossl_fn_get_words(const OSSL_FN *f)
-{
- if (ossl_unlikely(f == NULL)) {
- ERR_raise(ERR_LIB_OSSL_FN, ERR_R_PASSED_NULL_PARAMETER);
- return NULL;
- }
-
- return f->d;
-}
-
-size_t ossl_fn_get_dsize(const OSSL_FN *f)
-{
- return f->dsize;
-}
-
-bool ossl_fn_is_dynamically_allocated(const OSSL_FN *f)
-{
- return f->is_dynamically_allocated;
-}
-
-bool ossl_fn_is_securely_allocated(const OSSL_FN *f)
-{
- return f->is_securely_allocated;
-}
diff --git a/crypto/fn/fn_lib.c b/crypto/fn/fn_lib.c
deleted file mode 100644
index 08b78f6c02..0000000000
--- a/crypto/fn/fn_lib.c
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * Copyright 2025 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
- */
-
-#include
-#include
-#include
-#include
-#include
-#include "internal/common.h"
-#include "crypto/fnerr.h"
-#include "fn_local.h"
-#include "internal/constant_time.h"
-
-static OSSL_FN *ossl_fn_new_internal(size_t limbs, bool securely)
-{
- /* Total size of the whole OSSL_FN, in bytes */
- size_t totalsize = ossl_fn_totalsize(limbs);
- if (totalsize == 0)
- return NULL;
-
- OSSL_FN *ret = NULL;
-
- if (securely)
- ret = OPENSSL_secure_zalloc(totalsize);
- else
- ret = OPENSSL_zalloc(totalsize);
-
- if (ret != NULL) {
- ret->dsize = (int)limbs;
- ret->is_dynamically_allocated = 1;
- ret->is_securely_allocated = securely;
- }
- return ret;
-}
-
-static void ossl_fn_free_internal(OSSL_FN *f, bool clear)
-{
- if (f == NULL)
- return;
-
- size_t limbssize = f->dsize * sizeof(OSSL_FN_ULONG);
- size_t totalsize = limbssize + sizeof(OSSL_FN);
-
- if (f->is_dynamically_allocated) {
- if (f->is_securely_allocated)
- OPENSSL_secure_clear_free(f, totalsize);
- else if (clear)
- OPENSSL_clear_free(f, totalsize);
- else
- OPENSSL_free(f);
- } else if (clear) {
- OPENSSL_cleanse(f->d, limbssize);
- }
-}
-
-OSSL_FN *OSSL_FN_new_limbs(size_t size)
-{
- return ossl_fn_new_internal(size, false);
-}
-
-OSSL_FN *OSSL_FN_secure_new_limbs(size_t size)
-{
- return ossl_fn_new_internal(size, true);
-}
-
-OSSL_FN *OSSL_FN_new_bytes(size_t size)
-{
- return OSSL_FN_new_limbs(ossl_fn_bytes_to_limbs(size));
-}
-
-OSSL_FN *OSSL_FN_secure_new_bytes(size_t size)
-{
- return OSSL_FN_secure_new_limbs(ossl_fn_bytes_to_limbs(size));
-}
-
-OSSL_FN *OSSL_FN_new_bits(size_t size)
-{
- return OSSL_FN_new_bytes(ossl_fn_bits_to_bytes(size));
-}
-
-OSSL_FN *OSSL_FN_secure_new_bits(size_t size)
-{
- return OSSL_FN_secure_new_bytes(ossl_fn_bits_to_bytes(size));
-}
-
-void OSSL_FN_free(OSSL_FN *f)
-{
- ossl_fn_free_internal(f, false);
-}
-
-void OSSL_FN_clear_free(OSSL_FN *f)
-{
- ossl_fn_free_internal(f, true);
-}
-
-void OSSL_FN_clear(OSSL_FN *f)
-{
- size_t limbssize = f->dsize * sizeof(OSSL_FN_ULONG);
-
- OPENSSL_cleanse(f->d, limbssize);
-}
-
-/*-
- * Sets a->d[0] to |w| and zeroes the remaining limbs, so the full dsize
- * array reflects the value |w|. OSSL_FN is fixed-size: if a->dsize is 0
- * there is no limb to write and the call fails with
- * OSSL_FN_R_RESULT_ARG_TOO_SMALL (the same reason ossl_fn_set_words() raises
- * for an undersized destination).
- *
- * Constant-time with respect to |w|'s value: there is no value-dependent
- * control flow, since the full dsize array always holds the value. The only
- * branch is on the operand's public width (dsize).
- */
-int OSSL_FN_set_word(OSSL_FN *a, OSSL_FN_ULONG w)
-{
- size_t dsize = (size_t)a->dsize;
-
- if (ossl_unlikely(dsize < 1)) {
- ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_RESULT_ARG_TOO_SMALL);
- return 0;
- }
-
- a->d[0] = w;
- if (dsize > 1)
- memset(&a->d[1], 0, sizeof(OSSL_FN_ULONG) * (dsize - 1));
- return 1;
-}
-
-/*-
- * Equivalent to OSSL_FN_set_word(a, 1). Kept as a named function rather
- * than a macro or static inline, consistent with the rest of
- * crypto/fn/fn_lib.c. Leak profile as for OSSL_FN_set_word().
- */
-int OSSL_FN_one(OSSL_FN *a)
-{
- return OSSL_FN_set_word(a, OSSL_FN_ULONG_C(1));
-}
-
-/*-
- * Equivalent to OSSL_FN_set_word(a, 0). This is a plain value assignment,
- * not a secure wipe: the compiler may optimise the writes away if the value
- * is not subsequently observed. Use OSSL_FN_clear() (which calls
- * OPENSSL_cleanse()) when the limbs may hold secret data and must be wiped
- * irreversibly. Leak profile as for OSSL_FN_set_word().
- */
-int OSSL_FN_zero(OSSL_FN *a)
-{
- return OSSL_FN_set_word(a, OSSL_FN_ULONG_C(0));
-}
-
-static size_t ossl_fn_num_bits_word(OSSL_FN_ULONG l)
-{
- OSSL_FN_ULONG x, mask;
- size_t bits = (size_t)constant_time_select_int(
- (unsigned int)constant_time_is_zero_bn(l), 0, 1);
-
-#if OSSL_FN_BITS > 32
- x = l >> 32;
- mask = ~constant_time_is_zero_bn(x);
- bits += 32 & (size_t)mask;
- l ^= (x ^ l) & mask;
-#endif
-
- x = l >> 16;
- mask = ~constant_time_is_zero_bn(x);
- bits += 16 & (size_t)mask;
- l ^= (x ^ l) & mask;
-
- x = l >> 8;
- mask = ~constant_time_is_zero_bn(x);
- bits += 8 & (size_t)mask;
- l ^= (x ^ l) & mask;
-
- x = l >> 4;
- mask = ~constant_time_is_zero_bn(x);
- bits += 4 & (size_t)mask;
- l ^= (x ^ l) & mask;
-
- x = l >> 2;
- mask = ~constant_time_is_zero_bn(x);
- bits += 2 & (size_t)mask;
- l ^= (x ^ l) & mask;
-
- x = l >> 1;
- mask = ~constant_time_is_zero_bn(x);
- bits += 1 & (size_t)mask;
-
- return bits;
-}
-
-size_t OSSL_FN_num_bits(const OSSL_FN *a)
-{
- size_t i;
- size_t dsize = (size_t)a->dsize;
- size_t ret = 0;
-
- for (i = 0; i < dsize; i++) {
- size_t limb_bits = ossl_fn_num_bits_word(a->d[i]);
- size_t bits = i * OSSL_FN_BITS + limb_bits;
- size_t mask = (size_t)~constant_time_is_zero_bn(a->d[i]);
-
- ret = constant_time_select_s(mask, bits, ret);
- }
-
- return ret;
-}
-
-int OSSL_FN_cmp(const OSSL_FN *a, const OSSL_FN *b)
-{
- size_t i;
- size_t asize = (size_t)a->dsize;
- size_t bsize = (size_t)b->dsize;
- size_t max = asize > bsize ? asize : bsize;
- int res = 0;
-
- for (i = 0; i < max; i++) {
- OSSL_FN_ULONG aw = i < asize ? a->d[i] : 0;
- OSSL_FN_ULONG bw = i < bsize ? b->d[i] : 0;
-
- res = constant_time_select_int(
- (unsigned int)constant_time_lt_bn(aw, bw), -1, res);
- res = constant_time_select_int(
- (unsigned int)constant_time_lt_bn(bw, aw), 1, res);
- }
-
- return res;
-}
-
-/*-
- * Returns bit |n| of |a|. An out-of-range index (n < 0 or n >= the
- * operand's width in bits) reads as 0. The only control flow branches on
- * the operand's public width (dsize); the returned value is the bit itself,
- * which is the information the caller asked for.
- */
-int OSSL_FN_is_bit_set(const OSSL_FN *a, int n)
-{
- size_t limb, off;
-
- if (n < 0)
- return 0;
- limb = (size_t)n / OSSL_FN_BITS;
- off = (size_t)n % OSSL_FN_BITS;
- if (limb >= (size_t)a->dsize)
- return 0;
- return (a->d[limb] >> off) & OSSL_FN_ULONG_C(1);
-}
-
-/*-
- * Returns 1 if the unsigned value of |a| equals the single-limb word |w|.
- * Control flow branches only on the operand's public width (dsize); limb
- * values are combined with constant-time selects, so the number of limbs
- * inspected depends only on the public width, not on the operand's value.
- * The returned value is the equality test the caller asked for.
- */
-int OSSL_FN_is_word(const OSSL_FN *a, OSSL_FN_ULONG w)
-{
- size_t i;
- size_t dsize = (size_t)a->dsize;
- int res;
-
- if (dsize == 0)
- return w == 0;
-
- res = constant_time_select_int(
- (unsigned int)constant_time_eq_bn(a->d[0], w), 1, 0);
- for (i = 1; i < dsize; i++)
- res = constant_time_select_int(
- (unsigned int)constant_time_is_zero_bn(a->d[i]), res, 0);
- return res;
-}
-
-/*-
- * Equivalent to OSSL_FN_is_word(a, 0), kept as a named predicate for
- * readability at call sites. Leak profile as for OSSL_FN_is_word():
- * branches only on the operand's public width (dsize).
- */
-int OSSL_FN_is_zero(const OSSL_FN *a)
-{
- return OSSL_FN_is_word(a, 0);
-}
-
-/*-
- * Equivalent to OSSL_FN_is_word(a, 1), kept as a named predicate for
- * readability at call sites. Leak profile as for OSSL_FN_is_word():
- * branches only on the operand's public width (dsize).
- */
-int OSSL_FN_is_one(const OSSL_FN *a)
-{
- return OSSL_FN_is_word(a, 1);
-}
-
-/*-
- * Returns the least significant bit of |a|, which is the information the
- * caller asked for. The only control flow branches on the operand's public
- * width (dsize), not on limb values.
- */
-int OSSL_FN_is_odd(const OSSL_FN *a)
-{
- if (a->dsize <= 0)
- return 0;
- return (int)(a->d[0] & OSSL_FN_ULONG_C(1));
-}
-
-OSSL_FN *OSSL_FN_copy(OSSL_FN *a, const OSSL_FN *b)
-{
- if (ossl_unlikely(a == b))
- return a;
-
- size_t al = a->dsize;
- size_t bl = b->dsize;
-
- if (al < bl) {
- ERR_raise_data(ERR_LIB_OSSL_FN, OSSL_FN_R_RESULT_ARG_TOO_SMALL,
- "Needs to be at least %zu bytes, but is only %zu bytes",
- bl * sizeof(OSSL_FN_ULONG), al * sizeof(OSSL_FN_ULONG));
- return 0;
- }
-
- memcpy(a->d, b->d, bl * sizeof(OSSL_FN_ULONG));
- memset(a->d + bl, 0, (al - bl) * sizeof(OSSL_FN_ULONG));
- return a;
-}
-
-OSSL_FN *OSSL_FN_copy_truncate(OSSL_FN *a, const OSSL_FN *b)
-{
- if (ossl_unlikely(a == b))
- return a;
-
- size_t al = a->dsize;
- size_t bl = b->dsize;
-
- if (ossl_unlikely(al > bl)) {
- memcpy(a->d, b->d, bl * sizeof(OSSL_FN_ULONG));
- memset(&a->d[bl], 0, sizeof(OSSL_FN_ULONG) * (al - bl));
- } else {
- memcpy(a->d, b->d, al * sizeof(OSSL_FN_ULONG));
- }
-
- return a;
-}
diff --git a/crypto/fn/fn_local.h b/crypto/fn/fn_local.h
deleted file mode 100644
index 3cb6fc05ad..0000000000
--- a/crypto/fn/fn_local.h
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright 2025 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
- */
-
-#ifndef OSSL_CRYPTO_FN_LOCAL_H
-#define OSSL_CRYPTO_FN_LOCAL_H
-
-#include
-#include
-#include
-#include
-#include
-#include "internal/common.h"
-#include "crypto/fn.h"
-#include "crypto/fn_intern.h"
-
-#if OSSL_FN_BYTES == 4
-/* 32-bit systems */
-#define OSSL_FN_ULONG_C(n) UINT32_C(n)
-#define OSSL_FN_MASK UINT32_MAX
-#elif OSSL_FN_BYTES == 8
-#define OSSL_FN_ULONG_C(n) UINT64_C(n)
-#define OSSL_FN_MASK UINT64_MAX
-#else
-#error "OpenSSL doesn't support large numbers on this platform"
-#endif
-
-#define OSSL_FN_BITS (OSSL_FN_BYTES * 8)
-#define OSSL_FN_HIGH_BIT_MASK (OSSL_FN_ULONG_C(1) << (OSSL_FN_BITS - 1))
-#define OSSL_FN_LOW_HALF_MASK ((OSSL_FN_ULONG_C(1) << (OSSL_FN_BITS / 2)) - 1)
-#define OSSL_FN_HIGH_HALF_MASK (OSSL_FN_LOW_HALF_MASK << (OSSL_FN_BITS / 2))
-
-struct ossl_fn_st {
- /* Flag: alloced with OSSL_FN_new() or OSSL_FN_secure_new() */
- unsigned int is_dynamically_allocated : 1;
- /* Flag: alloced with OSSL_FN_secure_new() */
- unsigned int is_securely_allocated : 1;
-
- /*
- * The d array, with its size in number of OSSL_FN_ULONG.
- * This stores the number itself.
- *
- * Note: |dsize| is an int, because it turns out that some lower level
- * (possibly assembler) functions expect that type (especially, that
- * type size).
- * This deviates from the design in doc/designs/fixed-size-large-numbers.md
- */
- int dsize;
- OSSL_FN_ULONG d[];
-};
-
-static ossl_inline size_t ossl_fn_totalsize(size_t limbs)
-{
- /*
- * TODO(FIXNUM): Since the number of limbs is currently represented
- * as an 'int' in OSSL_FN, we must ensure that the desired size isn't
- * larger than can be represented.
- */
- if (ossl_unlikely(limbs >= INT_MAX))
- return 0;
-
- /*
- * sizeof(OSSL_FN) + limbs * sizeof(OSSL_FN_ULONG) > SIZE_MAX
- * => limbs * sizeof(OSSL_FN_ULONG) > SIZE_MAX - sizeof(OSSL_FN)
- * => limbs > (SIZE_MAX - sizeof(OSSL_FN)) / sizeof(OSSL_FN_ULONG)
- */
- if (ossl_unlikely(limbs > (SIZE_MAX - sizeof(OSSL_FN)) / sizeof(OSSL_FN_ULONG)))
- return 0;
- return sizeof(OSSL_FN) + limbs * sizeof(OSSL_FN_ULONG);
-}
-
-static ossl_inline size_t ossl_fn_bytes_to_limbs(size_t size)
-{
- return (size + sizeof(OSSL_FN_ULONG) - 1) / sizeof(OSSL_FN_ULONG);
-}
-
-static ossl_inline size_t ossl_fn_bits_to_bytes(size_t size)
-{
- return (size + 7) / 8;
-}
-
-/*
- * Internal functions to support BIGNUM's bn_expand_internal, BN_copy, and
- * similar.
- * The caller must ensure that src and dest are not NULL.
- * With ossl_fn_copy_internal, bn_words may be given -1 to signify that the
- * number of BN_ULONG should be found in src.
- */
-static ossl_inline OSSL_FN *ossl_fn_copy_internal_limbs(OSSL_FN *dest,
- const OSSL_FN_ULONG *src,
- int limbs)
-{
- if (ossl_unlikely(dest->dsize < limbs))
- return NULL;
- memcpy(dest->d, src, limbs * sizeof(dest->d[0]));
- memset(dest->d + limbs, 0, (dest->dsize - limbs) * sizeof(dest->d[0]));
- return dest;
-}
-
-static ossl_inline OSSL_FN *ossl_fn_copy_internal(OSSL_FN *dest,
- const OSSL_FN *src,
- int bn_words)
-{
- int words = bn_words < 0 ? src->dsize : bn_words;
-
- if (ossl_fn_copy_internal_limbs(dest, src->d, words) == NULL)
- return NULL;
- return dest;
-}
-
-/* OSSL_FN_CTX internals */
-
-struct ossl_fn_ctx_st {
- /*
- * Pointer to the last OSSL_FN_CTX_start() location (a simple pointer into
- * the memory area). See the struct ossl_fn_ctx_frame_st definition below
- * for details.
- */
- struct ossl_fn_ctx_frame_st *last_frame;
-
- /*
- * Flags
- */
- unsigned int is_securely_allocated : 1;
-
- /*
- * Current and peak usage tracking, by allocation components.
- * The |n_*| fields hold the currently active counts; the |peak_n_*|
- * fields hold the maximum each count has ever reached simultaneously.
- * This allows callers to determine suitable arena parameters for a
- * given workload without precise up-front prediction.
- */
- size_t n_frames;
- size_t n_numbers;
- size_t n_limbs;
- size_t peak_n_frames;
- size_t peak_n_numbers;
- size_t peak_n_limbs;
-
- /*
- * The arena itself.
- */
- size_t msize; /* Size of the arena, in bytes */
- unsigned char memory[];
-};
-
-struct ossl_fn_ctx_frame_st {
- /*
- * Pointer back to the whole arena where the frame is located,
- * for |last_frame| bookkeeping.
- */
- struct ossl_fn_ctx_st *arena;
- /*
- * Pointer to the previous frame in the arena, allowing OSSL_FN_CTX_end()
- * to do its job.
- */
- struct ossl_fn_ctx_frame_st *previous_frame;
- /*
- * Tracking for peak usage instrumentation. These count the OSSL_FN
- * instances and total limbs allocated within this frame.
- */
- size_t n_numbers;
- size_t n_limbs;
- /*
- * Every time OSSL_FN_CTX_get() is called, the current value of
- * |free_memory| is returned, and it's updated by incrementing it
- * by the number of bytes given by OSSL_FN_CTX_get().
- * The available number of bytes is limited by what's left in the arena.
- */
- unsigned char *free_memory; /* Pointer to the free area of the frame */
- size_t msize; /* Size of the frame, in bytes */
- unsigned char memory[];
-};
-
-/* end OSSL_FN_CTX internals */
-
-#endif
diff --git a/crypto/fn/fn_mod.c b/crypto/fn/fn_mod.c
deleted file mode 100644
index 110e8dc6b3..0000000000
--- a/crypto/fn/fn_mod.c
+++ /dev/null
@@ -1,564 +0,0 @@
-/*
- * Copyright 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
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
-
-#include "internal/cryptlib.h"
-#include "internal/nelem.h"
-#include "internal/safe_math.h"
-#include "crypto/fnerr.h"
-#include "fn_local.h"
-
-OSSL_SAFE_MATH_ADDU(size_t, size_t, OSSL_SAFE_MATH_MAXU(size_t))
-OSSL_SAFE_MATH_MULU(size_t, size_t, OSSL_SAFE_MATH_MAXU(size_t))
-
-static size_t ctx_add_size(size_t a, size_t b)
-{
- int err = 0;
- size_t r = safe_add_size_t(a, b, &err);
-
- return err == 0 ? r : 0;
-}
-
-static size_t ctx_max_size(size_t a, size_t b)
-{
- return a > b ? a : b;
-}
-
-/*
- * The *_ctx_size helpers below use local OSSL_FN headers with only |dsize|
- * set to represent temporaries that the corresponding operation allocates
- * with OSSL_FN_CTX_get_limbs(). This is enough for nested ctx-size helpers,
- * which only inspect operand sizes.
- */
-size_t OSSL_FN_mod_add_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
- const OSSL_FN *b, const OSSL_FN *m)
-{
- size_t tl, own_size, nested_size;
-
- if (r == NULL || a == NULL || b == NULL || m == NULL)
- return 0;
- int err = 0;
-
- tl = safe_add_size_t(a->dsize > b->dsize ? a->dsize : b->dsize,
- 1, &err);
- if (err != 0 || ossl_fn_totalsize(tl) == 0)
- return 0;
-
- OSSL_FN t = { .dsize = (int)tl };
-
- own_size = OSSL_FN_CTX_size(1, 1, tl);
- nested_size = OSSL_FN_mod_ctx_size(r, &t, m);
- if (own_size == 0 || nested_size == 0)
- return 0;
-
- return ctx_add_size(own_size, nested_size);
-}
-
-int OSSL_FN_mod_add(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
- const OSSL_FN *m, OSSL_FN_CTX *ctx)
-{
- const void *token = OSSL_FN_CTX_start(ctx);
- OSSL_FN *t;
- int ret = 0;
- size_t tl = (a->dsize > b->dsize ? a->dsize : b->dsize) + 1;
-
- if (token == NULL)
- return 0;
- if ((t = OSSL_FN_CTX_get_limbs(ctx, tl)) == NULL)
- goto err;
-
- ret = OSSL_FN_add(t, a, b)
- && OSSL_FN_mod(r, t, m, ctx);
-
-err:
- OSSL_FN_CTX_end(ctx, token);
- return ret;
-}
-
-/*
- * OSSL_FN_mod_add variant that may be used if both a and b are less than m.
- * The original formula is:
- *
- * r' = a + b
- * r = r′ − m[r′ ≥ m]
- *
- * This is replaced with addition, subtracting modulus, and conditional move
- * depending on whether or not subtraction borrowed.
- */
-int OSSL_FN_mod_add_quick(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
- const OSSL_FN *m)
-{
- size_t al = a->dsize;
- size_t bl = b->dsize;
- size_t rl = r->dsize;
- size_t ml = m->dsize;
- size_t aw = al < ml ? al : ml;
- size_t bw = bl < ml ? bl : ml;
- OSSL_FN_ULONG storage[2 * 1024 / OSSL_FN_BITS];
- OSSL_FN_ULONG *tp = storage;
- OSSL_FN_ULONG *mp = storage + ml;
- OSSL_FN_ULONG carry, borrow;
- size_t i;
-
- if (2 * ml > OSSL_NELEM(storage)) {
- tp = OPENSSL_malloc_array(2 * ml, sizeof(OSSL_FN_ULONG));
- if (tp == NULL)
- return 0;
- mp = tp + ml;
- }
-
- /* tp = a + b mod 2^(ml*bits) */
- carry = ossl_fn_add_words(tp, ml, a->d, aw, b->d, bw);
-
- /* mp = tp - m mod 2^(ml*bits) */
- borrow = ossl_fn_sub_words(mp, ml, tp, ml, m->d, ml);
-
- /*
- * Because a, b < m, we have a + b < 2m. Therefore tp < m whenever
- * carry = 1, which forces borrow = 1. The mask carry − borrow thus
- * only produces 0 (select tp2) or ~0 (select tp), matching exactly
- * whether a + b ≥ m.
- *
- * Thus, we have the cases:
- *
- * a + b < m => carry == 0, borrow == 1
- * m <= a+b < 2^(ml*bits) => carry == 0, borrow == 0
- * 2^(ml*bits) <= a+b < 2m => carry == 1, borrow == 1
- *
- * If (a + b < m), select tp; otherwise select tp2. Done with the
- * help of a mask.
- */
- OSSL_FN_ULONG mask = carry - borrow;
- size_t end = (rl < ml) ? rl : ml;
- for (i = 0; i < end; i++)
- r->d[i] = (mask & tp[i]) | (~mask & mp[i]);
- /* Make sure to pad r with zeroes when rl > ml */
- for (; i < rl; i++)
- r->d[i] = 0;
-
- if (tp != storage)
- OPENSSL_clear_free(tp, 2 * ml * sizeof(OSSL_FN_ULONG));
- else
- OPENSSL_cleanse(storage, sizeof(storage));
-
- return 1;
-}
-
-size_t OSSL_FN_mod_sub_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
- const OSSL_FN *b, const OSSL_FN *m)
-{
- size_t ml, n_numbers, own_size, mod_a_size, mod_b_size, nested_size;
-
- if (r == NULL || a == NULL || b == NULL || m == NULL)
- return 0;
-
- ml = m->dsize;
- n_numbers = (r == m) ? 3 : 2;
- if (ossl_fn_totalsize(ml) == 0)
- return 0;
-
- OSSL_FN am = { .dsize = (int)ml };
- OSSL_FN bm = { .dsize = (int)ml };
-
- own_size = OSSL_FN_CTX_size(1, n_numbers, n_numbers * ml);
- mod_a_size = OSSL_FN_mod_ctx_size(&am, a, m);
- mod_b_size = OSSL_FN_mod_ctx_size(&bm, b, m);
- nested_size = ctx_max_size(mod_a_size, mod_b_size);
- if (own_size == 0 || nested_size == 0)
- return 0;
-
- return ctx_add_size(own_size, nested_size);
-}
-
-int OSSL_FN_mod_sub(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
- const OSSL_FN *m, OSSL_FN_CTX *ctx)
-{
- const void *token = OSSL_FN_CTX_start(ctx);
- OSSL_FN *am, *bm, *rr = r;
- int ret = 0;
-
- if (token == NULL)
- return 0;
- if ((am = OSSL_FN_CTX_get_limbs(ctx, m->dsize)) == NULL
- || (bm = OSSL_FN_CTX_get_limbs(ctx, m->dsize)) == NULL)
- goto err;
-
- if (r == m && (rr = OSSL_FN_CTX_get_limbs(ctx, m->dsize)) == NULL)
- goto err;
-
- ret = OSSL_FN_mod(am, a, m, ctx)
- && OSSL_FN_mod(bm, b, m, ctx)
- && OSSL_FN_mod_sub_quick(rr, am, bm, m)
- && (rr == r || OSSL_FN_copy_truncate(r, rr) != NULL);
-
-err:
- OSSL_FN_CTX_end(ctx, token);
- return ret;
-}
-
-/*
- * OSSL_FN_mod_sub variant that may be used if a is less than m, while b is
- * of same bit width as m. It's implemented as subtraction followed by two
- * conditional additions.
- *
- * 0 <= a < m
- * 0 <= b < 2^w < 2*m
- *
- * after subtraction
- *
- * -2*m < r = a - b < m
- *
- * The original formula is:
- *
- * r' = a - b
- * r'' = r' + m[r' < 0]
- * r = r′' + m[r′' < 0]
- *
- * Because masking techniques are used, this is most efficiently
- * carried out with local loops rather than calling functions like
- * ossl_fn_add_words().
- */
-int OSSL_FN_mod_sub_quick(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
- const OSSL_FN *m)
-{
- if (r == m) {
- ERR_raise(ERR_LIB_OSSL_FN, ERR_R_PASSED_INVALID_ARGUMENT);
- return 0;
- }
-
- size_t al = a->dsize;
- size_t bl = b->dsize;
- size_t rl = r->dsize;
- size_t ml = m->dsize;
- size_t aw = al < ml ? al : ml;
- size_t bw = bl < ml ? bl : ml;
- OSSL_FN_ULONG storage[1024 / OSSL_FN_BITS];
- OSSL_FN_ULONG *tp = storage;
- size_t i;
- OSSL_FN_ULONG borrow, carry, ta, mask;
-
- if (ml > OSSL_NELEM(storage)) {
- tp = OPENSSL_malloc_array(ml, sizeof(OSSL_FN_ULONG));
- if (tp == NULL)
- return 0;
- }
-
- /* tp = a - b mod 2^(ml*bits) */
- borrow = ossl_fn_sub_words(tp, ml, a->d, aw, b->d, bw);
-
- /* If borrow, add m */
- for (i = 0, mask = 0 - borrow, carry = 0; i < ml; i++) {
- ta = ((m->d[i] & mask) + carry) & OSSL_FN_MASK;
- carry = (ta < carry);
- tp[i] = (tp[i] + ta) & OSSL_FN_MASK;
- carry += (tp[i] < ta);
- }
-
- /* If still borrow, add m again */
- borrow -= carry;
- for (i = 0, mask = 0 - borrow, carry = 0; i < ml; i++) {
- ta = ((m->d[i] & mask) + carry) & OSSL_FN_MASK;
- carry = (ta < carry);
- tp[i] = (tp[i] + ta) & OSSL_FN_MASK;
- carry += (tp[i] < ta);
- }
-
- for (i = 0; i < rl && i < ml; i++)
- r->d[i] = tp[i];
- /* Make sure to pad r with zeroes when rl > ml */
- for (; i < rl; i++)
- r->d[i] = 0;
-
- if (tp != storage)
- OPENSSL_clear_free(tp, ml * sizeof(OSSL_FN_ULONG));
- else
- OPENSSL_cleanse(storage, sizeof(storage));
-
- return 1;
-}
-
-size_t OSSL_FN_mod_mul_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
- const OSSL_FN *b, const OSSL_FN *m)
-{
- size_t tl, own_size, mul_size, mod_size, nested_size;
-
- if (r == NULL || a == NULL || b == NULL || m == NULL)
- return 0;
-
- if (a == b) {
- int err = 0;
-
- tl = safe_mul_size_t(2, a->dsize, &err);
- if (err != 0 || ossl_fn_totalsize(tl) == 0)
- return 0;
- OSSL_FN t = { .dsize = (int)tl };
-
- mul_size = OSSL_FN_sqr_ctx_size(&t, a);
- mod_size = OSSL_FN_mod_ctx_size(r, &t, m);
- } else {
- int err = 0;
-
- tl = safe_add_size_t(a->dsize, b->dsize, &err);
- if (err != 0 || ossl_fn_totalsize(tl) == 0)
- return 0;
- OSSL_FN t = { .dsize = (int)tl };
-
- mul_size = OSSL_FN_mul_ctx_size(&t, a, b);
- mod_size = OSSL_FN_mod_ctx_size(r, &t, m);
- }
-
- own_size = OSSL_FN_CTX_size(1, 1, tl);
- nested_size = ctx_max_size(mul_size, mod_size);
- if (own_size == 0 || nested_size == 0)
- return 0;
-
- return ctx_add_size(own_size, nested_size);
-}
-
-/* slow but works */
-int OSSL_FN_mod_mul(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
- const OSSL_FN *m, OSSL_FN_CTX *ctx)
-{
- const void *token = OSSL_FN_CTX_start(ctx);
- OSSL_FN *t;
- int ret = 0;
-
- if (token == NULL)
- return 0;
-
- if (a == b) {
- size_t tl = 2 * a->dsize;
-
- if ((t = OSSL_FN_CTX_get_limbs(ctx, tl)) == NULL
- || !OSSL_FN_sqr(t, a, ctx))
- goto err;
- } else {
- size_t tl = a->dsize + b->dsize;
-
- if ((t = OSSL_FN_CTX_get_limbs(ctx, tl)) == NULL
- || !OSSL_FN_mul(t, a, b, ctx))
- goto err;
- }
- if (!OSSL_FN_mod(r, t, m, ctx))
- goto err;
- ret = 1;
-err:
- OSSL_FN_CTX_end(ctx, token);
- return ret;
-}
-
-size_t OSSL_FN_mod_sqr_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
- const OSSL_FN *m)
-{
- size_t tl, own_size, sqr_size, mod_size, nested_size;
-
- if (r == NULL || a == NULL || m == NULL)
- return 0;
- int err = 0;
-
- tl = safe_mul_size_t(2, a->dsize, &err);
- if (err != 0 || ossl_fn_totalsize(tl) == 0)
- return 0;
-
- OSSL_FN t = { .dsize = (int)tl };
-
- own_size = OSSL_FN_CTX_size(1, 1, tl);
- sqr_size = OSSL_FN_sqr_ctx_size(&t, a);
- mod_size = OSSL_FN_mod_ctx_size(r, &t, m);
- nested_size = ctx_max_size(sqr_size, mod_size);
- if (own_size == 0 || nested_size == 0)
- return 0;
-
- return ctx_add_size(own_size, nested_size);
-}
-
-int OSSL_FN_mod_sqr(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *m,
- OSSL_FN_CTX *ctx)
-{
- const void *token = OSSL_FN_CTX_start(ctx);
- OSSL_FN *t;
- int ret = 0;
-
- if (token == NULL)
- return 0;
- if ((t = OSSL_FN_CTX_get_limbs(ctx, (size_t)(2 * a->dsize))) == NULL)
- goto err;
-
- ret = OSSL_FN_sqr(t, a, ctx)
- && OSSL_FN_mod(r, t, m, ctx);
-
-err:
- OSSL_FN_CTX_end(ctx, token);
- return ret;
-}
-
-size_t OSSL_FN_mod_lshift1_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
- const OSSL_FN *m)
-{
- size_t tl, own_size, nested_size;
-
- if (r == NULL || a == NULL || m == NULL)
- return 0;
- int err = 0;
-
- tl = safe_add_size_t(m->dsize, 1, &err);
- if (err != 0 || ossl_fn_totalsize(tl) == 0)
- return 0;
-
- OSSL_FN t = { .dsize = (int)tl };
-
- own_size = OSSL_FN_CTX_size(1, 1, tl);
- nested_size = OSSL_FN_mod_ctx_size(r, &t, m);
- if (own_size == 0 || nested_size == 0)
- return 0;
-
- return ctx_add_size(own_size, nested_size);
-}
-
-int OSSL_FN_mod_lshift1(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *m,
- OSSL_FN_CTX *ctx)
-{
- const void *token = OSSL_FN_CTX_start(ctx);
- OSSL_FN *t;
- int ret = 0;
-
- if (token == NULL)
- return 0;
- if ((t = OSSL_FN_CTX_get_limbs(ctx, (size_t)(m->dsize + 1))) == NULL)
- goto err;
-
- ret = OSSL_FN_lshift1(t, a)
- && OSSL_FN_mod(r, t, m, ctx);
-
-err:
- OSSL_FN_CTX_end(ctx, token);
- return ret;
-}
-
-/* OSSL_FN_mod_lshift1 variant that may be used if a is less than m */
-int OSSL_FN_mod_lshift1_quick(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *m)
-{
- OSSL_FN *t = OSSL_FN_new_limbs((size_t)(m->dsize + 1));
- int ret = 0;
-
- if (t == NULL)
- return 0;
- if (!OSSL_FN_lshift1(t, a))
- goto err;
- if (OSSL_FN_cmp(t, m) >= 0) {
- if (!OSSL_FN_sub(t, t, m))
- goto err;
- }
- OSSL_FN_copy_truncate(r, t);
- ret = 1;
-err:
- OSSL_FN_free(t);
- return ret;
-}
-
-size_t OSSL_FN_mod_lshift_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
- int n, const OSSL_FN *m)
-{
- size_t ml, own_size, nested_size;
-
- if (r == NULL || a == NULL || m == NULL)
- return 0;
- (void)n;
-
- ml = m->dsize;
- if (ossl_fn_totalsize(ml) == 0)
- return 0;
-
- OSSL_FN ra = { .dsize = (int)ml };
-
- own_size = OSSL_FN_CTX_size(1, 1, ml);
- nested_size = OSSL_FN_mod_ctx_size(&ra, a, m);
- if (own_size == 0 || nested_size == 0)
- return 0;
-
- return ctx_add_size(own_size, nested_size);
-}
-
-int OSSL_FN_mod_lshift(OSSL_FN *r, const OSSL_FN *a, int n, const OSSL_FN *m,
- OSSL_FN_CTX *ctx)
-{
- const void *token = OSSL_FN_CTX_start(ctx);
- OSSL_FN *ra;
- int ret = 0;
-
- if (token == NULL)
- return 0;
- if ((ra = OSSL_FN_CTX_get_limbs(ctx, m->dsize)) == NULL)
- goto err;
-
- ret = OSSL_FN_mod(ra, a, m, ctx)
- && OSSL_FN_mod_lshift_quick(r, ra, n, m);
-
-err:
- OSSL_FN_CTX_end(ctx, token);
- return ret;
-}
-
-/* OSSL_FN_mod_lshift variant that may be used if a is less than m */
-int OSSL_FN_mod_lshift_quick(OSSL_FN *r, const OSSL_FN *a, int n,
- const OSSL_FN *m)
-{
- OSSL_FN *t = NULL;
- int ret = 0;
-
- if (n <= 0)
- return n == 0 ? (OSSL_FN_copy_truncate(r, a) != NULL) : 0;
-
- t = OSSL_FN_new_limbs((size_t)(m->dsize + 1));
- if (t == NULL)
- goto err;
-
- if (OSSL_FN_copy_truncate(t, a) == NULL)
- goto err;
-
- while (n > 0) {
- size_t m_bits = OSSL_FN_num_bits(m);
- size_t t_bits = OSSL_FN_num_bits(t);
- size_t max_shift;
-
- /* 0 <= t < m */
- if (m_bits < t_bits) {
- ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_INPUT_NOT_REDUCED);
- goto err;
- }
- max_shift = m_bits - t_bits;
-
- if (max_shift > (size_t)n)
- max_shift = (size_t)n;
-
- if (max_shift) {
- int shift = (int)max_shift;
-
- if (!OSSL_FN_lshift(t, t, shift))
- goto err;
- n -= shift;
- } else {
- if (!OSSL_FN_lshift1(t, t))
- goto err;
- n--;
- }
-
- if (OSSL_FN_cmp(t, m) >= 0) {
- if (!OSSL_FN_sub(t, t, m))
- goto err;
- }
- }
-
- if (OSSL_FN_copy_truncate(r, t) == NULL)
- goto err;
- ret = 1;
-
-err:
- OSSL_FN_free(t);
- return ret;
-}
diff --git a/crypto/fn/fn_mul.c b/crypto/fn/fn_mul.c
deleted file mode 100644
index 4b5b50e83b..0000000000
--- a/crypto/fn/fn_mul.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2025 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
- */
-
-#include
-#include
-#include "crypto/cryptlib.h"
-#include "crypto/fnerr.h"
-#include "../bn/bn_local.h" /* For using the low level bignum functions */
-#include "fn_local.h"
-
-size_t OSSL_FN_mul_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
- const OSSL_FN *b)
-{
- size_t limbs = 0;
-
- if (r == NULL || a == NULL || b == NULL)
- return 0;
- if (r == a || r == b)
- limbs = r->dsize;
-
- return OSSL_FN_CTX_size(1, limbs == 0 ? 0 : 1, limbs);
-}
-
-int OSSL_FN_mul(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b, OSSL_FN_CTX *ctx)
-{
- size_t al = (size_t)a->dsize;
- size_t bl = (size_t)b->dsize;
- size_t rl = (size_t)r->dsize;
- size_t max = (size_t)(al + bl);
- const void *token = OSSL_FN_CTX_start(ctx);
- if (token == NULL)
- return 0;
-
- int ret = 0;
-#ifdef BN_MUL_COMBA
- if (al == bl) {
- if (rl >= 16 && al == 8) {
- bn_mul_comba8(r->d, a->d, b->d);
- goto end;
- }
- }
-#endif /* BN_MUL_COMBA */
-
- OSSL_FN *rr = r;
- if ((r == a) || (r == b))
- if ((rr = OSSL_FN_CTX_get_limbs(ctx, rl)) == NULL)
- goto err;
-
- bn_mul_truncated(rr->d, (int)rl, a->d, (int)al, b->d, (int)bl);
-
- if (rr != r)
- if (OSSL_FN_copy(r, rr) == NULL)
- goto err;
-
-#ifdef BN_MUL_COMBA
-end:
-#endif
-
-{
- size_t dif = (rl > max) ? rl - max : 0;
- OSSL_FN_ULONG *rp = &r->d[max];
- while (dif > 0) {
- *rp++ = 0;
- dif--;
- }
-}
-
- ret = 1;
-err:
- OSSL_FN_CTX_end(ctx, token);
- return ret;
-}
diff --git a/crypto/fn/fn_rand.c b/crypto/fn/fn_rand.c
deleted file mode 100644
index 369b57d9b0..0000000000
--- a/crypto/fn/fn_rand.c
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright 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
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
-
-#include
-#include
-#include "crypto/fnerr.h"
-#include "fn_local.h"
-
-/*
- * Internal flag selecting which DRBG pool the bytes are drawn from.
- * NORMAL routes through RAND_bytes_ex(), PRIVATE through
- * RAND_priv_bytes_ex() (a non-forward-linkable source). The same shaping
- * code feeds either pool; the flag selects which one, mirroring the
- * public/private split exposed by the OSSL_FN_rand() / OSSL_FN_priv_rand()
- * entry points.
- */
-enum ossl_fn_rand_flag {
- NORMAL = 0,
- PRIVATE
-};
-
-/* Set bit |pos| (0 = least significant) of |a|, by absolute position. */
-static void ossl_fn_set_bit(OSSL_FN *a, size_t pos)
-{
- a->d[pos / OSSL_FN_BITS] |= OSSL_FN_ULONG_C(1) << (pos % OSSL_FN_BITS);
-}
-
-/*-
- * ossl_fn_rand() fills |rnd| with |bits| random bits, shaping the top and
- * bottom bits per the |top|/|bottom| requests. The random bytes are drawn
- * directly into rnd->d's byte image (a whole number of limbs, so the result
- * is a random value regardless of the machine's byte order), and the
- * top/bottom/mask shaping is done directly on rnd->d's limbs as value
- * operations -- set bit |bits|-1 for TOP_ONE, bits |bits|-1 and |bits|-2
- * for TOP_TWO, clear the high bits of the top limb at |bits| and above,
- * set bit 0 for BOTTOM_ODD. No intermediate byte buffer is needed, since
- * OSSL_FN's limbs are fixed-size.
- *
- * A destination too small for |bits| is an error
- * (OSSL_FN_R_RESULT_ARG_TOO_SMALL), not an implicit expansion.
- *
- * The leak profile: control flow branches on |bits|, |top|, |bottom| (all
- * caller-chosen, public) and on the byte-draw return value, never on the
- * random bytes themselves. The result value of OSSL_FN_rand() /
- * OSSL_FN_priv_rand() is, of course, the random number the caller asked for.
- */
-static int ossl_fn_rand(enum ossl_fn_rand_flag flag, OSSL_FN *rnd, size_t bits,
- int top, int bottom, size_t strength,
- OSSL_LIB_CTX *libctx)
-{
- size_t limbs_needed, top_limb, i;
-
- if (rnd == NULL) {
- ERR_raise(ERR_LIB_OSSL_FN, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
-
- if (bits == 0) {
- if (top != OSSL_FN_RAND_TOP_ANY || bottom != OSSL_FN_RAND_BOTTOM_ANY)
- goto toosmall;
- return OSSL_FN_zero(rnd);
- }
- /* TOP_TWO forces two high bits, so it needs at least two bits. */
- if (top == OSSL_FN_RAND_TOP_TWO && bits < 2)
- goto toosmall;
-
- limbs_needed = bits / OSSL_FN_BITS;
- limbs_needed += (bits % OSSL_FN_BITS != 0) ? 1 : 0;
- if (limbs_needed > (size_t)rnd->dsize) {
- ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_RESULT_ARG_TOO_SMALL);
- return 0;
- }
- top_limb = limbs_needed - 1;
-
- /*
- * Draw random bytes directly into rnd->d's byte image. A whole number
- * of limbs is filled so the result is a random value regardless of the
- * machine's byte order; the high bits of the top limb beyond |bits| are
- * masked off below. The pool is selected by |flag|.
- */
- {
- size_t fill_bytes = limbs_needed * OSSL_FN_BYTES;
- int b = (flag == NORMAL)
- ? RAND_bytes_ex(libctx, (unsigned char *)rnd->d, fill_bytes,
- (unsigned int)strength)
- : RAND_priv_bytes_ex(libctx, (unsigned char *)rnd->d, fill_bytes,
- (unsigned int)strength);
-
- if (b <= 0)
- return 0;
- }
-
- /*
- * TODO(FIXNUM): a testing variant that mangles the byte buffer to
- * generate patterns more likely to trigger library bugs is not wired up
- * yet; if an OSSL_FN_bntest_rand() analogue is added for test coverage,
- * this is the spot for the mangle step.
- */
-
- /* Zero any limbs above those the bytes filled. */
- for (i = limbs_needed; i < (size_t)rnd->dsize; i++)
- rnd->d[i] = 0;
-
- /* Clear the high bits of the top limb at |bits| and above. */
- if (bits % OSSL_FN_BITS != 0)
- rnd->d[top_limb] &= (OSSL_FN_ULONG_C(1) << (bits % OSSL_FN_BITS)) - 1;
-
- /* Set the requested top bit(s); |bits| >= 2 is guaranteed for TOP_TWO. */
- if (top != OSSL_FN_RAND_TOP_ANY) {
- ossl_fn_set_bit(rnd, bits - 1);
- if (top == OSSL_FN_RAND_TOP_TWO)
- ossl_fn_set_bit(rnd, bits - 2);
- }
-
- /* Set the bottom bit if requested. */
- if (bottom == OSSL_FN_RAND_BOTTOM_ODD)
- rnd->d[0] |= OSSL_FN_ULONG_C(1);
-
- return 1;
-
-toosmall:
- ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_BITS_TOO_SMALL);
- return 0;
-}
-
-/* Draw from the public DRBG pool (NORMAL). */
-int OSSL_FN_rand(OSSL_FN *rnd, size_t bits, int top, int bottom,
- size_t strength, OSSL_LIB_CTX *libctx)
-{
- return ossl_fn_rand(NORMAL, rnd, bits, top, bottom, strength, libctx);
-}
-
-/* Draw from the private DRBG pool (PRIVATE). */
-int OSSL_FN_priv_rand(OSSL_FN *rnd, size_t bits, int top, int bottom,
- size_t strength, OSSL_LIB_CTX *libctx)
-{
- return ossl_fn_rand(PRIVATE, rnd, bits, top, bottom, strength, libctx);
-}
-
-/*-
- * ossl_fn_rand_range() produces 0 <= r < range by rejection sampling. The
- * libctx comes directly as an argument, as in ossl_fn_rand(); sign is never
- * considered, since OSSL_FN is unsigned.
- *
- * The leak profile: control flow branches on |range|'s top bit pattern and on
- * |r|'s width (both public), and the loop iteration count leaks the magnitude
- * of |range| (via OSSL_FN_num_bits) and the rejection probability.
- *
- * The destination |r| must be sized to hold at least |num_bits(range)| bits.
- * The "range = 100..._2" path draws n + 1 bits and is taken only when |r|
- * has room for them; an exactly-sized |r| (room for exactly n bits) uses the
- * standard n-bit rejection path instead.
- */
-static int ossl_fn_rand_range(enum ossl_fn_rand_flag flag, OSSL_FN *r,
- const OSSL_FN *range, size_t strength,
- OSSL_LIB_CTX *libctx)
-{
- size_t n;
- int count = 100;
-
- if (r == NULL) {
- ERR_raise(ERR_LIB_OSSL_FN, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
-
- if (OSSL_FN_is_zero(range)) {
- ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_INVALID_RANGE);
- return 0;
- }
-
- n = OSSL_FN_num_bits(range); /* n > 0 */
-
- /* OSSL_FN_is_bit_set(range, n - 1) always holds */
-
- if (n == 1) {
- return OSSL_FN_zero(r);
- } else if (!OSSL_FN_is_bit_set(range, (int)(n - 2))
- && !OSSL_FN_is_bit_set(range, (int)(n - 3))
- && n < (size_t)r->dsize * OSSL_FN_BITS) {
- /*
- * range = 100..._2, so 3*range (= 11..._2) is exactly one bit longer
- * than range. This draws n + 1 bits, so it is taken only when |r| has
- * room for them; an exactly-sized |r| (room for exactly n bits) falls
- * through to the standard n-bit rejection path below.
- */
- do {
- if (!ossl_fn_rand(flag, r, n + 1, OSSL_FN_RAND_TOP_ANY,
- OSSL_FN_RAND_BOTTOM_ANY, strength, libctx))
- return 0;
-
- /*
- * If r < 3*range, use r := r MOD range (which is either r, r -
- * range, or r - 2*range). Otherwise, iterate once more. Since
- * 3*range = 11..._2, each iteration succeeds with probability >=
- * .75.
- */
- if (OSSL_FN_cmp(r, range) >= 0) {
- if (!OSSL_FN_sub(r, r, range))
- return 0;
- if (OSSL_FN_cmp(r, range) >= 0)
- if (!OSSL_FN_sub(r, r, range))
- return 0;
- }
-
- if (!--count) {
- ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_TOO_MANY_ITERATIONS);
- return 0;
- }
-
- } while (OSSL_FN_cmp(r, range) >= 0);
- } else {
- do {
- /* range = 11..._2 or range = 101..._2 */
- if (!ossl_fn_rand(flag, r, n, OSSL_FN_RAND_TOP_ANY,
- OSSL_FN_RAND_BOTTOM_ANY, strength, libctx))
- return 0;
-
- if (!--count) {
- ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_TOO_MANY_ITERATIONS);
- return 0;
- }
- } while (OSSL_FN_cmp(r, range) >= 0);
- }
-
- return 1;
-}
-
-/* Draw from the public DRBG pool (NORMAL). */
-int OSSL_FN_rand_range(OSSL_FN *r, const OSSL_FN *range, size_t strength,
- OSSL_LIB_CTX *libctx)
-{
- return ossl_fn_rand_range(NORMAL, r, range, strength, libctx);
-}
-
-/* Draw from the private DRBG pool (PRIVATE). */
-int OSSL_FN_priv_rand_range(OSSL_FN *r, const OSSL_FN *range,
- size_t strength, OSSL_LIB_CTX *libctx)
-{
- return ossl_fn_rand_range(PRIVATE, r, range, strength, libctx);
-}
diff --git a/crypto/fn/fn_shift.c b/crypto/fn/fn_shift.c
deleted file mode 100644
index fe0dfa5d2c..0000000000
--- a/crypto/fn/fn_shift.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright 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
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
-
-#include
-#include
-#include "crypto/fnerr.h"
-#include "fn_local.h"
-
-/*
- * In respect to shift factor the execution time is invariant of
- * |n % OSSL_FN_BITS|, but not |n / OSSL_FN_BITS|. Or in other words
- * pre-condition for constant-time-ness is |n < OSSL_FN_BITS| or
- * |n / OSSL_FN_BITS| being non-secret.
- */
-int OSSL_FN_lshift(OSSL_FN *r, const OSSL_FN *a, int n)
-{
- size_t i, nw;
- unsigned int lb, rb;
- const OSSL_FN_ULONG *ap = a->d;
- OSSL_FN_ULONG *rp = r->d;
- size_t rl = (size_t)r->dsize;
- size_t al = (size_t)a->dsize;
-
- if (n < 0) {
- ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_INVALID_SHIFT);
- return 0;
- }
-
- nw = (size_t)n / OSSL_FN_BITS;
- if (nw >= rl) {
- memset(rp, 0, sizeof(*rp) * rl);
- return 1;
- }
-
- lb = (unsigned int)n % OSSL_FN_BITS;
- rb = OSSL_FN_BITS - lb;
-
- /*
- * Work from the high end to support r == a. Each result limb only
- * depends on the corresponding source limb and the limb just below it,
- * neither of which has been overwritten yet when walking downward.
- */
- for (i = rl; i > 0; i--) {
- size_t r_idx = i - 1;
- OSSL_FN_ULONG limb = 0;
-
- if (r_idx >= nw) {
- size_t src_idx = r_idx - nw;
-
- if (src_idx < al)
- limb = (ap[src_idx] << lb) & OSSL_FN_MASK;
- if (lb != 0 && src_idx > 0 && src_idx - 1 < al)
- limb |= ap[src_idx - 1] >> rb;
- }
- rp[r_idx] = limb;
- }
-
- return 1;
-}
-
-int OSSL_FN_lshift1(OSSL_FN *r, const OSSL_FN *a)
-{
- OSSL_FN_ULONG *rp = r->d;
- const OSSL_FN_ULONG *ap = a->d;
- OSSL_FN_ULONG t, c = 0;
- size_t rl = (size_t)r->dsize;
- size_t al = (size_t)a->dsize;
- size_t l = (rl < al) ? rl : al;
- size_t i;
-
- for (i = 0; i < l; i++) {
- t = ap[i];
- rp[i] = ((t << 1) | c) & OSSL_FN_MASK;
- c = t >> (OSSL_FN_BITS - 1);
- }
-
- if (i < rl) {
- rp[i++] = c;
- for (; i < rl; i++)
- rp[i] = 0;
- }
-
- return 1;
-}
-
-/*
- * In respect to shift factor the execution time is invariant of
- * |n % OSSL_FN_BITS|, but not |n / OSSL_FN_BITS|. Or in other words
- * pre-condition for constant-time-ness for sufficiently[!] zero-padded
- * inputs is |n < OSSL_FN_BITS| or |n / OSSL_FN_BITS| being non-secret.
- */
-int OSSL_FN_rshift(OSSL_FN *r, const OSSL_FN *a, int n)
-{
- size_t i, nw;
- unsigned int lb, rb;
- const OSSL_FN_ULONG *ap = a->d;
- OSSL_FN_ULONG *rp = r->d;
- size_t rl = (size_t)r->dsize;
- size_t al = (size_t)a->dsize;
-
- if (n < 0) {
- ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_INVALID_SHIFT);
- return 0;
- }
-
- nw = (size_t)n / OSSL_FN_BITS;
- rb = (unsigned int)n % OSSL_FN_BITS;
- lb = OSSL_FN_BITS - rb;
-
- /*
- * Work from the low end to support r == a. Each result limb only
- * depends on the corresponding source limb and the limb just above it,
- * neither of which has been overwritten yet when walking upward.
- */
- for (i = 0; i < rl; i++) {
- size_t src_idx = i + nw;
- OSSL_FN_ULONG limb = 0;
-
- if (src_idx < al) {
- limb = ap[src_idx] >> rb;
- if (rb != 0 && src_idx + 1 < al)
- limb |= (ap[src_idx + 1] << lb) & OSSL_FN_MASK;
- }
- rp[i] = limb;
- }
-
- return 1;
-}
-
-int OSSL_FN_rshift1(OSSL_FN *r, const OSSL_FN *a)
-{
- OSSL_FN_ULONG *rp = r->d;
- const OSSL_FN_ULONG *ap = a->d;
- size_t rl = (size_t)r->dsize;
- size_t al = (size_t)a->dsize;
- size_t i;
-
- /*
- * Work from the low end to support r == a. Each result limb only
- * depends on the corresponding source limb and the limb just above it,
- * neither of which has been overwritten yet when walking upward.
- */
- for (i = 0; i < rl; i++) {
- OSSL_FN_ULONG limb = 0;
-
- if (i < al) {
- limb = ap[i] >> 1;
- if (i + 1 < al)
- limb |= (ap[i + 1] << (OSSL_FN_BITS - 1)) & OSSL_FN_MASK;
- }
- rp[i] = limb;
- }
-
- return 1;
-}
diff --git a/crypto/fn/fn_sqr.c b/crypto/fn/fn_sqr.c
deleted file mode 100644
index 698d33c286..0000000000
--- a/crypto/fn/fn_sqr.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright 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
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
-
-#include
-#include
-#include "internal/safe_math.h"
-#include "crypto/cryptlib.h"
-#include "crypto/fnerr.h"
-#include "../bn/bn_local.h" /* For using the low level bignum functions */
-#include "fn_local.h"
-
-OSSL_SAFE_MATH_MULU(size_t, size_t, OSSL_SAFE_MATH_MAXU(size_t))
-
-size_t OSSL_FN_sqr_ctx_size(const OSSL_FN *r, const OSSL_FN *a)
-{
- size_t max, limbs, n_numbers = 1;
-
- if (r == NULL || a == NULL)
- return 0;
- int err = 0;
-
- max = safe_mul_size_t(2, a->dsize, &err);
- if ((size_t)r->dsize < max)
- n_numbers++;
- limbs = safe_mul_size_t(n_numbers, max, &err);
-
- return err == 0 ? OSSL_FN_CTX_size(1, n_numbers, limbs) : 0;
-}
-
-int OSSL_FN_sqr(OSSL_FN *r, const OSSL_FN *a, OSSL_FN_CTX *ctx)
-{
- const void *token = OSSL_FN_CTX_start(ctx);
- if (token == NULL)
- return 0;
-
- size_t al = (size_t)a->dsize;
- size_t rl = (size_t)r->dsize;
- size_t max = (size_t)(2 * al);
-
- int ret = 0;
-#ifdef BN_SQR_COMBA
- if (al == 4 && rl >= 8) {
- bn_sqr_comba4(r->d, a->d);
- goto end;
- } else if (al == 8 && rl >= 16) {
- bn_sqr_comba8(r->d, a->d);
- goto end;
- }
-#endif
-
- /* rl < max is always true when r == a, so covers that case too */
- OSSL_FN *rr = r;
- if (rl < max)
- if ((rr = OSSL_FN_CTX_get_limbs(ctx, max)) == NULL)
- goto err;
-
- OSSL_FN *tmp = NULL;
- if ((tmp = OSSL_FN_CTX_get_limbs(ctx, max)) == NULL)
- goto err;
-
- if (al != 0)
- bn_sqr_normal(rr->d, a->d, (int)al, tmp->d);
-
- if (rr != r) {
- /*
- * We use OSSL_FN_copy_truncate() here, because OSSL_FN_copy() expects
- * to make a full copy, but r may be smaller than rr
- */
- OSSL_FN_copy_truncate(r, rr);
- }
-
-#ifdef BN_SQR_COMBA
-end:
-#endif
-
- ret = 1;
-
- /* Zeroise everything above the result, if the r is that large */
- size_t dif = (rl > max) ? rl - max : 0;
- OSSL_FN_ULONG *rp = &r->d[max];
- while (dif > 0) {
- *rp++ = 0;
- dif--;
- }
-
-err:
- OSSL_FN_CTX_end(ctx, token);
- return ret;
-}
diff --git a/crypto/getenv.c b/crypto/getenv.c
index aa01ea8af7..8ea7128864 100644
--- a/crypto/getenv.c
+++ b/crypto/getenv.c
@@ -17,7 +17,7 @@
char *ossl_safe_getenv(const char *name)
{
-#if defined(_WIN32) && defined(CP_UTF8) && !defined(_WIN32_WCE)
+#if defined(_WIN32) && defined(CP_UTF8)
if (GetEnvironmentVariableW(L"OPENSSL_WIN32_UTF8", NULL, 0) != 0) {
char *val = NULL;
int vallen = 0;
diff --git a/crypto/hmac/hmac.c b/crypto/hmac/hmac.c
index 400dde4d40..f12b5bf0b3 100644
--- a/crypto/hmac/hmac.c
+++ b/crypto/hmac/hmac.c
@@ -53,9 +53,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);
- if (rv >= 1)
- return rv;
+ {
+ int ret = s390x_HMAC_init(ctx, key, len);
+ if (ret != -1) /* -1 means SW fallback */
+ return ret;
+ }
#endif
if (key != NULL) {
diff --git a/crypto/info.c b/crypto/info.c
index 2038db5a52..4baece2246 100644
--- a/crypto/info.c
+++ b/crypto/info.c
@@ -7,6 +7,7 @@
* https://www.openssl.org/source/license.html
*/
+#include
#include
#include "crypto/rand.h"
#include "crypto/dso_conf.h"
@@ -49,70 +50,75 @@ char ossl_cpu_info_str[CPU_INFO_STR_LEN] = "";
static CRYPTO_ONCE init_info = CRYPTO_ONCE_STATIC_INIT;
+/*
+ * Append a printf-formatted suffix to ossl_cpu_info_str, truncating to
+ * fit. The first call writes the base string (the buffer starts empty,
+ * so off == 0); subsequent calls extend it.
+ */
+static ossl_unused void cpu_info_append(const char *fmt, ...)
+{
+ size_t off = strlen(ossl_cpu_info_str);
+ va_list args;
+
+ if (off >= sizeof(ossl_cpu_info_str))
+ return;
+ va_start(args, fmt);
+ (void)vsnprintf(ossl_cpu_info_str + off,
+ sizeof(ossl_cpu_info_str) - off, fmt, args);
+ va_end(args);
+}
+
DEFINE_RUN_ONCE_STATIC(init_info_strings)
{
#if defined(OPENSSL_CPUID_OBJ)
#if defined(__i386) || defined(__i386__) || defined(_M_IX86) || defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)
const char *env;
- BIO_snprintf(ossl_cpu_info_str, sizeof(ossl_cpu_info_str),
- CPUINFO_PREFIX "OPENSSL_ia32cap=0x%.16llx:0x%.16llx:0x%.16llx:0x%.16llx:0x%.16llx",
+ cpu_info_append(CPUINFO_PREFIX
+ "OPENSSL_ia32cap=0x%.16llx:0x%.16llx:0x%.16llx:0x%.16llx:0x%.16llx",
(unsigned long long)OPENSSL_ia32cap_P[0] | (unsigned long long)OPENSSL_ia32cap_P[1] << 32,
(unsigned long long)OPENSSL_ia32cap_P[2] | (unsigned long long)OPENSSL_ia32cap_P[3] << 32,
(unsigned long long)OPENSSL_ia32cap_P[4] | (unsigned long long)OPENSSL_ia32cap_P[5] << 32,
(unsigned long long)OPENSSL_ia32cap_P[6] | (unsigned long long)OPENSSL_ia32cap_P[7] << 32,
(unsigned long long)OPENSSL_ia32cap_P[8] | (unsigned long long)OPENSSL_ia32cap_P[9] << 32);
-
if ((env = getenv("OPENSSL_ia32cap")) != NULL)
- BIO_snprintf(ossl_cpu_info_str + strlen(ossl_cpu_info_str),
- sizeof(ossl_cpu_info_str) - strlen(ossl_cpu_info_str),
- " env:%s", env);
+ cpu_info_append(" env:%s", env);
#elif defined(__arm__) || defined(__arm) || defined(__aarch64__)
const char *env;
- BIO_snprintf(ossl_cpu_info_str, sizeof(ossl_cpu_info_str),
- CPUINFO_PREFIX "OPENSSL_armcap=0x%x", OPENSSL_armcap_P);
+ cpu_info_append(CPUINFO_PREFIX "OPENSSL_armcap=0x%x", OPENSSL_armcap_P);
if ((env = getenv("OPENSSL_armcap")) != NULL)
- BIO_snprintf(ossl_cpu_info_str + strlen(ossl_cpu_info_str),
- sizeof(ossl_cpu_info_str) - strlen(ossl_cpu_info_str),
- " env:%s", env);
+ cpu_info_append(" env:%s", env);
#elif defined(__powerpc__) || defined(__POWERPC__) || defined(_ARCH_PPC)
const char *env;
- BIO_snprintf(ossl_cpu_info_str, sizeof(ossl_cpu_info_str),
- CPUINFO_PREFIX "OPENSSL_ppccap=0x%x", OPENSSL_ppccap_P);
+ cpu_info_append(CPUINFO_PREFIX "OPENSSL_ppccap=0x%x", OPENSSL_ppccap_P);
if ((env = getenv("OPENSSL_ppccap")) != NULL)
- BIO_snprintf(ossl_cpu_info_str + strlen(ossl_cpu_info_str),
- sizeof(ossl_cpu_info_str) - strlen(ossl_cpu_info_str),
- " env:%s", env);
+ cpu_info_append(" env:%s", env);
#elif defined(__sparcv9) || defined(__sparcv9__)
const char *env;
- BIO_snprintf(ossl_cpu_info_str, sizeof(ossl_cpu_info_str),
- CPUINFO_PREFIX "OPENSSL_sparcv9cap=0x%x:0x%x",
+ cpu_info_append(CPUINFO_PREFIX "OPENSSL_sparcv9cap=0x%x:0x%x",
OPENSSL_sparcv9cap_P[0], OPENSSL_sparcv9cap_P[1]);
if ((env = getenv("OPENSSL_sparcv9cap")) != NULL)
- BIO_snprintf(ossl_cpu_info_str + strlen(ossl_cpu_info_str),
- sizeof(ossl_cpu_info_str) - strlen(ossl_cpu_info_str),
- " env:%s", env);
+ cpu_info_append(" env:%s", env);
#elif defined(__s390__) || defined(__s390x__)
const char *env;
- BIO_snprintf(ossl_cpu_info_str, sizeof(ossl_cpu_info_str),
- CPUINFO_PREFIX "OPENSSL_s390xcap="
- "stfle:0x%llx:0x%llx:0x%llx:0x%llx:"
- "kimd:0x%llx:0x%llx:"
- "klmd:0x%llx:0x%llx:"
- "km:0x%llx:0x%llx:"
- "kmc:0x%llx:0x%llx:"
- "kmac:0x%llx:0x%llx:"
- "kmctr:0x%llx:0x%llx:"
- "kmo:0x%llx:0x%llx:"
- "kmf:0x%llx:0x%llx:"
- "prno:0x%llx:0x%llx:"
- "kma:0x%llx:0x%llx:"
- "pcc:0x%llx:0x%llx:"
- "kdsa:0x%llx:0x%llx",
+ cpu_info_append(CPUINFO_PREFIX "OPENSSL_s390xcap="
+ "stfle:0x%llx:0x%llx:0x%llx:0x%llx:"
+ "kimd:0x%llx:0x%llx:"
+ "klmd:0x%llx:0x%llx:"
+ "km:0x%llx:0x%llx:"
+ "kmc:0x%llx:0x%llx:"
+ "kmac:0x%llx:0x%llx:"
+ "kmctr:0x%llx:0x%llx:"
+ "kmo:0x%llx:0x%llx:"
+ "kmf:0x%llx:0x%llx:"
+ "prno:0x%llx:0x%llx:"
+ "kma:0x%llx:0x%llx:"
+ "pcc:0x%llx:0x%llx:"
+ "kdsa:0x%llx:0x%llx",
OPENSSL_s390xcap_P.stfle[0], OPENSSL_s390xcap_P.stfle[1],
OPENSSL_s390xcap_P.stfle[2], OPENSSL_s390xcap_P.stfle[3],
OPENSSL_s390xcap_P.kimd[0], OPENSSL_s390xcap_P.kimd[1],
@@ -128,63 +134,54 @@ DEFINE_RUN_ONCE_STATIC(init_info_strings)
OPENSSL_s390xcap_P.pcc[0], OPENSSL_s390xcap_P.pcc[1],
OPENSSL_s390xcap_P.kdsa[0], OPENSSL_s390xcap_P.kdsa[1]);
if ((env = getenv("OPENSSL_s390xcap")) != NULL)
- BIO_snprintf(ossl_cpu_info_str + strlen(ossl_cpu_info_str),
- sizeof(ossl_cpu_info_str) - strlen(ossl_cpu_info_str),
- " env:%s", env);
+ cpu_info_append(" env:%s", env);
#elif defined(__riscv)
const char *env;
size_t i;
- BIO_snprintf(ossl_cpu_info_str, sizeof(ossl_cpu_info_str),
- CPUINFO_PREFIX "OPENSSL_riscvcap=RV"
+ cpu_info_append(CPUINFO_PREFIX "OPENSSL_riscvcap=RV"
#if __riscv_xlen == 32
- "32"
+ "32"
#elif __riscv_xlen == 64
- "64"
+ "64"
#elif __riscv_xlen == 128
- "128"
+ "128"
#endif
#if defined(__riscv_i) && defined(__riscv_m) && defined(__riscv_a) \
&& defined(__riscv_f) && defined(__riscv_d) \
&& defined(__riscv_zicsr) && defined(__riscv_zifencei)
- "G" /* shorthand for IMAFD_Zicsr_Zifencei */
+ "G" /* shorthand for IMAFD_Zicsr_Zifencei */
#else
#ifdef __riscv_i
- "I"
+ "I"
#endif
#ifdef __riscv_m
- "M"
+ "M"
#endif
#ifdef __riscv_a
- "A"
+ "A"
#endif
#ifdef __riscv_f
- "F"
+ "F"
#endif
#ifdef __riscv_d
- "D"
+ "D"
#endif
#endif
#ifdef __riscv_c
- "C"
+ "C"
#endif
);
for (i = 0; i < kRISCVNumCaps; i++) {
if (OPENSSL_riscvcap_P[RISCV_capabilities[i].index]
& (1 << RISCV_capabilities[i].bit_offset))
/* Match, display the name */
- BIO_snprintf(ossl_cpu_info_str + strlen(ossl_cpu_info_str),
- sizeof(ossl_cpu_info_str) - strlen(ossl_cpu_info_str),
- "_%s", RISCV_capabilities[i].name);
+ cpu_info_append("_%s", RISCV_capabilities[i].name);
}
if (RISCV_HAS_V())
- BIO_snprintf(ossl_cpu_info_str + strlen(ossl_cpu_info_str),
- sizeof(ossl_cpu_info_str) - strlen(ossl_cpu_info_str),
- " vlen:%lu", riscv_vlen());
+ cpu_info_append(" vlen:%lu", riscv_vlen());
if ((env = getenv("OPENSSL_riscvcap")) != NULL)
- BIO_snprintf(ossl_cpu_info_str + strlen(ossl_cpu_info_str),
- sizeof(ossl_cpu_info_str) - strlen(ossl_cpu_info_str),
- " env:%s", env);
+ cpu_info_append(" env:%s", env);
#endif
#endif
diff --git a/crypto/int.c b/crypto/int.c
deleted file mode 100644
index f782c2aec6..0000000000
--- a/crypto/int.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2025 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
- */
-
-#include "crypto/cryptlib.h"
-
-size_t ossl_num_bits(size_t value)
-{
- size_t i;
- unsigned long ret = 0;
-
- /*
- * It is argued that *on average* constant counter loop performs
- * not worse [if not better] than one with conditional break or
- * mask-n-table-lookup-style, because of branch misprediction
- * penalties.
- */
- for (i = 0; i < sizeof(value) * 8; i++) {
- ret += (value != 0);
- value >>= 1;
- }
-
- return (int)ret;
-}
diff --git a/crypto/lms/lms_pubkey_decode.c b/crypto/lms/lms_pubkey_decode.c
index 8c2ee0ff5e..29ca1d44af 100644
--- a/crypto/lms/lms_pubkey_decode.c
+++ b/crypto/lms/lms_pubkey_decode.c
@@ -95,7 +95,7 @@ int ossl_lms_pubkey_decode(const unsigned char *pub, size_t publen,
{
LMS_PUB_KEY *pkey = &lmskey->pub;
- if (pkey->encoded != NULL && pkey->encodedlen != publen) {
+ if (pkey->encoded != NULL) {
OPENSSL_free(pkey->encoded);
pkey->encodedlen = 0;
}
@@ -110,6 +110,7 @@ int ossl_lms_pubkey_decode(const unsigned char *pub, size_t publen,
err:
OPENSSL_free(pkey->encoded);
pkey->encoded = NULL;
+ pkey->encodedlen = 0;
return 0;
}
diff --git a/crypto/md5/md5_riscv.c b/crypto/md5/md5_riscv.c
index 64dd1a5a26..3bd87a13c4 100644
--- a/crypto/md5/md5_riscv.c
+++ b/crypto/md5/md5_riscv.c
@@ -11,10 +11,10 @@
#include
#include "arch/riscv_arch.h"
-void ossl_md5_block_asm_data_order(MD5_CTX *c, const void *p, size_t num);
-void ossl_md5_block_asm_data_order_zbb(MD5_CTX *c, const void *p, size_t num);
-void ossl_md5_block_asm_data_order_riscv64(MD5_CTX *c, const void *p, size_t num);
-void ossl_md5_block_asm_data_order(MD5_CTX *c, const void *p, size_t num)
+void ossl_md5_block_asm_data_order(void *c, const void *p, size_t num);
+void ossl_md5_block_asm_data_order_zbb(void *c, const void *p, size_t num);
+void ossl_md5_block_asm_data_order_riscv64(void *c, const void *p, size_t num);
+void ossl_md5_block_asm_data_order(void *c, const void *p, size_t num)
{
if (RISCV_HAS_ZBB()) {
ossl_md5_block_asm_data_order_zbb(c, p, num);
diff --git a/crypto/mem_sec.c b/crypto/mem_sec.c
index 3c5de4de8f..a727d2008d 100644
--- a/crypto/mem_sec.c
+++ b/crypto/mem_sec.c
@@ -23,7 +23,6 @@
#ifndef OPENSSL_NO_SECURE_MEMORY
#if defined(_WIN32)
-#include
#if defined(WINAPI_FAMILY_PARTITION)
#if !defined(WINAPI_PARTITION_SYSTEM)
#define WINAPI_PARTITION_SYSTEM 0
diff --git a/crypto/ml_dsa/ml_dsa_key.c b/crypto/ml_dsa/ml_dsa_key.c
index 6b5b8b092f..ea5f4ee4da 100644
--- a/crypto/ml_dsa/ml_dsa_key.c
+++ b/crypto/ml_dsa/ml_dsa_key.c
@@ -332,7 +332,7 @@ int ossl_ml_dsa_key_has(const ML_DSA_KEY *key, int selection)
* @returns 1 on success, or 0 on failure.
*/
static int public_from_private(const ML_DSA_KEY *key, EVP_MD_CTX *md_ctx,
- VECTOR *t1, VECTOR *t0)
+ const OSSL_ML_DSA_SAMPLE_OPS *sample_ops, VECTOR *t1, VECTOR *t0)
{
int ret = 0;
const ML_DSA_PARAMS *params = key->params;
@@ -351,7 +351,7 @@ static int public_from_private(const ML_DSA_KEY *key, EVP_MD_CTX *md_ctx,
matrix_init(&a_ntt, s1_ntt.poly + l, k, l);
/* Using rho generate A' = A in NTT form */
- if (!matrix_expand_A(md_ctx, key->shake128_md, key->rho, &a_ntt))
+ if (!sample_ops->matrix_expand_A(md_ctx, key->shake128_md, key->rho, &a_ntt))
goto err;
/* t = NTT_inv(A' * NTT(s1)) + s2 */
@@ -376,6 +376,7 @@ err:
int ossl_ml_dsa_key_public_from_private(ML_DSA_KEY *key)
{
int ret = 0;
+ const OSSL_ML_DSA_SAMPLE_OPS *sample_ops = ossl_ml_dsa_sample_ops();
VECTOR t0;
EVP_MD_CTX *md_ctx = NULL;
@@ -383,7 +384,7 @@ int ossl_ml_dsa_key_public_from_private(ML_DSA_KEY *key)
return 0;
ret = ((md_ctx = EVP_MD_CTX_new()) != NULL)
&& ossl_ml_dsa_key_pub_alloc(key) /* allocate space for t1 */
- && public_from_private(key, md_ctx, &key->t1, &t0)
+ && public_from_private(key, md_ctx, sample_ops, &key->t1, &t0)
&& vector_equal(&t0, &key->t0) /* compare the generated t0 to the expected */
&& ossl_ml_dsa_pk_encode(key)
&& shake_xof(md_ctx, key->shake256_md,
@@ -397,6 +398,7 @@ int ossl_ml_dsa_key_public_from_private(ML_DSA_KEY *key)
int ossl_ml_dsa_key_pairwise_check(const ML_DSA_KEY *key)
{
int ret = 0;
+ const OSSL_ML_DSA_SAMPLE_OPS *sample_ops = ossl_ml_dsa_sample_ops();
VECTOR t1, t0;
POLY *polys = NULL;
uint32_t k = (uint32_t)key->params->k;
@@ -414,7 +416,7 @@ int ossl_ml_dsa_key_pairwise_check(const ML_DSA_KEY *key)
vector_init(&t1, polys, k);
vector_init(&t0, polys + k, k);
- if (!public_from_private(key, md_ctx, &t1, &t0))
+ if (!public_from_private(key, md_ctx, sample_ops, &t1, &t0))
goto err;
ret = vector_equal(&t1, &key->t1) && vector_equal(&t0, &key->t0);
@@ -435,6 +437,7 @@ err:
static int keygen_internal(ML_DSA_KEY *out)
{
int ret = 0;
+ const OSSL_ML_DSA_SAMPLE_OPS *sample_ops = ossl_ml_dsa_sample_ops();
uint8_t augmented_seed[ML_DSA_SEED_BYTES + 2];
uint8_t expanded_seed[ML_DSA_RHO_BYTES + ML_DSA_PRIV_SEED_BYTES + ML_DSA_K_BYTES];
const uint8_t *const rho = expanded_seed; /* p = Public Random Seed */
@@ -461,8 +464,9 @@ static int keygen_internal(ML_DSA_KEY *out)
memcpy(out->rho, rho, sizeof(out->rho));
memcpy(out->K, K, sizeof(out->K));
- ret = vector_expand_S(md_ctx, out->shake256_md, params->eta, priv_seed, &out->s1, &out->s2)
- && public_from_private(out, md_ctx, &out->t1, &out->t0)
+ ret = sample_ops->vector_expand_S(md_ctx, out->shake256_md, params->eta,
+ priv_seed, &out->s1, &out->s2)
+ && public_from_private(out, md_ctx, sample_ops, &out->t1, &out->t0)
&& ossl_ml_dsa_pk_encode(out)
&& shake_xof(md_ctx, out->shake256_md, out->pub_encoding, out->params->pk_len,
out->tr, sizeof(out->tr))
diff --git a/crypto/ml_dsa/ml_dsa_local.h b/crypto/ml_dsa/ml_dsa_local.h
index 9d01856ce3..23e2db247c 100644
--- a/crypto/ml_dsa/ml_dsa_local.h
+++ b/crypto/ml_dsa/ml_dsa_local.h
@@ -59,10 +59,21 @@ typedef struct vector_st VECTOR;
typedef struct matrix_st MATRIX;
typedef struct ml_dsa_sig_st ML_DSA_SIG;
-int ossl_ml_dsa_matrix_expand_A(EVP_MD_CTX *g_ctx, const EVP_MD *md,
+typedef int(ML_DSA_MATRIX_EXPAND_A_FN)(EVP_MD_CTX *g_ctx, const EVP_MD *md,
const uint8_t *rho, MATRIX *out);
-int ossl_ml_dsa_vector_expand_S(EVP_MD_CTX *h_ctx, const EVP_MD *md, int eta,
- const uint8_t *seed, VECTOR *s1, VECTOR *s2);
+typedef int(ML_DSA_VECTOR_EXPAND_S_FN)(EVP_MD_CTX *h_ctx, const EVP_MD *md,
+ int eta, const uint8_t *seed, VECTOR *s1, VECTOR *s2);
+typedef void(ML_DSA_VECTOR_EXPAND_MASK_FN)(VECTOR *out,
+ const uint8_t rho_prime[ML_DSA_RHO_PRIME_BYTES], uint32_t kappa, uint32_t gamma1,
+ EVP_MD_CTX *h_ctx, const EVP_MD *md);
+
+typedef struct ossl_ml_dsa_sample_ops_st {
+ ML_DSA_MATRIX_EXPAND_A_FN *matrix_expand_A;
+ ML_DSA_VECTOR_EXPAND_S_FN *vector_expand_S;
+ ML_DSA_VECTOR_EXPAND_MASK_FN *vector_expand_mask;
+} OSSL_ML_DSA_SAMPLE_OPS;
+
+const OSSL_ML_DSA_SAMPLE_OPS *ossl_ml_dsa_sample_ops(void);
void ossl_ml_dsa_matrix_mult_vector(const MATRIX *matrix_kl, const VECTOR *vl,
VECTOR *vk);
int ossl_ml_dsa_poly_expand_mask(POLY *out, const uint8_t *seed, size_t seed_len,
diff --git a/crypto/ml_dsa/ml_dsa_matrix.h b/crypto/ml_dsa/ml_dsa_matrix.h
index 3bc053720b..e5f4ebf6d9 100644
--- a/crypto/ml_dsa/ml_dsa_matrix.h
+++ b/crypto/ml_dsa/ml_dsa_matrix.h
@@ -41,11 +41,4 @@ matrix_mult_vector(const MATRIX *a, const VECTOR *s, VECTOR *t)
ossl_ml_dsa_matrix_mult_vector(a, s, t);
}
-static ossl_inline ossl_unused int
-matrix_expand_A(EVP_MD_CTX *g_ctx, const EVP_MD *md, const uint8_t *rho,
- MATRIX *out)
-{
- return ossl_ml_dsa_matrix_expand_A(g_ctx, md, rho, out);
-}
-
#endif /* !defined(OSSL_LIBCRYPTO_ML_DSA_ML_DSA_MATRIX_H) */
diff --git a/crypto/ml_dsa/ml_dsa_ntt_vec128.c b/crypto/ml_dsa/ml_dsa_ntt_vec128.c
index 8176cbcdfb..54d59a9a08 100644
--- a/crypto/ml_dsa/ml_dsa_ntt_vec128.c
+++ b/crypto/ml_dsa/ml_dsa_ntt_vec128.c
@@ -309,15 +309,47 @@ static const int32_t neg_zetas_montgomery_twisted[256] = {
static const vec_int32_t vec_q = { ML_DSA_Q, ML_DSA_Q, ML_DSA_Q, ML_DSA_Q };
static const vec_int32_t vec_q_inv = { ML_DSA_Q_INV, ML_DSA_Q_INV, ML_DSA_Q_INV, ML_DSA_Q_INV };
+/*
+ * @brief Reduce a in (-q, q) to a mod q in [0, q).
+ *
+ * @param a in (-q, q)
+ * @returns a mod q in [0, q)
+ */
+static ossl_inline
+ vec_int32_t
+ reduce_once_signed(vec_int32_t a)
+{
+ /* mask is 11..11 when a is negative, else 0 */
+ vec_uint32_t mask = -(((vec_uint32_t)a) >> 31);
+ return a + (vec_int32_t)(mask & (vec_uint32_t)vec_q);
+}
+
+/*
+ * @brief Reduce a in (-2q, q) to a mod q in [0, q).
+ *
+ * @param a in (-2q, q)
+ * @returns a mod q in [0, q)
+ */
+static ossl_inline
+ vec_int32_t
+ reduce_twice_signed(vec_int32_t a)
+{
+ /* mask is 11..11 when a is negative, else 0 */
+ vec_uint32_t mask = -(((vec_uint32_t)a) >> 31);
+ /* b is in (-q, q) */
+ vec_int32_t b = a + (vec_int32_t)(mask & (vec_uint32_t)vec_q);
+ return reduce_once_signed(b);
+}
+
/*
* @brief Computes the Montgomery product of a and b.
* See [Seiler 2018, Algorithm 3].
*
- * @param a is the first factor, assumed to be non-negative.
+ * @param a is the first factor, assumed to be in [0, q).
* @param a_twist is (int32)((uint32)a * ML_DSA_Q_INV).
* @param b is the second factor.
* @returns The Montgomery product of a and b in the range
- * -q+1..q-1.
+ * [0, q).
*/
static ossl_inline
@@ -329,22 +361,7 @@ static ossl_inline
vec_int32_t c = (vec_int32_t)c_u;
vec_int32_t z_high = vec_mulh((vec_int32_alias_t)a, (vec_int32_alias_t)b);
vec_int32_t r = z_high - c;
- return r;
-}
-
-/*
- * @brief Reduce a in (-q, q) to a mod q in [0, q-1].
- *
- * @param a in (-q, q)
- * @returns a mod q in [0, q-1]
- */
-static ossl_inline
- vec_int32_t
- reduce_once_signed(vec_int32_t a)
-{
- /* mask is 11..11 when a is negative, else 0 */
- vec_uint32_t mask = -(((vec_uint32_t)a) >> 31);
- return a + (vec_int32_t)(mask & (vec_uint32_t)vec_q);
+ return reduce_twice_signed(r);
}
/*
@@ -376,9 +393,8 @@ void ossl_poly_ntt_mult_scalar_vec128(const POLY *lhs, const POLY *rhs, POLY *ou
for (i = 0; i < ML_DSA_NUM_POLY_COEFFICIENTS / NUM_INT32_IN_VECTOR; i++) {
vec_int32_t twist_vec = (vec_int32_t)((vec_uint32_t)lhs_vec_ptr[i] * (vec_uint32_t)vec_q_inv);
- vec_int32_t result = montgomery_multiplication_vectorized(
+ out_vec_ptr[i] = montgomery_multiplication_vectorized(
lhs_vec_ptr[i], twist_vec, rhs_vec_ptr[i]);
- out_vec_ptr[i] = reduce_once_signed(result);
}
}
@@ -682,11 +698,10 @@ void ossl_ml_dsa_poly_ntt_inverse_vec128(POLY *p)
}
for (i = 0; i < ML_DSA_NUM_POLY_COEFFICIENTS / NUM_INT32_IN_VECTOR; i += 1) {
- vec_int32_t coeff_i_vec = montgomery_multiplication_vectorized(
+ p_vec[i] = montgomery_multiplication_vectorized(
vec_inverse_degree_montgomery,
vec_inverse_degree_montgomery_twisted,
p_vec[i]);
- p_vec[i] = reduce_once_signed(coeff_i_vec);
}
}
diff --git a/crypto/ml_dsa/ml_dsa_sample.c b/crypto/ml_dsa/ml_dsa_sample.c
index 5d9dc84a54..afa09b7971 100644
--- a/crypto/ml_dsa/ml_dsa_sample.c
+++ b/crypto/ml_dsa/ml_dsa_sample.c
@@ -8,6 +8,7 @@
*/
#include
+#include
#include "ml_dsa_local.h"
#include "ml_dsa_vector.h"
#include "ml_dsa_matrix.h"
@@ -35,6 +36,10 @@ typedef int(COEFF_FROM_NIBBLE_FUNC)(uint32_t nibble, uint32_t *out);
static COEFF_FROM_NIBBLE_FUNC coeff_from_nibble_4;
static COEFF_FROM_NIBBLE_FUNC coeff_from_nibble_2;
+static ML_DSA_MATRIX_EXPAND_A_FN matrix_expand_A_scalar;
+static ML_DSA_VECTOR_EXPAND_S_FN vector_expand_S_scalar;
+static ML_DSA_VECTOR_EXPAND_MASK_FN vector_expand_mask_scalar;
+
/**
* @brief Combine 3 bytes to form an coefficient.
* See FIPS 204, Algorithm 14, CoeffFromThreeBytes()
@@ -160,13 +165,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++) {
@@ -174,15 +180,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;
}
/**
@@ -198,7 +211,7 @@ static int rej_bounded_poly(EVP_MD_CTX *h_ctx, const EVP_MD *md,
* in the range of 0..q-1.
* @returns 1 if the matrix was generated, or 0 on error.
*/
-int ossl_ml_dsa_matrix_expand_A(EVP_MD_CTX *g_ctx, const EVP_MD *md,
+static int matrix_expand_A_scalar(EVP_MD_CTX *g_ctx, const EVP_MD *md,
const uint8_t *rho, MATRIX *out)
{
int ret = 0;
@@ -208,7 +221,6 @@ int ossl_ml_dsa_matrix_expand_A(EVP_MD_CTX *g_ctx, const EVP_MD *md,
/* The seed used for each matrix element is rho + column_index + row_index */
memcpy(derived_seed, rho, ML_DSA_RHO_BYTES);
-
for (i = 0; i < out->k; i++) {
for (j = 0; j < out->l; j++) {
derived_seed[ML_DSA_RHO_BYTES + 1] = (uint8_t)i;
@@ -241,7 +253,7 @@ err:
* the range (q-eta)..0..eta
* @returns 1 if s1 and s2 were successfully generated, or 0 otherwise.
*/
-int ossl_ml_dsa_vector_expand_S(EVP_MD_CTX *h_ctx, const EVP_MD *md, int eta,
+static int vector_expand_S_scalar(EVP_MD_CTX *h_ctx, const EVP_MD *md, int eta,
const uint8_t *seed, VECTOR *s1, VECTOR *s2)
{
int ret = 0;
@@ -275,6 +287,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;
}
@@ -285,9 +298,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;
}
/*
@@ -376,3 +391,46 @@ int ossl_ml_dsa_poly_sample_in_ball(POLY *out_c, const uint8_t *seed, int seed_l
}
return 1;
}
+
+static void vector_expand_mask_scalar(VECTOR *out,
+ const uint8_t rho_prime[ML_DSA_RHO_PRIME_BYTES], uint32_t kappa, uint32_t gamma1,
+ EVP_MD_CTX *h_ctx, const EVP_MD *md)
+{
+ size_t i;
+ uint8_t derived_seed[ML_DSA_RHO_PRIME_BYTES + 2];
+
+ memcpy(derived_seed, rho_prime, ML_DSA_RHO_PRIME_BYTES);
+
+ for (i = 0; i < out->num_poly; i++) {
+ size_t index = kappa + i;
+
+ derived_seed[ML_DSA_RHO_PRIME_BYTES] = index & 0xFF;
+ derived_seed[ML_DSA_RHO_PRIME_BYTES + 1] = (index >> 8) & 0xFF;
+ poly_expand_mask(out->poly + i, derived_seed, sizeof(derived_seed),
+ gamma1, h_ctx, md);
+ }
+ OPENSSL_cleanse(derived_seed, sizeof(derived_seed));
+}
+
+static const OSSL_ML_DSA_SAMPLE_OPS ml_dsa_sample_generic_meth = {
+ matrix_expand_A_scalar,
+ vector_expand_S_scalar,
+ vector_expand_mask_scalar
+};
+
+#if defined(KECCAK1600_ASM) \
+ && (defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)) \
+ && !defined(OPENSSL_NO_ASM)
+#include "ml_dsa_sample_hw_x86_64.inc"
+const OSSL_ML_DSA_SAMPLE_OPS *ossl_ml_dsa_sample_ops(void)
+{
+ if (SHA3_avx512vl_capable())
+ return &ml_dsa_sample_x86_64;
+ return &ml_dsa_sample_generic_meth;
+}
+#else
+const OSSL_ML_DSA_SAMPLE_OPS *ossl_ml_dsa_sample_ops(void)
+{
+ return &ml_dsa_sample_generic_meth;
+}
+#endif
diff --git a/crypto/ml_dsa/ml_dsa_sample_hw_x86_64.inc b/crypto/ml_dsa/ml_dsa_sample_hw_x86_64.inc
new file mode 100644
index 0000000000..fcf5f03323
--- /dev/null
+++ b/crypto/ml_dsa/ml_dsa_sample_hw_x86_64.inc
@@ -0,0 +1,307 @@
+/*
+ * Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright (c) 2026 Intel Corporation. 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
+ */
+
+#define ML_DSA_SHAKE_X4_BATCH_SIZE 4
+#define ML_DSA_SHAKE_X4_DONE_MASK ((1 << ML_DSA_SHAKE_X4_BATCH_SIZE) - 1)
+#define ML_DSA_EXPAND_MASK_BYTES_PER_COEFF 32
+#define ML_DSA_EXPAND_MASK_COEFFS_GAMMA1_19 20
+#define ML_DSA_EXPAND_MASK_COEFFS_GAMMA1_17 18
+#define ML_DSA_EXPAND_MASK_BUF_SIZE_GAMMA1_19 \
+ (ML_DSA_EXPAND_MASK_BYTES_PER_COEFF * ML_DSA_EXPAND_MASK_COEFFS_GAMMA1_19)
+#define ML_DSA_EXPAND_MASK_BUF_SIZE_GAMMA1_17 \
+ (ML_DSA_EXPAND_MASK_BYTES_PER_COEFF * ML_DSA_EXPAND_MASK_COEFFS_GAMMA1_17)
+#define ML_DSA_EXPAND_MASK_BUF_SIZE(gamma1) \
+ ((gamma1) == ML_DSA_GAMMA1_TWO_POWER_19 \
+ ? ML_DSA_EXPAND_MASK_BUF_SIZE_GAMMA1_19 \
+ : ML_DSA_EXPAND_MASK_BUF_SIZE_GAMMA1_17)
+
+static ossl_unused int rej_ntt_poly_mb(const uint8_t *seeds[ML_DSA_SHAKE_X4_BATCH_SIZE],
+ const size_t seed_len, POLY *outs[ML_DSA_SHAKE_X4_BATCH_SIZE], const size_t count)
+{
+ KECCAK1600_X4_AVX512VL_CTX ctx;
+ uint8_t blocks[ML_DSA_SHAKE_X4_BATCH_SIZE][SHAKE128_BLOCKSIZE];
+ int coeff_idx[ML_DSA_SHAKE_X4_BATCH_SIZE] = { 0, 0, 0, 0 };
+ size_t done_mask = 0;
+ size_t lane;
+
+ for (lane = count; lane < ML_DSA_SHAKE_X4_BATCH_SIZE; lane++)
+ done_mask |= ((size_t)1 << lane);
+
+ ossl_sha3_shake128_x4_inc_init_avx512vl(&ctx);
+ ossl_sha3_shake128_x4_inc_absorb_avx512vl(&ctx, seeds[0], seeds[1],
+ seeds[2], seeds[3], seed_len);
+
+ while (done_mask != ML_DSA_SHAKE_X4_DONE_MASK) {
+ ossl_sha3_shake128_x4_inc_squeeze_avx512vl(blocks[0], blocks[1],
+ blocks[2], blocks[3], SHAKE128_BLOCKSIZE, &ctx);
+
+ for (lane = 0; lane < ML_DSA_SHAKE_X4_BATCH_SIZE; lane++) {
+ if (done_mask & ((size_t)1 << lane))
+ continue;
+
+ const uint8_t *b = blocks[lane];
+ const uint8_t *end = b + SHAKE128_BLOCKSIZE;
+
+ for (; b < end && coeff_idx[lane] < ML_DSA_NUM_POLY_COEFFICIENTS; b += 3) {
+ uint32_t *coeff_ptr = &(outs[lane]->coeff[coeff_idx[lane]]);
+
+ if (coeff_from_three_bytes(b, coeff_ptr))
+ coeff_idx[lane]++;
+ }
+
+ if (coeff_idx[lane] >= ML_DSA_NUM_POLY_COEFFICIENTS)
+ done_mask |= ((size_t)1 << lane);
+ }
+ }
+
+ return 1;
+}
+
+static void vector_expand_mask_mb(VECTOR *out,
+ const uint8_t rho_prime[ML_DSA_RHO_PRIME_BYTES], const uint32_t kappa, const uint32_t gamma1,
+ EVP_MD_CTX *h_ctx, const EVP_MD *md)
+{
+ size_t i;
+ const size_t num_polys = out->num_poly;
+ uint8_t derived_seeds[ML_DSA_SHAKE_X4_BATCH_SIZE][ML_DSA_RHO_PRIME_BYTES + 2];
+ const size_t seed_len = sizeof(derived_seeds[0]);
+ const size_t buf_size = ML_DSA_EXPAND_MASK_BUF_SIZE(gamma1);
+ uint8_t buffers[ML_DSA_SHAKE_X4_BATCH_SIZE][ML_DSA_EXPAND_MASK_BUF_SIZE_GAMMA1_19];
+
+ (void)h_ctx;
+ (void)md;
+
+ for (i = 0; i < ML_DSA_SHAKE_X4_BATCH_SIZE; i++)
+ memcpy(derived_seeds[i], rho_prime, ML_DSA_RHO_PRIME_BYTES);
+
+ for (i = 0; i + (ML_DSA_SHAKE_X4_BATCH_SIZE - 1) < num_polys; i += ML_DSA_SHAKE_X4_BATCH_SIZE) {
+ size_t b;
+
+ for (b = 0; b < ML_DSA_SHAKE_X4_BATCH_SIZE; b++) {
+ const size_t index = kappa + i + b;
+
+ derived_seeds[b][ML_DSA_RHO_PRIME_BYTES] = index & 0xFF;
+ derived_seeds[b][ML_DSA_RHO_PRIME_BYTES + 1] = (index >> 8) & 0xFF;
+ }
+
+ ossl_sha3_shake256_x4_avx512vl(buffers[0], buffers[1], buffers[2], buffers[3], buf_size,
+ derived_seeds[0], derived_seeds[1], derived_seeds[2], derived_seeds[3], seed_len);
+
+ ossl_ml_dsa_poly_decode_expand_mask(&out->poly[i + 0], buffers[0], buf_size, gamma1);
+ ossl_ml_dsa_poly_decode_expand_mask(&out->poly[i + 1], buffers[1], buf_size, gamma1);
+ ossl_ml_dsa_poly_decode_expand_mask(&out->poly[i + 2], buffers[2], buf_size, gamma1);
+ ossl_ml_dsa_poly_decode_expand_mask(&out->poly[i + 3], buffers[3], buf_size, gamma1);
+ }
+
+ /*
+ * num_polys is always 4 (ML-DSA-44), 5 (ML-DSA-65), or 7 (ML-DSA-87), so the
+ * above loops will always runs at least once, initializing derived_seeds.
+ * As a result, 'left' below will be 0, 1, or 3, meaning the 4 way shake will
+ * recalculate values that are not used.
+ */
+ if (i < num_polys) {
+ const size_t left = num_polys - i;
+ size_t b;
+
+ for (b = 0; b < left; b++) {
+ const size_t index = kappa + i + b;
+
+ derived_seeds[b][ML_DSA_RHO_PRIME_BYTES] = (uint8_t)index;
+ derived_seeds[b][ML_DSA_RHO_PRIME_BYTES + 1] = (uint8_t)(index >> 8);
+ }
+
+ ossl_sha3_shake256_x4_avx512vl(buffers[0], buffers[1], buffers[2], buffers[3], buf_size,
+ derived_seeds[0], derived_seeds[1], derived_seeds[2], derived_seeds[3], seed_len);
+
+ ossl_ml_dsa_poly_decode_expand_mask(&out->poly[i + 0], buffers[0], buf_size, gamma1);
+
+ if ((i + 1) < num_polys)
+ ossl_ml_dsa_poly_decode_expand_mask(&out->poly[i + 1], buffers[1], buf_size, gamma1);
+
+ if ((i + 2) < num_polys)
+ ossl_ml_dsa_poly_decode_expand_mask(&out->poly[i + 2], buffers[2], buf_size, gamma1);
+ }
+
+ OPENSSL_cleanse(buffers, sizeof(buffers));
+ OPENSSL_cleanse(derived_seeds, sizeof(derived_seeds));
+}
+
+static ossl_unused int rej_bounded_poly_mb(COEFF_FROM_NIBBLE_FUNC *coef_from_nibble,
+ const uint8_t *seeds[ML_DSA_SHAKE_X4_BATCH_SIZE], const size_t seed_len,
+ POLY *outs[ML_DSA_SHAKE_X4_BATCH_SIZE], const size_t count)
+{
+ KECCAK1600_X4_AVX512VL_CTX ctx;
+ uint8_t blocks[ML_DSA_SHAKE_X4_BATCH_SIZE][SHAKE256_BLOCKSIZE];
+ int coeff_idx[ML_DSA_SHAKE_X4_BATCH_SIZE] = { 0, 0, 0, 0 };
+ size_t done_mask = 0;
+ size_t lane;
+
+ for (lane = count; lane < ML_DSA_SHAKE_X4_BATCH_SIZE; lane++)
+ done_mask |= ((size_t)1 << lane);
+
+ ossl_sha3_shake256_x4_inc_init_avx512vl(&ctx);
+ ossl_sha3_shake256_x4_inc_absorb_avx512vl(&ctx, seeds[0], seeds[1],
+ seeds[2], seeds[3], seed_len);
+
+ while (done_mask != ML_DSA_SHAKE_X4_DONE_MASK) {
+ ossl_sha3_shake256_x4_inc_squeeze_avx512vl(blocks[0], blocks[1],
+ blocks[2], blocks[3], SHAKE256_BLOCKSIZE, &ctx);
+
+ for (lane = 0; lane < ML_DSA_SHAKE_X4_BATCH_SIZE; lane++) {
+ if (done_mask & ((size_t)1 << lane))
+ continue;
+
+ const uint8_t *b = blocks[lane];
+ const uint8_t *end = b + SHAKE256_BLOCKSIZE;
+
+ for (; b < end && coeff_idx[lane] < ML_DSA_NUM_POLY_COEFFICIENTS; b++) {
+ uint32_t z0 = *b & 0x0F;
+ uint32_t z1 = *b >> 4;
+
+ if (coef_from_nibble(z0, &outs[lane]->coeff[coeff_idx[lane]]))
+ coeff_idx[lane]++;
+
+ if (coeff_idx[lane] >= ML_DSA_NUM_POLY_COEFFICIENTS) {
+ done_mask |= ((size_t)1 << lane);
+ break;
+ }
+
+ if (coef_from_nibble(z1, &outs[lane]->coeff[coeff_idx[lane]]))
+ coeff_idx[lane]++;
+
+ if (coeff_idx[lane] >= ML_DSA_NUM_POLY_COEFFICIENTS) {
+ done_mask |= ((size_t)1 << lane);
+ break;
+ }
+ }
+ }
+ }
+
+ OPENSSL_cleanse(blocks, sizeof(blocks));
+ ossl_sha3_shake256_x4_inc_cleanup_avx512vl(&ctx);
+ return 1;
+}
+
+static int matrix_expand_A_mb(EVP_MD_CTX *g_ctx, const EVP_MD *md,
+ const uint8_t *rho, MATRIX *out)
+{
+ size_t b, idx;
+ uint8_t derived_seeds[ML_DSA_SHAKE_X4_BATCH_SIZE][ML_DSA_RHO_BYTES + 2];
+ const size_t seed_len = sizeof(derived_seeds[0]);
+ const uint8_t *seeds[ML_DSA_SHAKE_X4_BATCH_SIZE];
+ POLY *polys[ML_DSA_SHAKE_X4_BATCH_SIZE];
+ POLY *poly = out->m_poly;
+
+ for (b = 0; b < ML_DSA_SHAKE_X4_BATCH_SIZE; b++) {
+ memcpy(derived_seeds[b], rho, ML_DSA_RHO_BYTES);
+ seeds[b] = derived_seeds[b];
+ }
+
+ for (idx = 0; (idx + ML_DSA_SHAKE_X4_BATCH_SIZE - 1) < (out->k * out->l);
+ idx += ML_DSA_SHAKE_X4_BATCH_SIZE) {
+ for (b = 0; b < ML_DSA_SHAKE_X4_BATCH_SIZE; b++) {
+ const size_t row = (idx + b) / out->l;
+ const size_t col = (idx + b) % out->l;
+
+ derived_seeds[b][ML_DSA_RHO_BYTES] = (uint8_t)col;
+ derived_seeds[b][ML_DSA_RHO_BYTES + 1] = (uint8_t)row;
+ polys[b] = &poly[idx + b];
+ }
+
+ if (!rej_ntt_poly_mb(seeds, seed_len, polys, 4))
+ return 0;
+ }
+
+ if (idx < (out->k * out->l)) {
+ const size_t left = (out->k * out->l) - idx;
+
+ for (b = 0; b < left; b++) {
+ const size_t row = (idx + b) / out->l;
+ const size_t col = (idx + b) % out->l;
+
+ derived_seeds[b][ML_DSA_RHO_BYTES] = (uint8_t)col;
+ derived_seeds[b][ML_DSA_RHO_BYTES + 1] = (uint8_t)row;
+ polys[b] = &poly[idx + b];
+ }
+
+ if (!rej_ntt_poly_mb(seeds, seed_len, polys, left))
+ return 0;
+ }
+
+ return 1;
+}
+
+static int vector_expand_S_mb(EVP_MD_CTX *h_ctx, const EVP_MD *md, const int eta,
+ const uint8_t *seed, VECTOR *s1, VECTOR *s2)
+{
+ int ret = 0;
+ size_t b, idx;
+ const size_t l = s1->num_poly;
+ const size_t total = l + s2->num_poly;
+ uint8_t derived_seeds[ML_DSA_SHAKE_X4_BATCH_SIZE][ML_DSA_PRIV_SEED_BYTES + 2];
+ const uint8_t *seeds[ML_DSA_SHAKE_X4_BATCH_SIZE];
+ const size_t seed_len = sizeof(derived_seeds[0]);
+ POLY *polys[ML_DSA_SHAKE_X4_BATCH_SIZE];
+ COEFF_FROM_NIBBLE_FUNC *coef_from_nibble_fn = (eta == ML_DSA_ETA_4) ? coeff_from_nibble_4 : coeff_from_nibble_2;
+
+ for (b = 0; b < ML_DSA_SHAKE_X4_BATCH_SIZE; b++) {
+ memcpy(derived_seeds[b], seed, ML_DSA_PRIV_SEED_BYTES);
+ seeds[b] = derived_seeds[b];
+ }
+
+ for (idx = 0; (idx + ML_DSA_SHAKE_X4_BATCH_SIZE - 1) < total; idx += ML_DSA_SHAKE_X4_BATCH_SIZE) {
+ for (b = 0; b < ML_DSA_SHAKE_X4_BATCH_SIZE; b++) {
+ const size_t poly_idx = idx + b;
+
+ derived_seeds[b][ML_DSA_PRIV_SEED_BYTES] = (uint8_t)(poly_idx);
+ derived_seeds[b][ML_DSA_PRIV_SEED_BYTES + 1] = (uint8_t)(poly_idx >> 8);
+
+ if (poly_idx < l)
+ polys[b] = &s1->poly[poly_idx];
+ else
+ polys[b] = &s2->poly[poly_idx - l];
+ }
+
+ if (!rej_bounded_poly_mb(coef_from_nibble_fn,
+ seeds, seed_len, polys, ML_DSA_SHAKE_X4_BATCH_SIZE))
+ goto err;
+ }
+
+ if (idx < total) {
+ const size_t batch_count = total - idx;
+
+ for (b = 0; b < batch_count; b++) {
+ const size_t poly_idx = idx + b;
+
+ derived_seeds[b][ML_DSA_PRIV_SEED_BYTES] = (uint8_t)(poly_idx);
+ derived_seeds[b][ML_DSA_PRIV_SEED_BYTES + 1] = (uint8_t)(poly_idx >> 8);
+
+ if (poly_idx < l)
+ polys[b] = &s1->poly[poly_idx];
+ else
+ polys[b] = &s2->poly[poly_idx - l];
+ }
+
+ if (!rej_bounded_poly_mb(coef_from_nibble_fn,
+ seeds, seed_len, polys, batch_count))
+ goto err;
+ }
+
+ ret = 1;
+err:
+ OPENSSL_cleanse(derived_seeds, sizeof(derived_seeds));
+ return ret;
+}
+
+static const OSSL_ML_DSA_SAMPLE_OPS ml_dsa_sample_x86_64 = {
+ matrix_expand_A_mb,
+ vector_expand_S_mb,
+ vector_expand_mask_mb
+};
diff --git a/crypto/ml_dsa/ml_dsa_sign.c b/crypto/ml_dsa/ml_dsa_sign.c
index 05251a6dd0..62dfd08d53 100644
--- a/crypto/ml_dsa/ml_dsa_sign.c
+++ b/crypto/ml_dsa/ml_dsa_sign.c
@@ -164,6 +164,7 @@ static int ml_dsa_sign_internal(const ML_DSA_KEY *priv,
uint8_t *out_sig)
{
int ret = 0;
+ const OSSL_ML_DSA_SAMPLE_OPS *sample_ops = ossl_ml_dsa_sample_ops();
const ML_DSA_PARAMS *params = priv->params;
EVP_MD_CTX *md_ctx = NULL;
uint32_t k = (uint32_t)params->k, l = (uint32_t)params->l;
@@ -236,7 +237,7 @@ static int ml_dsa_sign_internal(const ML_DSA_KEY *priv,
CONSTTIME_SECRET_VECTOR(priv->s2);
CONSTTIME_SECRET_VECTOR(priv->t0);
- if (!matrix_expand_A(md_ctx, priv->shake128_md, priv->rho, &a_ntt))
+ if (!sample_ops->matrix_expand_A(md_ctx, priv->shake128_md, priv->rho, &a_ntt))
goto err;
/*
@@ -267,8 +268,8 @@ static int ml_dsa_sign_internal(const ML_DSA_KEY *priv,
VECTOR *ct0 = &w1;
uint32_t z_max, r0_max, ct0_max, h_ones;
- vector_expand_mask(&y, rho_prime, sizeof(rho_prime), (uint32_t)kappa,
- gamma1, md_ctx, priv->shake256_md);
+ sample_ops->vector_expand_mask(&y, rho_prime,
+ (uint32_t)kappa, gamma1, md_ctx, priv->shake256_md);
vector_copy(y_ntt, &y);
vector_ntt(y_ntt);
@@ -391,6 +392,7 @@ static int ml_dsa_verify_internal(const ML_DSA_KEY *pub,
const uint8_t *sig_enc, size_t sig_enc_len)
{
int ret = 0;
+ const OSSL_ML_DSA_SAMPLE_OPS *sample_ops = ossl_ml_dsa_sample_ops();
uint8_t *alloc = NULL, *w1_encoded = NULL;
void *alloc_freeptr = NULL;
POLY *p, *c_ntt;
@@ -448,7 +450,7 @@ static int ml_dsa_verify_internal(const ML_DSA_KEY *pub,
vector_init(&ct1_ntt, p + k, k);
if (!ossl_ml_dsa_sig_decode(&sig, sig_enc, sig_enc_len, pub->params)
- || !matrix_expand_A(md_ctx, pub->shake128_md, pub->rho, &a_ntt))
+ || !sample_ops->matrix_expand_A(md_ctx, pub->shake128_md, pub->rho, &a_ntt))
goto err;
/* Compute verifiers challenge c_ntt = NTT(SampleInBall(c_tilde)) */
diff --git a/crypto/ml_dsa/ml_dsa_vector.h b/crypto/ml_dsa/ml_dsa_vector.h
index 6b408acdc2..9b83c0420e 100644
--- a/crypto/ml_dsa/ml_dsa_vector.h
+++ b/crypto/ml_dsa/ml_dsa_vector.h
@@ -152,33 +152,6 @@ vector_mult_scalar(const VECTOR *lhs, const POLY *rhs, VECTOR *out)
ossl_ml_dsa_poly_ntt_mult(lhs->poly + i, rhs, out->poly + i);
}
-static ossl_inline ossl_unused int
-vector_expand_S(EVP_MD_CTX *h_ctx, const EVP_MD *md, int eta,
- const uint8_t *seed, VECTOR *s1, VECTOR *s2)
-{
- return ossl_ml_dsa_vector_expand_S(h_ctx, md, eta, seed, s1, s2);
-}
-
-static ossl_inline ossl_unused void
-vector_expand_mask(VECTOR *out, const uint8_t *rho_prime, size_t rho_prime_len,
- uint32_t kappa, uint32_t gamma1,
- EVP_MD_CTX *h_ctx, const EVP_MD *md)
-{
- size_t i;
- uint8_t derived_seed[ML_DSA_RHO_PRIME_BYTES + 2];
-
- memcpy(derived_seed, rho_prime, ML_DSA_RHO_PRIME_BYTES);
-
- for (i = 0; i < out->num_poly; i++) {
- size_t index = kappa + i;
-
- derived_seed[ML_DSA_RHO_PRIME_BYTES] = index & 0xFF;
- derived_seed[ML_DSA_RHO_PRIME_BYTES + 1] = (index >> 8) & 0xFF;
- poly_expand_mask(out->poly + i, derived_seed, sizeof(derived_seed),
- gamma1, h_ctx, md);
- }
-}
-
/* Scale back previously rounded value */
static ossl_inline ossl_unused void
vector_scale_power2_round_ntt(const VECTOR *in, VECTOR *out)
diff --git a/crypto/ml_kem/ml_kem.c b/crypto/ml_kem/ml_kem.c
index 2fc0e5a980..89960dc105 100644
--- a/crypto/ml_kem/ml_kem.c
+++ b/crypto/ml_kem/ml_kem.c
@@ -1148,7 +1148,7 @@ static __owur int gencbd_vector_ntt(scalar *out, CBD_FUNC cbd, uint8_t *counter,
* |A| (our key->m, with the public key holding an expanded (16-bit per scalar
* coefficient) key->t vector).
*
- * Caller passes storage in |tmp| for for two temporary vectors.
+ * Caller passes storage in |tmp| for two temporary vectors.
*/
static __owur int encrypt_cpa(uint8_t out[ML_KEM_SHARED_SECRET_BYTES],
const uint8_t message[DEGREE / 8],
@@ -2032,11 +2032,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,
diff --git a/crypto/o_dir.c b/crypto/o_dir.c
index 36d33fbed4..ed92b9f130 100644
--- a/crypto/o_dir.c
+++ b/crypto/o_dir.c
@@ -31,8 +31,6 @@
# include "LPdir_vms.c"
#elif defined OPENSSL_SYS_WIN32
# include "LPdir_win32.c"
-#elif defined OPENSSL_SYS_WINCE
-# include "LPdir_wince.c"
#else
# include "LPdir_nyi.c"
#endif
diff --git a/crypto/o_str.c b/crypto/o_str.c
index c2ec1fc261..2192d48775 100644
--- a/crypto/o_str.c
+++ b/crypto/o_str.c
@@ -377,7 +377,7 @@ char *OPENSSL_buf2hexstr(const unsigned char *buf, long buflen)
int openssl_strerror_r(int errnum, char *buf, size_t buflen)
{
-#if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(_WIN32_WCE)
+#if defined(_MSC_VER) && _MSC_VER >= 1400
return !strerror_s(buf, buflen, errnum);
#elif defined(_GNU_SOURCE)
char *err;
diff --git a/crypto/objects/obj_xref.h b/crypto/objects/obj_xref.h
index 955571e134..46de3ccf4a 100644
--- a/crypto/objects/obj_xref.h
+++ b/crypto/objects/obj_xref.h
@@ -81,6 +81,8 @@ static const nid_triple sigoid_srt[] = {
NID_id_GostR3410_2012_512},
{NID_ED25519, NID_undef, NID_ED25519},
{NID_ED448, NID_undef, NID_ED448},
+ {NID_dsa_with_SHA384, NID_sha384, NID_dsa},
+ {NID_dsa_with_SHA512, NID_sha512, NID_dsa},
{NID_ecdsa_with_SHA3_224, NID_sha3_224, NID_X9_62_id_ecPublicKey},
{NID_ecdsa_with_SHA3_256, NID_sha3_256, NID_X9_62_id_ecPublicKey},
{NID_ecdsa_with_SHA3_384, NID_sha3_384, NID_X9_62_id_ecPublicKey},
@@ -129,10 +131,12 @@ static const nid_triple *const sigoid_srt_xref[] = {
&sigoid_srt[32],
&sigoid_srt[37],
&sigoid_srt[14],
+ &sigoid_srt[44],
&sigoid_srt[21],
&sigoid_srt[33],
&sigoid_srt[38],
&sigoid_srt[15],
+ &sigoid_srt[45],
&sigoid_srt[22],
&sigoid_srt[34],
&sigoid_srt[39],
@@ -147,15 +151,15 @@ static const nid_triple *const sigoid_srt_xref[] = {
&sigoid_srt[28],
&sigoid_srt[40],
&sigoid_srt[41],
- &sigoid_srt[48],
- &sigoid_srt[44],
- &sigoid_srt[49],
- &sigoid_srt[45],
&sigoid_srt[50],
&sigoid_srt[46],
&sigoid_srt[51],
&sigoid_srt[47],
&sigoid_srt[52],
+ &sigoid_srt[48],
+ &sigoid_srt[53],
+ &sigoid_srt[49],
+ &sigoid_srt[54],
};
/* clang-format on */
diff --git a/crypto/objects/obj_xref.txt b/crypto/objects/obj_xref.txt
index 71bc12af74..2f82617a84 100644
--- a/crypto/objects/obj_xref.txt
+++ b/crypto/objects/obj_xref.txt
@@ -64,6 +64,8 @@ ecdsa_with_SHA3_512 sha3_512 X9_62_id_ecPublicKey
dsa_with_SHA224 sha224 dsa
dsa_with_SHA256 sha256 dsa
+dsa_with_SHA384 sha384 dsa
+dsa_with_SHA512 sha512 dsa
id_GostR3411_94_with_GostR3410_2001 id_GostR3411_94 id_GostR3410_2001
id_GostR3411_94_with_GostR3410_94 id_GostR3411_94 id_GostR3410_94
diff --git a/crypto/ocsp/ocsp_ext.c b/crypto/ocsp/ocsp_ext.c
index e6467aa0ae..038be72b04 100644
--- a/crypto/ocsp/ocsp_ext.c
+++ b/crypto/ocsp/ocsp_ext.c
@@ -360,7 +360,7 @@ X509_EXTENSION *OCSP_crlID_new(const char *url, long *n, char *tim)
if (url) {
if ((cid->crlUrl = ASN1_IA5STRING_new()) == NULL)
goto err;
- if (!(ASN1_STRING_set(cid->crlUrl, url, -1)))
+ if (!(ASN1_STRING_set_string(cid->crlUrl, url)))
goto err;
}
if (n) {
@@ -446,7 +446,7 @@ X509_EXTENSION *OCSP_url_svcloc_new(const X509_NAME *issuer, const char **urls)
goto err;
if ((ia5 = ASN1_IA5STRING_new()) == NULL)
goto err;
- if (!ASN1_STRING_set((ASN1_STRING *)ia5, *urls, -1))
+ if (!ASN1_STRING_set_string((ASN1_STRING *)ia5, *urls))
goto err;
/* ad->location is allocated inside ACCESS_DESCRIPTION_new */
ad->location->type = GEN_URI;
diff --git a/crypto/ocsp/ocsp_srv.c b/crypto/ocsp/ocsp_srv.c
index beecad63a2..fa99da8a7f 100644
--- a/crypto/ocsp/ocsp_srv.c
+++ b/crypto/ocsp/ocsp_srv.c
@@ -301,7 +301,7 @@ int OCSP_RESPID_match_ex(OCSP_RESPID *respid, X509 *cert, OSSL_LIB_CTX *libctx,
if (!X509_pubkey_digest(cert, sha1, md, NULL))
goto err;
- ret = (ASN1_STRING_length(respid->value.byKey) == SHA_DIGEST_LENGTH)
+ ret = (ASN1_STRING_length_ex(respid->value.byKey) == SHA_DIGEST_LENGTH)
&& (memcmp(ASN1_STRING_get0_data(respid->value.byKey), md,
SHA_DIGEST_LENGTH)
== 0);
diff --git a/crypto/ocsp/v3_ocsp.c b/crypto/ocsp/v3_ocsp.c
index d31c74ef45..408c2a1548 100644
--- a/crypto/ocsp/v3_ocsp.c
+++ b/crypto/ocsp/v3_ocsp.c
@@ -143,7 +143,7 @@ static void *ocsp_nonce_new(void)
static int i2d_ocsp_nonce(const void *a, unsigned char **pp)
{
const ASN1_OCTET_STRING *os = a;
- if (pp) {
+ if (pp != NULL && os->length > 0) {
memcpy(*pp, os->data, os->length);
*pp += os->length;
}
@@ -164,7 +164,8 @@ static void *d2i_ocsp_nonce(void *a, const unsigned char **pp, long length)
if (!ASN1_OCTET_STRING_set(os, *pp, length))
goto err;
- *pp += length;
+ if (length > 0)
+ *pp += length;
if (pos)
*pos = os;
diff --git a/crypto/pem/pem_info.c b/crypto/pem/pem_info.c
index 8f38fe0580..fa189f0c5d 100644
--- a/crypto/pem/pem_info.c
+++ b/crypto/pem/pem_info.c
@@ -24,6 +24,14 @@
#include
#include "crypto/evp.h"
+typedef enum {
+ PEM_INFO_NONE,
+ PEM_INFO_X509,
+ PEM_INFO_X509_AUX,
+ PEM_INFO_X509_CRL,
+ PEM_INFO_PKEY
+} pem_info_type;
+
#ifndef OPENSSL_NO_STDIO
STACK_OF(X509_INFO)
*PEM_X509_INFO_read_ex(FILE *fp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb,
@@ -63,7 +71,7 @@ STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio_ex(BIO *bp, STACK_OF(X509_INFO) *sk,
int ok = 0;
STACK_OF(X509_INFO) *ret = NULL;
unsigned int i, raw, ptype;
- d2i_of_void *d2i = 0;
+ pem_info_type itype = PEM_INFO_NONE;
if (sk == NULL) {
if ((ret = sk_X509_INFO_new_null()) == NULL) {
@@ -78,6 +86,7 @@ STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio_ex(BIO *bp, STACK_OF(X509_INFO) *sk,
for (;;) {
raw = 0;
ptype = 0;
+ itype = PEM_INFO_NONE;
ERR_set_mark();
i = PEM_read_bio(bp, &name, &header, &data, &len);
if (i == 0) {
@@ -102,15 +111,15 @@ STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio_ex(BIO *bp, STACK_OF(X509_INFO) *sk,
goto start;
}
if ((strcmp(name, PEM_STRING_X509_TRUSTED) == 0))
- d2i = (D2I_OF(void))d2i_X509_AUX;
+ itype = PEM_INFO_X509_AUX;
else
- d2i = (D2I_OF(void))d2i_X509;
+ itype = PEM_INFO_X509;
xi->x509 = X509_new_ex(libctx, propq);
if (xi->x509 == NULL)
goto err;
pp = &(xi->x509);
} else if (strcmp(name, PEM_STRING_X509_CRL) == 0) {
- d2i = (D2I_OF(void))d2i_X509_CRL;
+ itype = PEM_INFO_X509_CRL;
if (xi->crl != NULL) {
if (!sk_X509_INFO_push(ret, xi))
goto err;
@@ -137,7 +146,7 @@ STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio_ex(BIO *bp, STACK_OF(X509_INFO) *sk,
xi->enc_data = NULL;
xi->enc_len = 0;
- d2i = (D2I_OF(void))d2i_AutoPrivateKey;
+ itype = PEM_INFO_PKEY;
xi->x_pkey = X509_PKEY_new();
if (xi->x_pkey == NULL)
goto err;
@@ -146,11 +155,11 @@ STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio_ex(BIO *bp, STACK_OF(X509_INFO) *sk,
|| strcmp(name, PEM_STRING_PKCS8) == 0)
raw = 1;
} else { /* unknown */
- d2i = NULL;
+ itype = PEM_INFO_NONE;
pp = NULL;
}
- if (d2i != NULL) {
+ if (itype != PEM_INFO_NONE) {
if (!raw) {
EVP_CIPHER_INFO cipher;
@@ -160,15 +169,36 @@ STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio_ex(BIO *bp, STACK_OF(X509_INFO) *sk,
goto err;
p = data;
if (ptype) {
- if (d2i_PrivateKey_ex(ptype, pp, &p, len,
+ if (d2i_PrivateKey_ex(ptype, (EVP_PKEY **)pp, &p, len,
libctx, propq)
== NULL) {
ERR_raise(ERR_LIB_PEM, ERR_R_ASN1_LIB);
goto err;
}
- } else if (d2i(pp, &p, len) == NULL) {
- ERR_raise(ERR_LIB_PEM, ERR_R_ASN1_LIB);
- goto err;
+ } else {
+ void *decoded = NULL;
+
+ switch (itype) {
+ case PEM_INFO_X509:
+ decoded = d2i_X509((X509 **)pp, &p, len);
+ break;
+ case PEM_INFO_X509_AUX:
+ decoded = d2i_X509_AUX((X509 **)pp, &p, len);
+ break;
+ case PEM_INFO_X509_CRL:
+ decoded = d2i_X509_CRL((X509_CRL **)pp, &p, len);
+ break;
+ case PEM_INFO_PKEY:
+ decoded = d2i_AutoPrivateKey_ex((EVP_PKEY **)pp, &p,
+ len, libctx, propq);
+ break;
+ default:
+ break;
+ }
+ if (decoded == NULL) {
+ ERR_raise(ERR_LIB_PEM, ERR_R_ASN1_LIB);
+ goto err;
+ }
}
} else { /* encrypted key data */
if (!PEM_get_EVP_CIPHER_INFO(header, &xi->enc_cipher))
diff --git a/crypto/pkcs12/p12_add.c b/crypto/pkcs12/p12_add.c
index 8ea41676d8..1217317783 100644
--- a/crypto/pkcs12/p12_add.c
+++ b/crypto/pkcs12/p12_add.c
@@ -219,6 +219,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/crypto/pkcs12/p12_mutl.c b/crypto/pkcs12/p12_mutl.c
index 2888efd689..60843bd951 100644
--- a/crypto/pkcs12/p12_mutl.c
+++ b/crypto/pkcs12/p12_mutl.c
@@ -350,7 +350,7 @@ int PKCS12_verify_mac(PKCS12 *p12, const char *pass, int passlen)
}
}
X509_SIG_get0(p12->mac->dinfo, NULL, &macoct);
- if ((maclen != (unsigned int)ASN1_STRING_length(macoct))
+ if ((maclen != ASN1_STRING_length_ex(macoct))
|| CRYPTO_memcmp(mac, ASN1_STRING_get0_data(macoct), maclen) != 0)
return 0;
diff --git a/crypto/pkcs7/pk7_attr.c b/crypto/pkcs7/pk7_attr.c
index b865d97356..28f073f36f 100644
--- a/crypto/pkcs7/pk7_attr.c
+++ b/crypto/pkcs7/pk7_attr.c
@@ -30,7 +30,7 @@ int PKCS7_add_attrib_smimecap(PKCS7_SIGNER_INFO *si,
}
seq->length = ASN1_item_i2d((ASN1_VALUE *)cap, &seq->data,
ASN1_ITEM_rptr(X509_ALGORS));
- if (ASN1_STRING_length(seq) <= 0 || ASN1_STRING_get0_data(seq) == NULL) {
+ if (ASN1_STRING_length_ex(seq) == 0 || ASN1_STRING_get0_data(seq) == NULL) {
ASN1_STRING_free(seq);
return 1;
}
@@ -46,14 +46,17 @@ STACK_OF(X509_ALGOR) *PKCS7_get_smimecap(PKCS7_SIGNER_INFO *si)
{
const ASN1_TYPE *cap;
const unsigned char *p;
+ size_t len;
cap = PKCS7_get_signed_attribute(si, NID_SMIMECapabilities);
if (cap == NULL || (cap->type != V_ASN1_SEQUENCE))
return NULL;
p = ASN1_STRING_get0_data(cap->value.sequence);
+ len = ASN1_STRING_length_ex(cap->value.sequence);
+ if (len > INT_MAX)
+ return NULL;
return (STACK_OF(X509_ALGOR) *)
- ASN1_item_d2i(NULL, &p, ASN1_STRING_length(cap->value.sequence),
- ASN1_ITEM_rptr(X509_ALGORS));
+ ASN1_item_d2i(NULL, &p, (int)len, ASN1_ITEM_rptr(X509_ALGORS));
}
/* Basic smime-capabilities OID and optional integer arg */
@@ -129,7 +132,7 @@ int PKCS7_add1_attrib_digest(PKCS7_SIGNER_INFO *si,
os = ASN1_OCTET_STRING_new();
if (os == NULL)
return 0;
- if (!ASN1_STRING_set(os, md, mdlen)
+ if (!ASN1_STRING_set_data(os, md, mdlen)
|| !PKCS7_add_signed_attribute(si, NID_pkcs9_messageDigest,
V_ASN1_OCTET_STRING, os)) {
ASN1_OCTET_STRING_free(os);
diff --git a/crypto/pkcs7/pk7_doit.c b/crypto/pkcs7/pk7_doit.c
index 7b6a3b36b4..33d2eaafdf 100644
--- a/crypto/pkcs7/pk7_doit.c
+++ b/crypto/pkcs7/pk7_doit.c
@@ -74,16 +74,19 @@ static ASN1_OCTET_STRING *pkcs7_get1_data(PKCS7 *p7)
if (PKCS7_type_is_other(p7) && (p7->d.other != NULL)
&& (p7->d.other->type == V_ASN1_SEQUENCE)
&& (p7->d.other->value.sequence != NULL)
- && (ASN1_STRING_length(p7->d.other->value.sequence) > 0)) {
+ && (ASN1_STRING_length_ex(p7->d.other->value.sequence) > 0)) {
const unsigned char *data = ASN1_STRING_get0_data(p7->d.other->value.sequence);
long len;
int inf, tag, class;
+ size_t tmp;
+ tmp = ASN1_STRING_length_ex(p7->d.other->value.sequence);
+ if (tmp > INT_MAX)
+ return NULL;
os = ASN1_OCTET_STRING_new();
if (os == NULL)
return NULL;
- inf = ASN1_get_object(&data, &len, &tag, &class,
- ASN1_STRING_length(p7->d.other->value.sequence));
+ inf = ASN1_get_object(&data, &len, &tag, &class, (int)tmp);
if (inf != V_ASN1_CONSTRUCTED || tag != V_ASN1_SEQUENCE
|| !ASN1_OCTET_STRING_set(os, data, len)) {
ASN1_OCTET_STRING_free(os);
@@ -198,7 +201,7 @@ static int pkcs7_decrypt_rinfo(unsigned char **pek, int *peklen,
goto err;
ret = evp_pkey_decrypt_alloc(pctx, &ek, &eklen, fixlen,
- ASN1_STRING_get0_data(ri->enc_key), ASN1_STRING_length(ri->enc_key));
+ ASN1_STRING_get0_data(ri->enc_key), ASN1_STRING_length_ex(ri->enc_key));
if (ret <= 0)
goto err;
@@ -371,7 +374,7 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio)
if (bio == NULL) {
if (PKCS7_is_detached(p7)) {
bio = BIO_new(BIO_s_null());
- } else if (os != NULL && ASN1_STRING_length(os) > 0) {
+ } else if (os != NULL && ASN1_STRING_length_ex(os) > 0) {
/*
* bio needs a copy of os->data instead of a pointer because
* the data will be used after os has been freed
@@ -380,8 +383,8 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio)
if (bio != NULL) {
BIO_set_mem_eof_return(bio, 0);
const unsigned char *os_data = ASN1_STRING_get0_data(os);
- int os_len = ASN1_STRING_length(os);
- if (BIO_write(bio, os_data, os_len) != os_len) {
+ size_t os_len = ASN1_STRING_length_ex(os);
+ if (os_len > INT_MAX || BIO_write(bio, os_data, (int)os_len) != (int)os_len) {
BIO_free_all(bio);
bio = NULL;
}
@@ -656,10 +659,12 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
if (in_bio != NULL) {
bio = in_bio;
} else {
- int data_body_len = ASN1_STRING_length(data_body);
+ size_t data_body_len = ASN1_STRING_length_ex(data_body);
+ if (data_body_len > INT_MAX)
+ goto err;
if (data_body_len > 0)
bio = BIO_new_mem_buf(ASN1_STRING_get0_data(data_body),
- data_body_len);
+ (int)data_body_len);
else {
bio = BIO_new(BIO_s_mem());
if (bio == NULL)
@@ -1110,7 +1115,7 @@ int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
ERR_raise(ERR_LIB_PKCS7, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST);
goto err;
}
- if ((ASN1_STRING_length(message_digest) != (int)md_len)
+ if ((ASN1_STRING_length_ex(message_digest) != md_len)
|| (memcmp(ASN1_STRING_get0_data(message_digest), md_dat, md_len))) {
ERR_raise(ERR_LIB_PKCS7, PKCS7_R_DIGEST_FAILURE);
ret = -1;
@@ -1142,8 +1147,12 @@ int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
}
const unsigned char *sig_data = ASN1_STRING_get0_data(os);
- int sig_len = ASN1_STRING_length(os);
- i = EVP_VerifyFinal_ex(mdc_tmp, sig_data, sig_len, pkey, libctx, propq);
+ size_t sig_len = ASN1_STRING_length_ex(os);
+ if (sig_len > INT_MAX) {
+ ret = -1;
+ goto err;
+ }
+ i = EVP_VerifyFinal_ex(mdc_tmp, sig_data, (int)sig_len, pkey, libctx, propq);
if (i <= 0) {
ERR_raise(ERR_LIB_PKCS7, PKCS7_R_SIGNATURE_FAILURE);
ret = -1;
@@ -1171,7 +1180,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/crypto/pkcs7/pk7_lib.c b/crypto/pkcs7/pk7_lib.c
index 0a1d0f61a5..a9640769cf 100644
--- a/crypto/pkcs7/pk7_lib.c
+++ b/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)
diff --git a/crypto/pkcs7/pk7_smime.c b/crypto/pkcs7/pk7_smime.c
index 49129690de..7ede4b6694 100644
--- a/crypto/pkcs7/pk7_smime.c
+++ b/crypto/pkcs7/pk7_smime.c
@@ -199,9 +199,15 @@ static int pkcs7_copy_existing_digest(PKCS7 *p7, PKCS7_SIGNER_INFO *si)
}
}
- if (osdig != NULL)
- return PKCS7_add1_attrib_digest(si, ASN1_STRING_get0_data(osdig), ASN1_STRING_length(osdig));
+ if (osdig != NULL) {
+ size_t len;
+ len = ASN1_STRING_length_ex(osdig);
+ if (len > INT_MAX)
+ goto err;
+ return PKCS7_add1_attrib_digest(si, ASN1_STRING_get0_data(osdig), (int)len);
+ }
+err:
ERR_raise(ERR_LIB_PKCS7, PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND);
return 0;
}
diff --git a/crypto/poly1305/poly1305_base2_44.c b/crypto/poly1305/poly1305_base2_44.c
deleted file mode 100644
index e64f5294d8..0000000000
--- a/crypto/poly1305/poly1305_base2_44.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright 2016-2021 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 module is meant to be used as template for base 2^44 assembly
- * implementation[s]. On side note compiler-generated code is not
- * slower than compiler-generated base 2^64 code on [high-end] x86_64,
- * even though amount of multiplications is 50% higher. Go figure...
- */
-#include
-#include
-
-typedef uint128_t u128;
-
-typedef struct {
- uint64_t h[3];
- uint64_t s[2];
- uint64_t r[3];
-} poly1305_internal;
-
-#define POLY1305_BLOCK_SIZE 16
-
-/* pick 64-bit unsigned integer in little endian order */
-static uint64_t U8TOU64(const unsigned char *p)
-{
- return (((uint64_t)(p[0] & 0xff)) | ((uint64_t)(p[1] & 0xff) << 8) | ((uint64_t)(p[2] & 0xff) << 16) | ((uint64_t)(p[3] & 0xff) << 24) | ((uint64_t)(p[4] & 0xff) << 32) | ((uint64_t)(p[5] & 0xff) << 40) | ((uint64_t)(p[6] & 0xff) << 48) | ((uint64_t)(p[7] & 0xff) << 56));
-}
-
-/* store a 64-bit unsigned integer in little endian */
-static void U64TO8(unsigned char *p, uint64_t v)
-{
- p[0] = (unsigned char)((v) & 0xff);
- p[1] = (unsigned char)((v >> 8) & 0xff);
- p[2] = (unsigned char)((v >> 16) & 0xff);
- p[3] = (unsigned char)((v >> 24) & 0xff);
- p[4] = (unsigned char)((v >> 32) & 0xff);
- p[5] = (unsigned char)((v >> 40) & 0xff);
- p[6] = (unsigned char)((v >> 48) & 0xff);
- p[7] = (unsigned char)((v >> 56) & 0xff);
-}
-
-int poly1305_init(void *ctx, const unsigned char key[16])
-{
- poly1305_internal *st = (poly1305_internal *)ctx;
- uint64_t r0, r1;
-
- /* h = 0 */
- st->h[0] = 0;
- st->h[1] = 0;
- st->h[2] = 0;
-
- r0 = U8TOU64(&key[0]) & 0x0ffffffc0fffffff;
- r1 = U8TOU64(&key[8]) & 0x0ffffffc0ffffffc;
-
- /* break r1:r0 to three 44-bit digits, masks are 1<<44-1 */
- st->r[0] = r0 & 0x0fffffffffff;
- st->r[1] = ((r0 >> 44) | (r1 << 20)) & 0x0fffffffffff;
- st->r[2] = (r1 >> 24);
-
- st->s[0] = (st->r[1] + (st->r[1] << 2)) << 2;
- st->s[1] = (st->r[2] + (st->r[2] << 2)) << 2;
-
- return 0;
-}
-
-void poly1305_blocks(void *ctx, const unsigned char *inp, size_t len,
- uint32_t padbit)
-{
- poly1305_internal *st = (poly1305_internal *)ctx;
- uint64_t r0, r1, r2;
- uint64_t s1, s2;
- uint64_t h0, h1, h2, c;
- u128 d0, d1, d2;
- uint64_t pad = (uint64_t)padbit << 40;
-
- r0 = st->r[0];
- r1 = st->r[1];
- r2 = st->r[2];
-
- s1 = st->s[0];
- s2 = st->s[1];
-
- h0 = st->h[0];
- h1 = st->h[1];
- h2 = st->h[2];
-
- while (len >= POLY1305_BLOCK_SIZE) {
- uint64_t m0, m1;
-
- m0 = U8TOU64(inp + 0);
- m1 = U8TOU64(inp + 8);
-
- /* h += m[i], m[i] is broken to 44-bit digits */
- h0 += m0 & 0x0fffffffffff;
- h1 += ((m0 >> 44) | (m1 << 20)) & 0x0fffffffffff;
- h2 += (m1 >> 24) + pad;
-
- /* h *= r "%" p, where "%" stands for "partial remainder" */
- d0 = ((u128)h0 * r0) + ((u128)h1 * s2) + ((u128)h2 * s1);
- d1 = ((u128)h0 * r1) + ((u128)h1 * r0) + ((u128)h2 * s2);
- d2 = ((u128)h0 * r2) + ((u128)h1 * r1) + ((u128)h2 * r0);
-
- /* "lazy" reduction step */
- h0 = (uint64_t)d0 & 0x0fffffffffff;
- h1 = (uint64_t)(d1 += (uint64_t)(d0 >> 44)) & 0x0fffffffffff;
- h2 = (uint64_t)(d2 += (uint64_t)(d1 >> 44)) & 0x03ffffffffff; /* last 42 bits */
-
- c = (d2 >> 42);
- h0 += c + (c << 2);
-
- inp += POLY1305_BLOCK_SIZE;
- len -= POLY1305_BLOCK_SIZE;
- }
-
- st->h[0] = h0;
- st->h[1] = h1;
- st->h[2] = h2;
-}
-
-void poly1305_emit(void *ctx, unsigned char mac[16], const uint32_t nonce[4])
-{
- poly1305_internal *st = (poly1305_internal *)ctx;
- uint64_t h0, h1, h2;
- uint64_t g0, g1, g2;
- u128 t;
- uint64_t mask;
-
- h0 = st->h[0];
- h1 = st->h[1];
- h2 = st->h[2];
-
- /* after "lazy" reduction, convert 44+bit digits to 64-bit ones */
- h0 = (uint64_t)(t = (u128)h0 + (h1 << 44));
- h1 >>= 20;
- h1 = (uint64_t)(t = (u128)h1 + (h2 << 24) + (t >> 64));
- h2 >>= 40;
- h2 += (uint64_t)(t >> 64);
-
- /* compare to modulus by computing h + -p */
- g0 = (uint64_t)(t = (u128)h0 + 5);
- g1 = (uint64_t)(t = (u128)h1 + (t >> 64));
- g2 = h2 + (uint64_t)(t >> 64);
-
- /* if there was carry into 131st bit, h1:h0 = g1:g0 */
- mask = 0 - (g2 >> 2);
- g0 &= mask;
- g1 &= mask;
- mask = ~mask;
- h0 = (h0 & mask) | g0;
- h1 = (h1 & mask) | g1;
-
- /* mac = (h + nonce) % (2^128) */
- h0 = (uint64_t)(t = (u128)h0 + nonce[0] + ((uint64_t)nonce[1] << 32));
- h1 = (uint64_t)(t = (u128)h1 + nonce[2] + ((uint64_t)nonce[3] << 32) + (t >> 64));
-
- U64TO8(mac + 0, h0);
- U64TO8(mac + 8, h1);
-}
diff --git a/crypto/poly1305/poly1305_ieee754.c b/crypto/poly1305/poly1305_ieee754.c
deleted file mode 100644
index 16d3d0f5a9..0000000000
--- a/crypto/poly1305/poly1305_ieee754.c
+++ /dev/null
@@ -1,485 +0,0 @@
-/*
- * Copyright 2016-2024 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 module is meant to be used as template for non-x87 floating-
- * point assembly modules. The template itself is x86_64-specific
- * though, as it was debugged on x86_64. So that implementer would
- * have to recognize platform-specific parts, UxTOy and inline asm,
- * and act accordingly.
- *
- * Huh? x86_64-specific code as template for non-x87? Note seven, which
- * is not a typo, but reference to 80-bit precision. This module on the
- * other hand relies on 64-bit precision operations, which are default
- * for x86_64 code. And since we are at it, just for sense of it,
- * large-block performance in cycles per processed byte for *this* code
- * is:
- * gcc-4.8 icc-15.0 clang-3.4(*)
- *
- * Westmere 4.96 5.09 4.37
- * Sandy Bridge 4.95 4.90 4.17
- * Haswell 4.92 4.87 3.78
- * Bulldozer 4.67 4.49 4.68
- * VIA Nano 7.07 7.05 5.98
- * Silvermont 10.6 9.61 12.6
- *
- * (*) clang managed to discover parallelism and deployed SIMD;
- *
- * And for range of other platforms with unspecified gcc versions:
- *
- * Freescale e300 12.5
- * PPC74x0 10.8
- * POWER6 4.92
- * POWER7 4.50
- * POWER8 4.10
- *
- * z10 11.2
- * z196+ 7.30
- *
- * UltraSPARC III 16.0
- * SPARC T4 16.1
- */
-
-#if !(defined(__GNUC__) && __GNUC__ >= 2)
-#error "this is gcc-specific template"
-#endif
-
-#include
-#include
-
-typedef union {
- double d;
- uint64_t u;
-} elem64;
-
-#define TWO(p) ((double)(1ULL << (p)))
-#define TWO0 TWO(0)
-#define TWO32 TWO(32)
-#define TWO64 (TWO32 * TWO(32))
-#define TWO96 (TWO64 * TWO(32))
-#define TWO130 (TWO96 * TWO(34))
-
-#define EXP(p) ((1023ULL + (p)) << 52)
-
-#if defined(__x86_64__) || (defined(__PPC__) && defined(__LITTLE_ENDIAN__))
-#define U8TOU32(p) (*(const uint32_t *)(p))
-#define U32TO8(p, v) (*(uint32_t *)(p) = (v))
-#elif defined(__PPC__) || defined(__POWERPC__)
-#define U8TOU32(p) ({uint32_t ret; asm ("lwbrx %0,0,%1":"=r"(ret):"b"(p)); ret; })
-#define U32TO8(p, v) asm("stwbrx %0,0,%1" ::"r"(v), "b"(p) : "memory")
-#elif defined(__s390x__)
-#define U8TOU32(p) ({uint32_t ret; asm ("lrv %0,%1":"=d"(ret):"m"(*(uint32_t *)(p))); ret; })
-#define U32TO8(p, v) asm("strv %1,%0" : "=m"(*(uint32_t *)(p)) : "d"(v))
-#endif
-
-#ifndef U8TOU32
-#define U8TOU32(p) ((uint32_t)(p)[0] | (uint32_t)(p)[1] << 8 | (uint32_t)(p)[2] << 16 | (uint32_t)(p)[3] << 24)
-#endif
-#ifndef U32TO8
-#define U32TO8(p, v) ((p)[0] = (uint8_t)(v), (p)[1] = (uint8_t)((v) >> 8), \
- (p)[2] = (uint8_t)((v) >> 16), (p)[3] = (uint8_t)((v) >> 24))
-#endif
-
-typedef struct {
- elem64 h[4];
- double r[8];
- double s[6];
-} poly1305_internal;
-
-/* "round toward zero (truncate), mask all exceptions" */
-#if defined(__x86_64__)
-static const uint32_t mxcsr = 0x7f80;
-#elif defined(__PPC__) || defined(__POWERPC__)
-static const uint64_t one = 1;
-#elif defined(__s390x__)
-static const uint32_t fpc = 1;
-#elif defined(__sparc__)
-static const uint64_t fsr = 1ULL << 30;
-#elif defined(__mips__)
-static const uint32_t fcsr = 1;
-#else
-#error "unrecognized platform"
-#endif
-
-int poly1305_init(void *ctx, const unsigned char key[16])
-{
- poly1305_internal *st = (poly1305_internal *)ctx;
- elem64 r0, r1, r2, r3;
-
- /* h = 0, biased */
-#if 0
- st->h[0].d = TWO(52)*TWO0;
- st->h[1].d = TWO(52)*TWO32;
- st->h[2].d = TWO(52)*TWO64;
- st->h[3].d = TWO(52)*TWO96;
-#else
- st->h[0].u = EXP(52 + 0);
- st->h[1].u = EXP(52 + 32);
- st->h[2].u = EXP(52 + 64);
- st->h[3].u = EXP(52 + 96);
-#endif
-
- if (key) {
- /*
- * set "truncate" rounding mode
- */
-#if defined(__x86_64__)
- uint32_t mxcsr_orig;
-
- asm volatile("stmxcsr %0" : "=m"(mxcsr_orig));
- asm volatile("ldmxcsr %0" ::"m"(mxcsr));
-#elif defined(__PPC__) || defined(__POWERPC__)
- double fpscr_orig, fpscr = *(double *)&one;
-
- asm volatile("mffs %0" : "=f"(fpscr_orig));
- asm volatile("mtfsf 255,%0" ::"f"(fpscr));
-#elif defined(__s390x__)
- uint32_t fpc_orig;
-
- asm volatile("stfpc %0" : "=m"(fpc_orig));
- asm volatile("lfpc %0" ::"m"(fpc));
-#elif defined(__sparc__)
- uint64_t fsr_orig;
-
- asm volatile("stx %%fsr,%0" : "=m"(fsr_orig));
- asm volatile("ldx %0,%%fsr" ::"m"(fsr));
-#elif defined(__mips__)
- uint32_t fcsr_orig;
-
- asm volatile("cfc1 %0,$31" : "=r"(fcsr_orig));
- asm volatile("ctc1 %0,$31" ::"r"(fcsr));
-#endif
-
- /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
- r0.u = EXP(52 + 0) | (U8TOU32(&key[0]) & 0x0fffffff);
- r1.u = EXP(52 + 32) | (U8TOU32(&key[4]) & 0x0ffffffc);
- r2.u = EXP(52 + 64) | (U8TOU32(&key[8]) & 0x0ffffffc);
- r3.u = EXP(52 + 96) | (U8TOU32(&key[12]) & 0x0ffffffc);
-
- st->r[0] = r0.d - TWO(52) * TWO0;
- st->r[2] = r1.d - TWO(52) * TWO32;
- st->r[4] = r2.d - TWO(52) * TWO64;
- st->r[6] = r3.d - TWO(52) * TWO96;
-
- st->s[0] = st->r[2] * (5.0 / TWO130);
- st->s[2] = st->r[4] * (5.0 / TWO130);
- st->s[4] = st->r[6] * (5.0 / TWO130);
-
- /*
- * base 2^32 -> base 2^16
- */
- st->r[1] = (st->r[0] + TWO(52) * TWO(16) * TWO0) - TWO(52) * TWO(16) * TWO0;
- st->r[0] -= st->r[1];
-
- st->r[3] = (st->r[2] + TWO(52) * TWO(16) * TWO32) - TWO(52) * TWO(16) * TWO32;
- st->r[2] -= st->r[3];
-
- st->r[5] = (st->r[4] + TWO(52) * TWO(16) * TWO64) - TWO(52) * TWO(16) * TWO64;
- st->r[4] -= st->r[5];
-
- st->r[7] = (st->r[6] + TWO(52) * TWO(16) * TWO96) - TWO(52) * TWO(16) * TWO96;
- st->r[6] -= st->r[7];
-
- st->s[1] = (st->s[0] + TWO(52) * TWO(16) * TWO0 / TWO96) - TWO(52) * TWO(16) * TWO0 / TWO96;
- st->s[0] -= st->s[1];
-
- st->s[3] = (st->s[2] + TWO(52) * TWO(16) * TWO32 / TWO96) - TWO(52) * TWO(16) * TWO32 / TWO96;
- st->s[2] -= st->s[3];
-
- st->s[5] = (st->s[4] + TWO(52) * TWO(16) * TWO64 / TWO96) - TWO(52) * TWO(16) * TWO64 / TWO96;
- st->s[4] -= st->s[5];
-
- /*
- * restore original FPU control register
- */
-#if defined(__x86_64__)
- asm volatile("ldmxcsr %0" ::"m"(mxcsr_orig));
-#elif defined(__PPC__) || defined(__POWERPC__)
- asm volatile("mtfsf 255,%0" ::"f"(fpscr_orig));
-#elif defined(__s390x__)
- asm volatile("lfpc %0" ::"m"(fpc_orig));
-#elif defined(__sparc__)
- asm volatile("ldx %0,%%fsr" ::"m"(fsr_orig));
-#elif defined(__mips__)
- asm volatile("ctc1 %0,$31" ::"r"(fcsr_orig));
-#endif
- }
-
- return 0;
-}
-
-void poly1305_blocks(void *ctx, const unsigned char *inp, size_t len,
- int padbit)
-{
- poly1305_internal *st = (poly1305_internal *)ctx;
- elem64 in0, in1, in2, in3;
- uint64_t pad = (uint64_t)padbit << 32;
-
- double x0, x1, x2, x3;
- double h0lo, h0hi, h1lo, h1hi, h2lo, h2hi, h3lo, h3hi;
- double c0lo, c0hi, c1lo, c1hi, c2lo, c2hi, c3lo, c3hi;
-
- const double r0lo = st->r[0];
- const double r0hi = st->r[1];
- const double r1lo = st->r[2];
- const double r1hi = st->r[3];
- const double r2lo = st->r[4];
- const double r2hi = st->r[5];
- const double r3lo = st->r[6];
- const double r3hi = st->r[7];
-
- const double s1lo = st->s[0];
- const double s1hi = st->s[1];
- const double s2lo = st->s[2];
- const double s2hi = st->s[3];
- const double s3lo = st->s[4];
- const double s3hi = st->s[5];
-
- /*
- * set "truncate" rounding mode
- */
-#if defined(__x86_64__)
- uint32_t mxcsr_orig;
-
- asm volatile("stmxcsr %0" : "=m"(mxcsr_orig));
- asm volatile("ldmxcsr %0" ::"m"(mxcsr));
-#elif defined(__PPC__) || defined(__POWERPC__)
- double fpscr_orig, fpscr = *(double *)&one;
-
- asm volatile("mffs %0" : "=f"(fpscr_orig));
- asm volatile("mtfsf 255,%0" ::"f"(fpscr));
-#elif defined(__s390x__)
- uint32_t fpc_orig;
-
- asm volatile("stfpc %0" : "=m"(fpc_orig));
- asm volatile("lfpc %0" ::"m"(fpc));
-#elif defined(__sparc__)
- uint64_t fsr_orig;
-
- asm volatile("stx %%fsr,%0" : "=m"(fsr_orig));
- asm volatile("ldx %0,%%fsr" ::"m"(fsr));
-#elif defined(__mips__)
- uint32_t fcsr_orig;
-
- asm volatile("cfc1 %0,$31" : "=r"(fcsr_orig));
- asm volatile("ctc1 %0,$31" ::"r"(fcsr));
-#endif
-
- /*
- * load base 2^32 and de-bias
- */
- h0lo = st->h[0].d - TWO(52) * TWO0;
- h1lo = st->h[1].d - TWO(52) * TWO32;
- h2lo = st->h[2].d - TWO(52) * TWO64;
- h3lo = st->h[3].d - TWO(52) * TWO96;
-
-#ifdef __clang__
- h0hi = 0;
- h1hi = 0;
- h2hi = 0;
- h3hi = 0;
-#else
- in0.u = EXP(52 + 0) | U8TOU32(&inp[0]);
- in1.u = EXP(52 + 32) | U8TOU32(&inp[4]);
- in2.u = EXP(52 + 64) | U8TOU32(&inp[8]);
- in3.u = EXP(52 + 96) | U8TOU32(&inp[12]) | pad;
-
- x0 = in0.d - TWO(52) * TWO0;
- x1 = in1.d - TWO(52) * TWO32;
- x2 = in2.d - TWO(52) * TWO64;
- x3 = in3.d - TWO(52) * TWO96;
-
- x0 += h0lo;
- x1 += h1lo;
- x2 += h2lo;
- x3 += h3lo;
-
- goto fast_entry;
-#endif
-
- do {
- in0.u = EXP(52 + 0) | U8TOU32(&inp[0]);
- in1.u = EXP(52 + 32) | U8TOU32(&inp[4]);
- in2.u = EXP(52 + 64) | U8TOU32(&inp[8]);
- in3.u = EXP(52 + 96) | U8TOU32(&inp[12]) | pad;
-
- x0 = in0.d - TWO(52) * TWO0;
- x1 = in1.d - TWO(52) * TWO32;
- x2 = in2.d - TWO(52) * TWO64;
- x3 = in3.d - TWO(52) * TWO96;
-
- /*
- * note that there are multiple ways to accumulate input, e.g.
- * one can as well accumulate to h0lo-h1lo-h1hi-h2hi...
- */
- h0lo += x0;
- h0hi += x1;
- h2lo += x2;
- h2hi += x3;
-
- /*
- * carries that cross 32n-bit (and 130-bit) boundaries
- */
- c0lo = (h0lo + TWO(52) * TWO32) - TWO(52) * TWO32;
- c1lo = (h1lo + TWO(52) * TWO64) - TWO(52) * TWO64;
- c2lo = (h2lo + TWO(52) * TWO96) - TWO(52) * TWO96;
- c3lo = (h3lo + TWO(52) * TWO130) - TWO(52) * TWO130;
-
- c0hi = (h0hi + TWO(52) * TWO32) - TWO(52) * TWO32;
- c1hi = (h1hi + TWO(52) * TWO64) - TWO(52) * TWO64;
- c2hi = (h2hi + TWO(52) * TWO96) - TWO(52) * TWO96;
- c3hi = (h3hi + TWO(52) * TWO130) - TWO(52) * TWO130;
-
- /*
- * base 2^48 -> base 2^32 with last reduction step
- */
- x1 = (h1lo - c1lo) + c0lo;
- x2 = (h2lo - c2lo) + c1lo;
- x3 = (h3lo - c3lo) + c2lo;
- x0 = (h0lo - c0lo) + c3lo * (5.0 / TWO130);
-
- x1 += (h1hi - c1hi) + c0hi;
- x2 += (h2hi - c2hi) + c1hi;
- x3 += (h3hi - c3hi) + c2hi;
- x0 += (h0hi - c0hi) + c3hi * (5.0 / TWO130);
-
-#ifndef __clang__
- fast_entry:
-#endif
- /*
- * base 2^32 * base 2^16 = base 2^48
- */
- h0lo = s3lo * x1 + s2lo * x2 + s1lo * x3 + r0lo * x0;
- h1lo = r0lo * x1 + s3lo * x2 + s2lo * x3 + r1lo * x0;
- h2lo = r1lo * x1 + r0lo * x2 + s3lo * x3 + r2lo * x0;
- h3lo = r2lo * x1 + r1lo * x2 + r0lo * x3 + r3lo * x0;
-
- h0hi = s3hi * x1 + s2hi * x2 + s1hi * x3 + r0hi * x0;
- h1hi = r0hi * x1 + s3hi * x2 + s2hi * x3 + r1hi * x0;
- h2hi = r1hi * x1 + r0hi * x2 + s3hi * x3 + r2hi * x0;
- h3hi = r2hi * x1 + r1hi * x2 + r0hi * x3 + r3hi * x0;
-
- inp += 16;
- len -= 16;
-
- } while (len >= 16);
-
- /*
- * carries that cross 32n-bit (and 130-bit) boundaries
- */
- c0lo = (h0lo + TWO(52) * TWO32) - TWO(52) * TWO32;
- c1lo = (h1lo + TWO(52) * TWO64) - TWO(52) * TWO64;
- c2lo = (h2lo + TWO(52) * TWO96) - TWO(52) * TWO96;
- c3lo = (h3lo + TWO(52) * TWO130) - TWO(52) * TWO130;
-
- c0hi = (h0hi + TWO(52) * TWO32) - TWO(52) * TWO32;
- c1hi = (h1hi + TWO(52) * TWO64) - TWO(52) * TWO64;
- c2hi = (h2hi + TWO(52) * TWO96) - TWO(52) * TWO96;
- c3hi = (h3hi + TWO(52) * TWO130) - TWO(52) * TWO130;
-
- /*
- * base 2^48 -> base 2^32 with last reduction step
- */
- x1 = (h1lo - c1lo) + c0lo;
- x2 = (h2lo - c2lo) + c1lo;
- x3 = (h3lo - c3lo) + c2lo;
- x0 = (h0lo - c0lo) + c3lo * (5.0 / TWO130);
-
- x1 += (h1hi - c1hi) + c0hi;
- x2 += (h2hi - c2hi) + c1hi;
- x3 += (h3hi - c3hi) + c2hi;
- x0 += (h0hi - c0hi) + c3hi * (5.0 / TWO130);
-
- /*
- * store base 2^32, with bias
- */
- st->h[1].d = x1 + TWO(52) * TWO32;
- st->h[2].d = x2 + TWO(52) * TWO64;
- st->h[3].d = x3 + TWO(52) * TWO96;
- st->h[0].d = x0 + TWO(52) * TWO0;
-
- /*
- * restore original FPU control register
- */
-#if defined(__x86_64__)
- asm volatile("ldmxcsr %0" ::"m"(mxcsr_orig));
-#elif defined(__PPC__) || defined(__POWERPC__)
- asm volatile("mtfsf 255,%0" ::"f"(fpscr_orig));
-#elif defined(__s390x__)
- asm volatile("lfpc %0" ::"m"(fpc_orig));
-#elif defined(__sparc__)
- asm volatile("ldx %0,%%fsr" ::"m"(fsr_orig));
-#elif defined(__mips__)
- asm volatile("ctc1 %0,$31" ::"r"(fcsr_orig));
-#endif
-}
-
-void poly1305_emit(void *ctx, unsigned char mac[16], const uint32_t nonce[4])
-{
- poly1305_internal *st = (poly1305_internal *)ctx;
- uint64_t h0, h1, h2, h3, h4;
- uint32_t g0, g1, g2, g3, g4;
- uint64_t t;
- uint32_t mask;
-
- /*
- * thanks to bias masking exponent gives integer result
- */
- h0 = st->h[0].u & 0x000fffffffffffffULL;
- h1 = st->h[1].u & 0x000fffffffffffffULL;
- h2 = st->h[2].u & 0x000fffffffffffffULL;
- h3 = st->h[3].u & 0x000fffffffffffffULL;
-
- /*
- * can be partially reduced, so reduce...
- */
- h4 = h3 >> 32;
- h3 &= 0xffffffffU;
- g4 = h4 & -4;
- h4 &= 3;
- g4 += g4 >> 2;
-
- h0 += g4;
- h1 += h0 >> 32;
- h0 &= 0xffffffffU;
- h2 += h1 >> 32;
- h1 &= 0xffffffffU;
- h3 += h2 >> 32;
- h2 &= 0xffffffffU;
-
- /* compute h + -p */
- g0 = (uint32_t)(t = h0 + 5);
- g1 = (uint32_t)(t = h1 + (t >> 32));
- g2 = (uint32_t)(t = h2 + (t >> 32));
- g3 = (uint32_t)(t = h3 + (t >> 32));
- g4 = h4 + (uint32_t)(t >> 32);
-
- /* if there was carry, select g0-g3 */
- mask = 0 - (g4 >> 2);
- g0 &= mask;
- g1 &= mask;
- g2 &= mask;
- g3 &= mask;
- mask = ~mask;
- g0 |= (h0 & mask);
- g1 |= (h1 & mask);
- g2 |= (h2 & mask);
- g3 |= (h3 & mask);
-
- /* mac = (h + nonce) % (2^128) */
- g0 = (uint32_t)(t = (uint64_t)g0 + nonce[0]);
- g1 = (uint32_t)(t = (uint64_t)g1 + (t >> 32) + nonce[1]);
- g2 = (uint32_t)(t = (uint64_t)g2 + (t >> 32) + nonce[2]);
- g3 = (uint32_t)(t = (uint64_t)g3 + (t >> 32) + nonce[3]);
-
- U32TO8(mac + 0, g0);
- U32TO8(mac + 4, g1);
- U32TO8(mac + 8, g2);
- U32TO8(mac + 12, g3);
-}
diff --git a/crypto/ppccap.c b/crypto/ppccap.c
index a2acf6b6ed..e029eb3051 100644
--- a/crypto/ppccap.c
+++ b/crypto/ppccap.c
@@ -134,7 +134,7 @@ static unsigned long getauxval(unsigned long key)
#define HWCAP_ARCH_3_00 (1U << 23)
#define HWCAP_ARCH_3_1 (1U << 18)
-#if defined(__GNUC__) && __GNUC__ >= 2
+#if defined(__GNUC__)
__attribute__((constructor))
#endif
void OPENSSL_cpuid_setup(void)
diff --git a/crypto/property/property.c b/crypto/property/property.c
index e807f06995..aa0bb283f1 100644
--- a/crypto/property/property.c
+++ b/crypto/property/property.c
@@ -830,10 +830,18 @@ int ossl_method_store_fetch(OSSL_METHOD_STORE *store,
}
}
fin:
- if (ret && ossl_method_up_ref(&best_impl->method)) {
+ if (ret) {
*method = best_impl->method.method;
if (prov_rw != NULL)
*prov_rw = best_impl->provider;
+#ifdef OPENSSL_NO_CACHED_FETCH
+ if (!ossl_method_up_ref(&best_impl->method)) {
+ ret = 0;
+ *method = NULL;
+ if (prov_rw != NULL)
+ *prov_rw = NULL;
+ }
+#endif
} else {
ret = 0;
}
@@ -938,9 +946,15 @@ static ossl_inline int ossl_method_store_cache_get_atomic(OSSL_METHOD_STORE *sto
r = ossl_method_store_atomic_find_in_list(sa, nid, prov, prop_query);
- if (r != NULL && ossl_method_up_ref(&r->method)) {
+ if (r != NULL) {
*method = r->method.method;
res = 1;
+#ifdef OPENSSL_NO_CACHED_FETCH
+ if (!ossl_method_up_ref(&r->method)) {
+ *method = NULL;
+ res = 0;
+ }
+#endif
}
return res;
diff --git a/crypto/provider_core.c b/crypto/provider_core.c
index 6094882947..93732995be 100644
--- a/crypto/provider_core.c
+++ b/crypto/provider_core.c
@@ -486,7 +486,7 @@ int ossl_provider_up_ref(OSSL_PROVIDER *prov)
{
int ref = 0;
- if (CRYPTO_UP_REF(&prov->refcnt, &ref) <= 0)
+ if (!CRYPTO_UP_REF(&prov->refcnt, &ref))
return 0;
#ifndef FIPS_MODULE
@@ -1134,7 +1134,7 @@ static int provider_init(OSSL_PROVIDER *prov)
prov->error_strings[0].error = ERR_PACK(prov->error_lib, 0, 0);
prov->error_strings[0].string = prov->name;
/*
- * Copy reasonstrings item 0..cnt-1 to prov->error_trings positions
+ * Copy reasonstrings item 0..cnt-1 to prov->error_strings positions
* 1..cnt.
*/
for (cnt2 = 1; cnt2 <= cnt; cnt2++) {
@@ -1576,7 +1576,7 @@ int ossl_provider_doall_activated(OSSL_LIB_CTX *ctx,
* to avoid upping the ref count on the parent provider, which we
* must not do while holding locks.
*/
- if (CRYPTO_UP_REF(&prov->refcnt, &ref) <= 0) {
+ if (!CRYPTO_UP_REF(&prov->refcnt, &ref)) {
CRYPTO_THREAD_unlock(prov->flag_lock);
goto err_unlock;
}
diff --git a/crypto/rand/rand_deprecated.c b/crypto/rand/rand_deprecated.c
index d838f3cd70..07b6ff04e8 100644
--- a/crypto/rand/rand_deprecated.c
+++ b/crypto/rand/rand_deprecated.c
@@ -12,7 +12,6 @@
#include
#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
-#include
#ifndef OPENSSL_NO_DEPRECATED_1_1_0
#define DEPRECATED_RAND_FUNCTIONS_DEFINED
diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c
index c8d77c68e9..63a3d1bca8 100644
--- a/crypto/rand/rand_lib.c
+++ b/crypto/rand/rand_lib.c
@@ -25,12 +25,6 @@
#include "internal/provider.h"
#include "internal/common.h"
-/* clang-format off */
-#ifndef OPENSSL_DEFAULT_SEED_SRC
-#define OPENSSL_DEFAULT_SEED_SRC SEED-SRC
-#endif
-/* clang-format on */
-
typedef struct rand_global_st {
/*
* The three shared DRBG instances
@@ -545,10 +539,10 @@ static EVP_RAND_CTX *rand_new_seed(OSSL_LIB_CTX *libctx)
name = dgbl->seed_name;
} else {
fallback = 1;
- name = OPENSSL_MSTR(OPENSSL_DEFAULT_SEED_SRC);
+ name = OPENSSL_SEED_SRC_NAME;
}
#else /* !OPENSSL_NO_FIPS_JITTER */
- name = "JITTER";
+ name = OPENSSL_SEED_SRC_NAME;
propq = "";
#endif /* OPENSSL_NO_FIPS_JITTER */
diff --git a/crypto/rand/rand_uniform.c b/crypto/rand/rand_uniform.c
index 877150af4e..0b7f7a3c0a 100644
--- a/crypto/rand/rand_uniform.c
+++ b/crypto/rand/rand_uniform.c
@@ -47,7 +47,7 @@ uint32_t ossl_rand_uniform_uint32(OSSL_LIB_CTX *ctx, uint32_t upper, int *err)
* We are generating a fixed point number on the interval [0, 1).
* Multiplying this by the range gives us a number on [0, upper).
* The high word of the multiplication result represents the integral
- * part we want. The lower word is the fractional part. We can early exit if
+ * part we want. The lower word is the fractional part. We can early exit
* if the fractional part is small enough that no carry from the next lower
* word can cause an overflow and carry into the integer part. This
* happens when the fractional part is bounded by 2^32 - upper which
@@ -69,7 +69,7 @@ uint32_t ossl_rand_uniform_uint32(OSSL_LIB_CTX *ctx, uint32_t upper, int *err)
* repeat the process with the next lower word.
*
* Each *bit* of randomness has a probability of one half of terminating
- * this process, so each each word beyond the first has a probability
+ * this process, so each word beyond the first has a probability
* of 2^-32 of not terminating the process. That is, we're extremely
* likely to stop very rapidly.
*/
diff --git a/crypto/rand/randfile.c b/crypto/rand/randfile.c
index ab059bb5e8..c2be28a122 100644
--- a/crypto/rand/randfile.c
+++ b/crypto/rand/randfile.c
@@ -35,8 +35,7 @@
#ifndef OPENSSL_NO_POSIX_IO
#include
#include
-#if defined(_WIN32) && !defined(_WIN32_WCE)
-#include
+#if defined(_WIN32)
#include
#define stat _stat
#define chmod _chmod
@@ -70,7 +69,8 @@
* This declaration is a nasty hack to get around vms' extension to fopen for
* passing in sharing options being disabled by /STANDARD=ANSI89
*/
-static __FILE_ptr32 (*const vms_fopen)(const char *, const char *, ...) = (__FILE_ptr32 (*)(const char *, const char *, ...))fopen;
+static __FILE_ptr32 (*const vms_fopen)(const char *, const char *, ...)
+ = (__FILE_ptr32 (*)(const char *, const char *, ...))fopen;
#define VMS_OPEN_ATTRS \
"shr=get,put,upd,del", "ctx=bin,stm", "rfm=stm", "rat=none", "mrs=0"
#define openssl_fopen(fname, mode) vms_fopen((fname), (mode), VMS_OPEN_ATTRS)
@@ -272,7 +272,7 @@ const char *RAND_file_name(char *buf, size_t size)
size_t len;
int use_randfile = 1;
-#if defined(_WIN32) && defined(CP_UTF8) && !defined(_WIN32_WCE)
+#if defined(_WIN32) && defined(CP_UTF8)
DWORD envlen;
WCHAR *var;
diff --git a/crypto/rc4/asm/rc4-md5-x86_64.pl b/crypto/rc4/asm/rc4-md5-x86_64.pl
index f814d6f86f..c4440ab32c 100644
--- a/crypto/rc4/asm/rc4-md5-x86_64.pl
+++ b/crypto/rc4/asm/rc4-md5-x86_64.pl
@@ -26,7 +26,7 @@
# and Jim Guilford of Intel. MD5 is fresh implementation aiming to
# minimize register usage, which was used as "main thread" with RC4
# weaved into it, one RC4 round per one MD5 round. In addition to the
-# stiched subroutine the script can generate standalone replacement
+# stitched subroutine the script can generate standalone replacement
# ossl_md5_block_asm_data_order and RC4. Below are performance numbers in
# cycles per processed byte, less is better, for these the standalone
# subroutines, sum of them, and stitched one:
diff --git a/crypto/rc5/rc5_local.h b/crypto/rc5/rc5_local.h
index a1fbe61fec..7b5f8c847b 100644
--- a/crypto/rc5/rc5_local.h
+++ b/crypto/rc5/rc5_local.h
@@ -19,7 +19,7 @@
#elif defined(__ICC)
#define ROTATE_l32(a, n) _rotl(a, n)
#define ROTATE_r32(a, n) _rotr(a, n)
-#elif defined(__GNUC__) && __GNUC__ >= 2 && !defined(__STRICT_ANSI__) && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM) && !defined(PEDANTIC)
+#elif defined(__GNUC__) && !defined(__STRICT_ANSI__) && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM) && !defined(PEDANTIC)
#if defined(__i386) || defined(__i386__) || defined(__x86_64) || defined(__x86_64__)
#define ROTATE_l32(a, n) ({ \
register unsigned int ret; \
diff --git a/crypto/riscvcap.c b/crypto/riscvcap.c
index cdec9a0216..760fc5b0dd 100644
--- a/crypto/riscvcap.c
+++ b/crypto/riscvcap.c
@@ -129,7 +129,7 @@ size_t riscv_vlen(void)
return vlen;
}
-#if defined(__GNUC__) && __GNUC__ >= 2
+#if defined(__GNUC__)
__attribute__((constructor))
#endif
void OPENSSL_cpuid_setup(void)
diff --git a/crypto/rsa/rsa_backend.c b/crypto/rsa/rsa_backend.c
index 00b4880c80..161d9a9c56 100644
--- a/crypto/rsa/rsa_backend.c
+++ b/crypto/rsa/rsa_backend.c
@@ -227,7 +227,7 @@ int ossl_rsa_fromdata(RSA *rsa, const OSSL_PARAM params[], int include_private)
if (!ossl_rsa_check_factors(rsa)) {
ERR_raise_data(ERR_LIB_RSA, RSA_R_INVALID_KEYPAIR,
- "RSA factors/exponents are too big for for n-modulus\n");
+ "RSA factors/exponents are too big for n-modulus\n");
goto err;
}
@@ -532,7 +532,8 @@ RSA *ossl_rsa_dup(const RSA *rsa, int selection)
}
if (rsa->pss != NULL) {
- dupkey->pss = RSA_PSS_PARAMS_dup(rsa->pss);
+ if ((dupkey->pss = RSA_PSS_PARAMS_dup(rsa->pss)) == NULL)
+ goto err;
if (rsa->pss->maskGenAlgorithm != NULL
&& dupkey->pss->maskGenAlgorithm == NULL) {
dupkey->pss->maskHash = ossl_x509_algor_mgf1_decode(rsa->pss->maskGenAlgorithm);
diff --git a/crypto/rsa/rsa_lib.c b/crypto/rsa/rsa_lib.c
index a7d5798c88..88a7a2b93f 100644
--- a/crypto/rsa/rsa_lib.c
+++ b/crypto/rsa/rsa_lib.c
@@ -163,7 +163,7 @@ int RSA_up_ref(RSA *r)
{
int i;
- if (CRYPTO_UP_REF(&r->references, &i) <= 0)
+ if (!CRYPTO_UP_REF(&r->references, &i))
return 0;
REF_PRINT_COUNT("RSA", i, r);
diff --git a/crypto/rsa/rsa_ossl.c b/crypto/rsa/rsa_ossl.c
index b883baa58f..674ee4b10d 100644
--- a/crypto/rsa/rsa_ossl.c
+++ b/crypto/rsa/rsa_ossl.c
@@ -1184,9 +1184,12 @@ static int rsa_ossl_finish(RSA *rsa)
static int rsa_ossl_s390x_mod_exp(BIGNUM *r0, const BIGNUM *i, RSA *rsa,
BN_CTX *ctx)
{
+ int rc;
+
if (rsa->version != RSA_ASN1_VERSION_MULTI) {
- if (s390x_crt(r0, i, rsa->p, rsa->q, rsa->dmp1, rsa->dmq1, rsa->iqmp) == 1)
- return 1;
+ rc = s390x_crt(r0, i, rsa->p, rsa->q, rsa->dmp1, rsa->dmq1, rsa->iqmp);
+ if (rc >= 0)
+ return rc;
}
return rsa_ossl_mod_exp(r0, i, rsa, ctx);
}
diff --git a/crypto/sha/asm/keccak1600-avx512.pl b/crypto/sha/asm/keccak1600-avx512.pl
index 2a295d1c85..1b40130a6e 100755
--- a/crypto/sha/asm/keccak1600-avx512.pl
+++ b/crypto/sha/asm/keccak1600-avx512.pl
@@ -22,7 +22,7 @@
# It's impossible to have one that is optimal for every step, hence
# it's changing as algorithm progresses. Data is saved in linear order,
# but in-register order morphs between rounds. Even rounds take in
-# linear layout, and odd rounds - transposed, or "verticaly-shaped"...
+# linear layout, and odd rounds - transposed, or "vertically-shaped"...
#
########################################################################
# Numbers are cycles per processed byte out of large message.
diff --git a/crypto/sha/asm/keccak1600x4-avx512vl.pl b/crypto/sha/asm/keccak1600x4-avx512vl.pl
new file mode 100755
index 0000000000..a7fc1814f5
--- /dev/null
+++ b/crypto/sha/asm/keccak1600x4-avx512vl.pl
@@ -0,0 +1,2349 @@
+#!/usr/bin/env perl
+#
+# Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
+# Copyright (c) 2026 Intel Corporation. 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
+
+###############################################################################
+# Keccak x4 AVX512VL SHA3/SHAKE Assembly Routines
+#
+# Description:
+# This file emits x86_64 assembly for AVX512VL accelerated Keccak-f[1600]
+# processing of 4 independent states in parallel ("x4").
+#
+# It provides the core 24-round Keccak permutation and x4 helper routines
+# used by SHA3 and SHAKE absorb/finalize/squeeze paths. Data from four
+# input/output lanes is packed across YMM registers so lane-local operations
+# execute in SIMD.
+#
+###############################################################################
+
+# $output is the last argument if it looks like a file (it has an extension)
+# $flavour is the first argument if it doesn't look like a file
+$output = $#ARGV >= 0 && $ARGV[$#ARGV] =~ m|\.\w+$| ? pop : undef;
+$flavour = $#ARGV >= 0 && $ARGV[0] !~ m|\.| ? shift : undef;
+
+$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
+
+$avx512vl = 0;
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
+( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
+die "can't locate x86_64-xlate.pl";
+
+# Check for AVX512VL support in assembler
+if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` =~ /GNU assembler version (\d+)\.(\d+)/) {
+ my ($gas_major, $gas_minor) = ($1, $2);
+ $avx512vl = ($gas_major > 2 || ($gas_major == 2 && $gas_minor >= 26));
+}
+
+if (!$avx512vl
+ && $win64
+ && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/)
+ && `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)(?:\.([0-9]+))?/)
+{
+ $avx512vl = ($1 >= 2.12);
+}
+
+if (!$avx512vl && `$ENV{CC} -v 2>&1` =~ /((?:clang|LLVM) version|.*based on LLVM) ([0-9]+\.[0-9]+)/) {
+ $avx512vl = ($2>=3.9);
+}
+
+open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\""
+ or die "can't call $xlate: $!";
+*STDOUT=*OUT;
+
+$arg1="%rdi";
+$arg2="%rsi";
+$arg3="%rdx";
+$arg4="%rcx";
+$arg5="%r8";
+$arg6="%r9";
+$roundn="%r13d";
+$tblptr="%r14";
+
+# Define SHAKE rates
+$SHAKE128_RATE="\$168";
+$SHAKE256_RATE="\$136";
+
+# Stack frame offsets for SHAKE x4 wrapper functions
+$STATE_SIZE="808"; # (25 * 8 * 4) + 8 = 808 bytes
+$sf_arg1="0";
+$sf_arg2="8";
+$sf_arg3="16";
+$sf_arg4="24";
+$sf_arg5="32";
+$sf_state_ptr="40";
+$sf_state_x4="48";
+$sf_size="856"; # 48 + 808 = 856 bytes
+
+# Emit an internal helper call used by one-shot wrappers.
+# - Win64: call the provided *_internal shim and bracket it with 32-byte
+# shadow space so shim entry can use xlate-compatible [rsp+8]/[rsp+16].
+# - non-Win64: call the local function entry label (.L_), which
+# sits at the same address as the public symbol. Calling the public
+# global symbol by name here would break Mach-O builds: the call textually
+# precedes the symbol's .globl declaration, so x86_64-xlate.pl never gets
+# a chance to prepend the platform's leading-underscore, leaving an
+# undefined reference to the un-decorated name.
+# The argument must be the shim/internal symbol name, e.g.
+# SHA3_shake128_x4_inc_squeeze_avx512vl_internal
+sub call_internal {
+ my ($shim_name) = @_;
+ my $external_name = $shim_name;
+
+ $external_name =~ s/_internal$//;
+
+ return <<___ if ($win64);
+ sub \$32, %rsp
+ call $shim_name
+ add \$32, %rsp
+___
+
+ return <<___;
+ call .L_$external_name
+___
+}
+
+if ($avx512vl>0) {{{
+
+my $avx512_mask = (1<<31)|(1<<30)|(1<<17)|(1<<16); # AVX512VL|BW|DQ|F
+
+$code .= <<___;
+.text
+
+.extern OPENSSL_ia32cap_P
+
+.globl SHA3_avx512vl_capable
+.type SHA3_avx512vl_capable,\@abi-omnipotent
+.align 32
+SHA3_avx512vl_capable:
+ mov OPENSSL_ia32cap_P+8(%rip), %ecx
+ xor %eax, %eax
+ # 1<<31|1<<30|1<<17|1<<16: AVX512VL|AVX512BW|AVX512DQ|AVX512F
+ and \$$avx512_mask, %ecx
+ cmp \$$avx512_mask, %ecx
+ cmove %ecx, %eax
+ ret
+.size SHA3_avx512vl_capable, .-SHA3_avx512vl_capable
+___
+
+$code.=<<___;
+.text
+
+# Perform Keccak permutation
+#
+# YMM registers 0 to 24 are used as Keccak state registers.
+# This function, as is, can work on 1 to 4 independent states at the same time.
+#
+# There is no clear boundary between Theta, Rho, Pi, Chi and Iota steps.
+# Instructions corresponding to these steps overlap for better efficiency.
+#
+# Arguments:
+# ymm0-ymm24 [in/out] Keccak state registers (one SIMD per one state register)
+# ymm25-ymm31 [clobbered] temporary SIMD registers
+# $roundn [clobbered] used for round tracking
+# $tblptr [clobbered] used for access to SHA3 constant table
+.type keccak_1600_permute,\@abi-omnipotent
+.align 32
+keccak_1600_permute:
+.cfi_startproc
+ mov \$24, $roundn # 24 rounds
+ lea iotas(%rip), $tblptr # Load the address of the SHA3 round constants
+
+.align 32
+.Lkeccak_rnd_loop:
+ # Theta step
+
+ # Compute column parities
+ # C[5] = [0, 0, 0, 0, 0]
+ # for x in 0 to 4:
+ # C[x] = state[x][0] XOR state[x][1] XOR state[x][2] XOR state[x][3] XOR state[x][4]
+
+ vmovdqa64 %ymm0, %ymm25
+ vpternlogq \$0x96, %ymm5, %ymm10, %ymm25
+ vmovdqa64 %ymm1, %ymm26
+ vpternlogq \$0x96, %ymm11, %ymm6, %ymm26
+ vmovdqa64 %ymm2, %ymm27
+ vpternlogq \$0x96, %ymm12, %ymm7, %ymm27
+
+ vmovdqa64 %ymm3, %ymm28
+ vpternlogq \$0x96, %ymm13, %ymm8, %ymm28
+ vmovdqa64 %ymm4, %ymm29
+ vpternlogq \$0x96, %ymm14, %ymm9, %ymm29
+ vpternlogq \$0x96, %ymm20, %ymm15, %ymm25
+
+ vpternlogq \$0x96, %ymm21, %ymm16, %ymm26
+ vpternlogq \$0x96, %ymm22, %ymm17, %ymm27
+ vpternlogq \$0x96, %ymm23, %ymm18, %ymm28
+
+ # Start computing D values and keep computing column parity
+ # D[5] = [0, 0, 0, 0, 0]
+ # for x in 0 to 4:
+ # D[x] = C[(x+4) mod 5] XOR ROTATE_LEFT(C[(x+1) mod 5], 1)
+
+ vprolq \$1, %ymm26, %ymm30
+ vprolq \$1, %ymm27, %ymm31
+ vpternlogq \$0x96, %ymm24, %ymm19, %ymm29
+
+ # Continue computing D values and apply Theta
+ # for x in 0 to 4:
+ # for y in 0 to 4:
+ # state[x][y] = state[x][y] XOR D[x]
+
+ vpternlogq \$0x96, %ymm30, %ymm29, %ymm0
+ vpternlogq \$0x96, %ymm30, %ymm29, %ymm10
+ vpternlogq \$0x96, %ymm30, %ymm29, %ymm20
+
+ vpternlogq \$0x96, %ymm30, %ymm29, %ymm5
+ vpternlogq \$0x96, %ymm30, %ymm29, %ymm15
+ vprolq \$1, %ymm28, %ymm30
+
+ vpternlogq \$0x96, %ymm31, %ymm25, %ymm6
+ vpternlogq \$0x96, %ymm31, %ymm25, %ymm16
+ vpternlogq \$0x96, %ymm31, %ymm25, %ymm1
+
+ vpternlogq \$0x96, %ymm31, %ymm25, %ymm11
+ vpternlogq \$0x96, %ymm31, %ymm25, %ymm21
+ vprolq \$1, %ymm29, %ymm31
+
+ vpbroadcastq ($tblptr), %ymm29 # Load the round constant into ymm29 (Iota)
+ add \$8, $tblptr # Increment the pointer to the next round constant
+
+ vpternlogq \$0x96, %ymm30, %ymm26, %ymm12
+ vpternlogq \$0x96, %ymm30, %ymm26, %ymm7
+ vpternlogq \$0x96, %ymm30, %ymm26, %ymm22
+
+ vpternlogq \$0x96, %ymm30, %ymm26, %ymm17
+ vpternlogq \$0x96, %ymm30, %ymm26, %ymm2
+ vprolq \$1, %ymm25, %ymm30
+
+ # Rho step
+ # Keep applying Theta and start Rho step
+ #
+ # ROTATION_OFFSETS[5][5] = [
+ # [0, 1, 62, 28, 27],
+ # [36, 44, 6, 55, 20],
+ # [3, 10, 43, 25, 39],
+ # [41, 45, 15, 21, 8],
+ # [18, 2, 61, 56, 14] ]
+ #
+ # for x in 0 to 4:
+ # for y in 0 to 4:
+ # state[x][y] = ROTATE_LEFT(state[x][y], ROTATION_OFFSETS[x][y])
+
+ vpternlogq \$0x96, %ymm31, %ymm27, %ymm3
+ vpternlogq \$0x96, %ymm31, %ymm27, %ymm13
+ vpternlogq \$0x96, %ymm31, %ymm27, %ymm23
+
+ vprolq \$44, %ymm6, %ymm6
+ vpternlogq \$0x96, %ymm31, %ymm27, %ymm18
+ vpternlogq \$0x96, %ymm31, %ymm27, %ymm8
+
+ vprolq \$43, %ymm12, %ymm12
+ vprolq \$21, %ymm18, %ymm18
+ vpternlogq \$0x96, %ymm30, %ymm28, %ymm24
+
+ vprolq \$14, %ymm24, %ymm24
+ vprolq \$28, %ymm3, %ymm3
+ vpternlogq \$0x96, %ymm30, %ymm28, %ymm9
+
+ vprolq \$20, %ymm9, %ymm9
+ vprolq \$3, %ymm10, %ymm10
+ vpternlogq \$0x96, %ymm30, %ymm28, %ymm19
+
+ vprolq \$45, %ymm16, %ymm16
+ vprolq \$61, %ymm22, %ymm22
+ vpternlogq \$0x96, %ymm30, %ymm28, %ymm4
+
+ vprolq \$1, %ymm1, %ymm1
+ vprolq \$6, %ymm7, %ymm7
+ vpternlogq \$0x96, %ymm30, %ymm28, %ymm14
+
+ # Continue with Rho and start Pi and Chi steps at the same time
+ # Ternary logic 0xD2 is used for Chi step
+ #
+ # for x in 0 to 4:
+ # for y in 0 to 4:
+ # state[x][y] = state[x][y] XOR ((NOT state[(x+1) mod 5][y]) AND state[(x+2) mod 5][y])
+
+ vprolq \$25, %ymm13, %ymm13
+ vprolq \$8, %ymm19, %ymm19
+ vmovdqa64 %ymm0, %ymm30
+ vpternlogq \$0xD2, %ymm12, %ymm6, %ymm30
+
+ vprolq \$18, %ymm20, %ymm20
+ vprolq \$27, %ymm4, %ymm4
+ vpxorq %ymm29, %ymm30, %ymm30 # Iota step
+
+ vprolq \$36, %ymm5, %ymm5
+ vprolq \$10, %ymm11, %ymm11
+ vmovdqa64 %ymm6, %ymm31
+ vpternlogq \$0xD2, %ymm18, %ymm12, %ymm31
+
+ vprolq \$15, %ymm17, %ymm17
+ vprolq \$56, %ymm23, %ymm23
+ vpternlogq \$0xD2, %ymm24, %ymm18, %ymm12
+
+ vprolq \$62, %ymm2, %ymm2
+ vprolq \$55, %ymm8, %ymm8
+ vpternlogq \$0xD2, %ymm0, %ymm24, %ymm18
+
+ vprolq \$39, %ymm14, %ymm14
+ vprolq \$41, %ymm15, %ymm15
+ vpternlogq \$0xD2, %ymm6, %ymm0, %ymm24
+ vmovdqa64 %ymm30, %ymm0
+ vmovdqa64 %ymm31, %ymm6
+
+ vprolq \$2, %ymm21, %ymm21
+ vmovdqa64 %ymm3, %ymm30
+ vpternlogq \$0xD2, %ymm10, %ymm9, %ymm30
+ vmovdqa64 %ymm9, %ymm31
+ vpternlogq \$0xD2, %ymm16, %ymm10, %ymm31
+
+ vpternlogq \$0xD2, %ymm22, %ymm16, %ymm10
+ vpternlogq \$0xD2, %ymm3, %ymm22, %ymm16
+ vpternlogq \$0xD2, %ymm9, %ymm3, %ymm22
+ vmovdqa64 %ymm30, %ymm3
+ vmovdqa64 %ymm31, %ymm9
+
+ vmovdqa64 %ymm1, %ymm30
+ vpternlogq \$0xD2, %ymm13, %ymm7, %ymm30
+ vmovdqa64 %ymm7, %ymm31
+ vpternlogq \$0xD2, %ymm19, %ymm13, %ymm31
+ vpternlogq \$0xD2, %ymm20, %ymm19, %ymm13
+
+ vpternlogq \$0xD2, %ymm1, %ymm20, %ymm19
+ vpternlogq \$0xD2, %ymm7, %ymm1, %ymm20
+ vmovdqa64 %ymm30, %ymm1
+ vmovdqa64 %ymm31, %ymm7
+ vmovdqa64 %ymm4, %ymm30
+ vpternlogq \$0xD2, %ymm11, %ymm5, %ymm30
+
+ vmovdqa64 %ymm5, %ymm31
+ vpternlogq \$0xD2, %ymm17, %ymm11, %ymm31
+ vpternlogq \$0xD2, %ymm23, %ymm17, %ymm11
+ vpternlogq \$0xD2, %ymm4, %ymm23, %ymm17
+
+ vpternlogq \$0xD2, %ymm5, %ymm4, %ymm23
+ vmovdqa64 %ymm30, %ymm4
+ vmovdqa64 %ymm31, %ymm5
+ vmovdqa64 %ymm2, %ymm30
+ vpternlogq \$0xD2, %ymm14, %ymm8, %ymm30
+ vmovdqa64 %ymm8, %ymm31
+ vpternlogq \$0xD2, %ymm15, %ymm14, %ymm31
+
+ vpternlogq \$0xD2, %ymm21, %ymm15, %ymm14
+ vpternlogq \$0xD2, %ymm2, %ymm21, %ymm15
+ vpternlogq \$0xD2, %ymm8, %ymm2, %ymm21
+ vmovdqa64 %ymm30, %ymm2
+ vmovdqa64 %ymm31, %ymm8
+
+ # Complete the steps and get updated state registers in ymm0 to ymm24
+ vmovdqa64 %ymm3, %ymm30
+ vmovdqa64 %ymm18, %ymm3
+ vmovdqa64 %ymm17, %ymm18
+ vmovdqa64 %ymm11, %ymm17
+ vmovdqa64 %ymm7, %ymm11
+ vmovdqa64 %ymm10, %ymm7
+ vmovdqa64 %ymm1, %ymm10
+ vmovdqa64 %ymm6, %ymm1
+ vmovdqa64 %ymm9, %ymm6
+ vmovdqa64 %ymm22, %ymm9
+ vmovdqa64 %ymm14, %ymm22
+ vmovdqa64 %ymm20, %ymm14
+ vmovdqa64 %ymm2, %ymm20
+ vmovdqa64 %ymm12, %ymm2
+ vmovdqa64 %ymm13, %ymm12
+ vmovdqa64 %ymm19, %ymm13
+ vmovdqa64 %ymm23, %ymm19
+ vmovdqa64 %ymm15, %ymm23
+ vmovdqa64 %ymm4, %ymm15
+ vmovdqa64 %ymm24, %ymm4
+ vmovdqa64 %ymm21, %ymm24
+ vmovdqa64 %ymm8, %ymm21
+ vmovdqa64 %ymm16, %ymm8
+ vmovdqa64 %ymm5, %ymm16
+ vmovdqa64 %ymm30, %ymm5
+
+ dec $roundn # Decrement the round counter
+ jnz .Lkeccak_rnd_loop # Jump to the start of the loop if r13d is not zero
+ ret
+.cfi_endproc
+.size keccak_1600_permute,.-keccak_1600_permute
+
+# Initialize YMM registers 0-24 to zero
+.globl keccak_1600_init_state
+.type keccak_1600_init_state,\@abi-omnipotent
+.align 32
+keccak_1600_init_state:
+.cfi_startproc
+ vpxorq %ymm0, %ymm0, %ymm0
+ vmovdqa64 %ymm0, %ymm1
+ vmovdqa64 %ymm0, %ymm2
+ vmovdqa64 %ymm0, %ymm3
+ vmovdqa64 %ymm0, %ymm4
+ vmovdqa64 %ymm0, %ymm5
+ vmovdqa64 %ymm0, %ymm6
+ vmovdqa64 %ymm0, %ymm7
+ vmovdqa64 %ymm0, %ymm8
+ vmovdqa64 %ymm0, %ymm9
+ vmovdqa64 %ymm0, %ymm10
+ vmovdqa64 %ymm0, %ymm11
+ vmovdqa64 %ymm0, %ymm12
+ vmovdqa64 %ymm0, %ymm13
+ vmovdqa64 %ymm0, %ymm14
+ vmovdqa64 %ymm0, %ymm15
+ vmovdqa64 %ymm0, %ymm16
+ vmovdqa64 %ymm0, %ymm17
+ vmovdqa64 %ymm0, %ymm18
+ vmovdqa64 %ymm0, %ymm19
+ vmovdqa64 %ymm0, %ymm20
+ vmovdqa64 %ymm0, %ymm21
+ vmovdqa64 %ymm0, %ymm22
+ vmovdqa64 %ymm0, %ymm23
+ vmovdqa64 %ymm0, %ymm24
+ ret
+.cfi_endproc
+.size keccak_1600_init_state,.-keccak_1600_init_state
+
+.globl keccak_1600_load_state_x4
+.type keccak_1600_load_state_x4,\@abi-omnipotent
+.align 32
+keccak_1600_load_state_x4:
+.cfi_startproc
+ vmovdqu64 32*0($arg1), %ymm0
+ vmovdqu64 32*1($arg1), %ymm1
+ vmovdqu64 32*2($arg1), %ymm2
+ vmovdqu64 32*3($arg1), %ymm3
+ vmovdqu64 32*4($arg1), %ymm4
+ vmovdqu64 32*5($arg1), %ymm5
+ vmovdqu64 32*6($arg1), %ymm6
+ vmovdqu64 32*7($arg1), %ymm7
+ vmovdqu64 32*8($arg1), %ymm8
+ vmovdqu64 32*9($arg1), %ymm9
+ vmovdqu64 32*10($arg1), %ymm10
+ vmovdqu64 32*11($arg1), %ymm11
+ vmovdqu64 32*12($arg1), %ymm12
+ vmovdqu64 32*13($arg1), %ymm13
+ vmovdqu64 32*14($arg1), %ymm14
+ vmovdqu64 32*15($arg1), %ymm15
+ vmovdqu64 32*16($arg1), %ymm16
+ vmovdqu64 32*17($arg1), %ymm17
+ vmovdqu64 32*18($arg1), %ymm18
+ vmovdqu64 32*19($arg1), %ymm19
+ vmovdqu64 32*20($arg1), %ymm20
+ vmovdqu64 32*21($arg1), %ymm21
+ vmovdqu64 32*22($arg1), %ymm22
+ vmovdqu64 32*23($arg1), %ymm23
+ vmovdqu64 32*24($arg1), %ymm24
+ ret
+.cfi_endproc
+.size keccak_1600_load_state_x4,.-keccak_1600_load_state_x4
+
+
+.globl keccak_1600_save_state_x4
+.type keccak_1600_save_state_x4,\@abi-omnipotent
+.align 32
+keccak_1600_save_state_x4:
+.cfi_startproc
+ vmovdqu64 %ymm0, 32*0($arg1)
+ vmovdqu64 %ymm1, 32*1($arg1)
+ vmovdqu64 %ymm2, 32*2($arg1)
+ vmovdqu64 %ymm3, 32*3($arg1)
+ vmovdqu64 %ymm4, 32*4($arg1)
+ vmovdqu64 %ymm5, 32*5($arg1)
+ vmovdqu64 %ymm6, 32*6($arg1)
+ vmovdqu64 %ymm7, 32*7($arg1)
+ vmovdqu64 %ymm8, 32*8($arg1)
+ vmovdqu64 %ymm9, 32*9($arg1)
+ vmovdqu64 %ymm10, 32*10($arg1)
+ vmovdqu64 %ymm11, 32*11($arg1)
+ vmovdqu64 %ymm12, 32*12($arg1)
+ vmovdqu64 %ymm13, 32*13($arg1)
+ vmovdqu64 %ymm14, 32*14($arg1)
+ vmovdqu64 %ymm15, 32*15($arg1)
+ vmovdqu64 %ymm16, 32*16($arg1)
+ vmovdqu64 %ymm17, 32*17($arg1)
+ vmovdqu64 %ymm18, 32*18($arg1)
+ vmovdqu64 %ymm19, 32*19($arg1)
+ vmovdqu64 %ymm20, 32*20($arg1)
+ vmovdqu64 %ymm21, 32*21($arg1)
+ vmovdqu64 %ymm22, 32*22($arg1)
+ vmovdqu64 %ymm23, 32*23($arg1)
+ vmovdqu64 %ymm24, 32*24($arg1)
+ ret
+.cfi_endproc
+.size keccak_1600_save_state_x4,.-keccak_1600_save_state_x4
+
+
+# Add input data to state when message length is less than rate
+# Arguments:
+# r10: state pointer to absorb into (clobbered)
+# arg2 (rsi): message pointer lane 0 (updated on output)
+# arg3 (rdx): message pointer lane 1 (updated on output)
+# arg4 (rcx): message pointer lane 2 (updated on output)
+# arg5 (r8): message pointer lane 3 (updated on output)
+# r12: length in bytes (clobbered on output)
+# Clobbers: r9, rbx, r15, k1, ymm31-ymm29
+.globl keccak_1600_partial_add_x4
+.type keccak_1600_partial_add_x4,\@abi-omnipotent
+.align 32
+keccak_1600_partial_add_x4:
+.cfi_startproc
+ mov 8*100(%r10), %r9
+ test \$7, %r9d
+ jz .Lstart_aligned_to_4x8
+
+ # Start offset is not aligned to register size
+ mov %r9, %r15 # %r15 = s[100]
+
+ and \$7, %r9d
+ neg %r9d
+ add \$8, %r9d # register capacity = 8 - (offset % 8)
+ cmp %r9d, %r12d
+ cmovnae %r12d, %r9d # %r9d = min(register capacity, length)
+
+ lea byte_kmask_0_to_7(%rip), %rbx
+ kmovb (%rbx,%r9), %k1 # message load mask
+
+ mov %r15, %rbx
+ and \$~7, %ebx
+ lea (%r10,%rbx,4), %r10 # get to state starting register
+
+ mov %r15, %rbx
+ and \$7, %ebx
+
+ vmovdqu8 (%r10), %ymm31 # load & store / allocate SB for the register
+ vmovdqu8 %ymm31, (%r10)
+
+ vmovdqu8 ($arg2), %xmm31{%k1}{z} # Read 1 to 7 bytes from lane 0
+ vmovdqu8 8*0(%r10,%rbx), %xmm30{%k1}{z} # Read 1 to 7 bytes from state reg lane 0
+ vpxorq %xmm30, %xmm31, %xmm31
+ vmovdqu8 %xmm31, 8*0(%r10,%rbx){%k1} # Write 1 to 7 bytes to state reg lane 0
+
+ vmovdqu8 ($arg3), %xmm31{%k1}{z} # Read 1 to 7 bytes from lane 1
+ vmovdqu8 8*1(%r10,%rbx), %xmm30{%k1}{z} # Read 1 to 7 bytes from state reg lane 1
+ vpxorq %xmm30, %xmm31, %xmm31
+ vmovdqu8 %xmm31, 8*1(%r10,%rbx){%k1} # Write 1 to 7 bytes to state reg lane 1
+
+ vmovdqu8 ($arg4), %xmm31{%k1}{z} # Read 1 to 7 bytes from lane 2
+ vmovdqu8 8*2(%r10,%rbx), %xmm30{%k1}{z} # Read 1 to 7 bytes from state reg lane 2
+ vpxorq %xmm30, %xmm31, %xmm31
+ vmovdqu8 %xmm31, 8*2(%r10,%rbx){%k1} # Write 1 to 7 bytes to state reg lane 2
+
+ vmovdqu8 ($arg5), %xmm31{%k1}{z} # Read 1 to 7 bytes from lane 3
+ vmovdqu8 8*3(%r10,%rbx), %xmm30{%k1}{z} # Read 1 to 7 bytes from state reg lane 3
+ vpxorq %xmm30, %xmm31, %xmm31
+ vmovdqu8 %xmm31, 8*3(%r10,%rbx){%k1} # Write 1 to 7 bytes to state reg lane 3
+
+ sub %r9, %r12
+ jz .Lzero_bytes
+
+ add %r9, $arg2
+ add %r9, $arg3
+ add %r9, $arg4
+ add %r9, $arg5
+ add \$32, %r10
+ xor %r9, %r9
+ jmp .Lymm_loop
+
+.Lstart_aligned_to_4x8:
+ lea (%r10,%r9,4), %r10
+ xor %r9, %r9
+
+.align 32
+.Lymm_loop:
+ cmp \$8, %r12d
+ jb .Llt_8_bytes
+
+ vmovq ($arg2,%r9), %xmm31 # Read 8 bytes from lane 0
+ vpinsrq \$1, ($arg3,%r9), %xmm31, %xmm31 # Read 8 bytes from lane 1
+ vmovq ($arg4,%r9), %xmm30 # Read 8 bytes from lane 2
+ vpinsrq \$1, ($arg5,%r9),%xmm30, %xmm30 # Read 8 bytes from lane 3
+ vinserti32x4 \$1, %xmm30, %ymm31, %ymm31
+ vpxorq (%r10,%r9,4), %ymm31, %ymm31 # Add data with the state
+ vmovdqu64 %ymm31, (%r10,%r9,4)
+ add \$8, %r9
+ sub \$8, %r12
+ jz .Lzero_bytes
+
+ jmp .Lymm_loop
+
+.align 32
+.Lzero_bytes:
+ add %r9, $arg2
+ add %r9, $arg3
+ add %r9, $arg4
+ add %r9, $arg5
+ ret
+
+.align 32
+.Llt_8_bytes:
+ add %r9, $arg2
+ add %r9, $arg3
+ add %r9, $arg4
+ add %r9, $arg5
+ lea (%r10,%r9,4), %r10
+
+ lea byte_kmask_0_to_7(%rip), %rbx
+ kmovb (%rbx,%r12), %k1 # message load mask
+
+ vmovdqu8 ($arg2), %xmm31{%k1}{z} # Read 1 to 7 bytes from lane 0
+ vmovdqu8 ($arg3), %xmm30{%k1}{z} # Read 1 to 7 bytes from lane 1
+ vpunpcklqdq %xmm30, %xmm31, %xmm31 # Interleave data from lane 0 and lane 1
+ vmovdqu8 ($arg4), %xmm30{%k1}{z} # Read 1 to 7 bytes from lane 2
+ vmovdqu8 ($arg5), %xmm29{%k1}{z} # Read 1 to 7 bytes from lane 3
+ vpunpcklqdq %xmm29, %xmm30, %xmm30 # Interleave data from lane 2 and lane 3
+ vinserti32x4 \$1, %xmm30, %ymm31, %ymm31
+
+ vpxorq (%r10), %ymm31, %ymm31 # Add data to the state
+ vmovdqu64 %ymm31, (%r10) # Update state in memory
+
+ add %r12, $arg2 # increment message pointer lane 0
+ add %r12, $arg3 # increment message pointer lane 1
+ add %r12, $arg4 # increment message pointer lane 2
+ add %r12, $arg5 # increment message pointer lane 3
+ ret
+.cfi_endproc
+.size keccak_1600_partial_add_x4,.-keccak_1600_partial_add_x4
+
+
+# Extract bytes from state and write to outputs
+# Arguments:
+# r10: state pointer to start extracting from (clobbered)
+# arg1 (rdi): output pointer lane 0 (updated on output)
+# arg2 (rsi): output pointer lane 1 (updated on output)
+# arg3 (rdx): output pointer lane 2 (updated on output)
+# arg4 (rcx): output pointer lane 3 (updated on output)
+# r12: length in bytes (clobbered on output)
+# r11: state offset to start extract from
+.globl keccak_1600_extract_bytes_x4
+.type keccak_1600_extract_bytes_x4,\@abi-omnipotent
+.align 32
+keccak_1600_extract_bytes_x4:
+.cfi_startproc
+ or %r12, %r12
+ jz .Lextract_zero_bytes
+
+ test \$7, %r11d
+ jz .Lextract_start_aligned_to_4x8
+
+ # Extract offset is not aligned to the register size (8 bytes)
+ mov %r11, %r9
+
+ and \$7, %r9d
+ neg %r9d
+ add \$8, %r9d # register capacity = 8 - (offset % 8)
+ cmp %r9d, %r12d
+ cmovnae %r12d, %r9d # %r9d = min(register capacity, length)
+
+ lea byte_kmask_0_to_7(%rip), %rbx
+ kmovb (%rbx,%r9), %k1 # message store mask
+
+ mov %r11, %rbx
+ and \$~7, %ebx
+ lea (%r10,%rbx,4), %r10 # get to state starting register
+
+ mov %r11, %rbx
+ and \$7, %ebx
+
+ vmovdqu8 8*0(%r10,%rbx), %xmm31{%k1}{z} # Read 1-7 bytes from state reg lane 0
+ vmovdqu8 %xmm31, ($arg1){%k1} # Write 1-7 bytes to lane 0 output
+
+ vmovdqu8 8*1(%r10,%rbx), %xmm31{%k1}{z} # Read 1-7 bytes from state reg lane 1
+ vmovdqu8 %xmm31, ($arg2){%k1} # Write 1-7 bytes to lane 1 output
+
+ vmovdqu8 8*2(%r10,%rbx), %xmm31{%k1}{z} # Read 1-7 bytes from state reg lane 2
+ vmovdqu8 %xmm31, ($arg3){%k1} # Write 1-7 bytes to lane 2 output
+
+ vmovdqu8 8*3(%r10,%rbx), %xmm31{%k1}{z} # Read 1-7 bytes from state reg lane 3
+ vmovdqu8 %xmm31, ($arg4){%k1} # Write 1-7 bytes to lane 3 output
+
+ # Increment output registers
+ add %r9, $arg1
+ add %r9, $arg2
+ add %r9, $arg3
+ add %r9, $arg4
+
+ # Decrement length to extract
+ sub %r9, %r12
+ jz .Lextract_zero_bytes
+
+ # More data to extract, update state register pointer
+ add \$32, %r10
+ xor %r9, %r9
+ jmp .Lextract_ymm_loop
+
+.Lextract_start_aligned_to_4x8:
+ lea (%r10,%r11,4), %r10
+ xor %r9, %r9
+
+.align 32
+.Lextract_ymm_loop:
+ cmp \$8, %r12
+ jb .Lextract_lt_8_bytes
+
+ vmovdqu64 (%r10), %xmm31
+ vmovdqu64 16(%r10), %xmm30
+ vmovq %xmm31, ($arg1,%r9)
+ vpextrq \$1, %xmm31, ($arg2,%r9)
+ vmovq %xmm30, ($arg3,%r9)
+ vpextrq \$1, %xmm30, ($arg4,%r9)
+ add \$8, %r9
+ sub \$8, %r12
+ jz .Lzero_bytes_left
+
+ add \$32, %r10
+ jmp .Lextract_ymm_loop
+
+.align 32
+.Lzero_bytes_left:
+ # Increment output pointers
+ add %r9, $arg1
+ add %r9, $arg2
+ add %r9, $arg3
+ add %r9, $arg4
+.Lextract_zero_bytes:
+ ret
+
+.align 32
+.Lextract_lt_8_bytes:
+ add %r9, $arg1
+ add %r9, $arg2
+ add %r9, $arg3
+ add %r9, $arg4
+
+ lea byte_kmask_0_to_7(%rip), %r9
+ kmovb (%r9,%r12), %k1 # k1 is the mask of message bytes to read
+
+ vmovq 0*8(%r10), %xmm31 # Read 8 bytes from state lane 0
+ vmovdqu8 %xmm31, ($arg1){%k1} # Extract 1-7 bytes into output 0
+ vmovq 1*8(%r10), %xmm31 # Read 8 bytes from state lane 1
+ vmovdqu8 %xmm31, ($arg2){%k1} # Extract 1-7 bytes into output 1
+ vmovq 2*8(%r10), %xmm31 # Read 8 bytes from state lane 2
+ vmovdqu8 %xmm31, ($arg3){%k1} # Extract 1-7 bytes into output 2
+ vmovq 3*8(%r10), %xmm31 # Read 8 bytes from state lane 3
+ vmovdqu8 %xmm31, ($arg4){%k1} # Extract 1-7 bytes into output 3
+
+ # Increment output pointers
+ add %r12, $arg1
+ add %r12, $arg2
+ add %r12, $arg3
+ add %r12, $arg4
+ ret
+.cfi_endproc
+.size keccak_1600_extract_bytes_x4,.-keccak_1600_extract_bytes_x4
+
+
+# SHAKE128 x4 multi-buffer functions
+# These functions process 4 independent SHAKE128 streams in parallel using AVX-512VL
+# State layout: 25 ymm registers (200 bytes each) + 1 qword = 808 bytes per context
+# Rate: 168 bytes for SHAKE128
+
+# SHA3_shake128_x4_avx512vl
+# One-shot SHAKE-128 x4 function: init + absorb + finalize + squeeze
+# Arguments:
+# arg1 (rdi): pointer to output lane 0
+# arg2 (rsi): pointer to output lane 1
+# arg3 (rdx): pointer to output lane 2
+# arg4 (rcx): pointer to output lane 3
+# arg5 (r8): output length in bytes (must be same for all lanes)
+# arg6 (r9): pointer to input lane 0
+# [stack+0]: pointer to input lane 1
+# [stack+8]: pointer to input lane 2
+# [stack+16]: pointer to input lane 3
+# [stack+24]: input length in bytes (must be same for all lanes)
+# Returns: void
+.globl SHA3_shake128_x4_avx512vl
+.type SHA3_shake128_x4_avx512vl,\@function,10
+.align 32
+SHA3_shake128_x4_avx512vl:
+.cfi_startproc
+ push %rbp
+.cfi_push %rbp
+ mov %rsp, %rbp
+ push %rbx
+.cfi_push %rbx
+___
+$code .= <<___ if ($win64);
+ sub \$160, %rsp
+ vmovups %xmm6, 0(%rsp)
+ vmovups %xmm7, 16(%rsp)
+ vmovups %xmm8, 32(%rsp)
+ vmovups %xmm9, 48(%rsp)
+ vmovups %xmm10, 64(%rsp)
+ vmovups %xmm11, 80(%rsp)
+ vmovups %xmm12, 96(%rsp)
+ vmovups %xmm13, 112(%rsp)
+ vmovups %xmm14, 128(%rsp)
+ vmovups %xmm15, 144(%rsp)
+___
+$code.=<<___;
+
+ sub \$$sf_size, %rsp
+ mov %rsp, %rbx
+
+.Lshake128_x4_body:
+ mov $arg1, $sf_arg1(%rbx)
+ mov $arg2, $sf_arg2(%rbx)
+ mov $arg3, $sf_arg3(%rbx)
+ mov $arg4, $sf_arg4(%rbx)
+ mov $arg5, $sf_arg5(%rbx)
+
+ lea $sf_state_x4(%rbx), $arg1 # start of x4 state on the stack frame
+ mov $arg1, $sf_state_ptr(%rbx)
+
+ # Initialize the state array to zero
+ call keccak_1600_init_state
+
+ call keccak_1600_save_state_x4
+
+ movq \$0, 8*100($arg1) # clear s[100]
+
+ mov $sf_state_ptr(%rbx), $arg1
+ mov $arg6, $arg2
+___
+$code .= <<___ if ($win64);
+ # xlate prologue handles up to six arguments. For one-shot x4 wrappers
+ # (10 args), the remaining four stay in Win64 stack slots.
+ mov 64(%rbp), $arg3 # arg7 from stack
+ mov 72(%rbp), $arg4 # arg8 from stack
+ mov 80(%rbp), $arg5 # arg9 from stack
+ mov 88(%rbp), $arg6 # arg10 from stack
+___
+$code .= <<___ if (!$win64);
+ mov 16(%rbp), $arg3 # arg7 from stack
+ mov 24(%rbp), $arg4 # arg8 from stack
+ mov 32(%rbp), $arg5 # arg9 from stack
+ mov 40(%rbp), $arg6 # arg10 from stack
+___
+$code.=<<___;
+ # Internal entry avoids Win64 xlate prologue argument remapping.
+___
+$code .= call_internal("SHA3_shake128_x4_inc_absorb_avx512vl_internal");
+$code.=<<___;
+
+ mov $sf_state_ptr(%rbx), $arg1
+ call .L_SHA3_shake128_x4_inc_finalize_avx512vl
+
+ # squeeze
+ mov $sf_arg1(%rbx), $arg1
+ mov $sf_arg2(%rbx), $arg2
+ mov $sf_arg3(%rbx), $arg3
+ mov $sf_arg4(%rbx), $arg4
+ mov $sf_arg5(%rbx), $arg5
+ mov $sf_state_ptr(%rbx), $arg6
+___
+$code .= call_internal("SHA3_shake128_x4_inc_squeeze_avx512vl_internal");
+$code.=<<___;
+
+ # Clear the temporary buffer
+ lea $sf_state_x4(%rbx), %r9
+ vpxorq %ymm31, %ymm31, %ymm31
+ vmovdqu64 %ymm31, 32*0(%r9)
+ vmovdqu64 %ymm31, 32*1(%r9)
+ vmovdqu64 %ymm31, 32*2(%r9)
+ vmovdqu64 %ymm31, 32*3(%r9)
+ vmovdqu64 %ymm31, 32*4(%r9)
+ vmovdqu64 %ymm31, 32*5(%r9)
+ vmovdqu64 %ymm31, 32*6(%r9)
+ vmovdqu64 %ymm31, 32*7(%r9)
+ vmovdqu64 %ymm31, 32*8(%r9)
+ vmovdqu64 %ymm31, 32*9(%r9)
+ vmovdqu64 %ymm31, 32*10(%r9)
+ vmovdqu64 %ymm31, 32*11(%r9)
+ vmovdqu64 %ymm31, 32*12(%r9)
+ vmovdqu64 %ymm31, 32*13(%r9)
+ vmovdqu64 %ymm31, 32*14(%r9)
+ vmovdqu64 %ymm31, 32*15(%r9)
+ vmovdqu64 %ymm31, 32*16(%r9)
+ vmovdqu64 %ymm31, 32*17(%r9)
+ vmovdqu64 %ymm31, 32*18(%r9)
+ vmovdqu64 %ymm31, 32*19(%r9)
+ vmovdqu64 %ymm31, 32*20(%r9)
+ vmovdqu64 %ymm31, 32*21(%r9)
+ vmovdqu64 %ymm31, 32*22(%r9)
+ vmovdqu64 %ymm31, 32*23(%r9)
+ vmovdqu64 %ymm31, 32*24(%r9)
+ vmovq %xmm31, 32*25(%r9)
+
+.Lshake128_x4_epilogue:
+___
+$code .= <<___ if ($win64);
+ vmovups $sf_size+0(%rsp), %xmm6
+ vmovups $sf_size+16(%rsp), %xmm7
+ vmovups $sf_size+32(%rsp), %xmm8
+ vmovups $sf_size+48(%rsp), %xmm9
+ vmovups $sf_size+64(%rsp), %xmm10
+ vmovups $sf_size+80(%rsp), %xmm11
+ vmovups $sf_size+96(%rsp), %xmm12
+ vmovups $sf_size+112(%rsp), %xmm13
+ vmovups $sf_size+128(%rsp), %xmm14
+ vmovups $sf_size+144(%rsp), %xmm15
+ add \$160, %rsp
+___
+$code.=<<___;
+ add \$$sf_size, %rsp
+ pop %rbx
+.cfi_pop %rbx
+ pop %rbp
+.cfi_pop %rbp
+ ret
+.cfi_endproc
+.size SHA3_shake128_x4_avx512vl,.-SHA3_shake128_x4_avx512vl
+
+___
+
+$code .= <<___ if ($win64);
+# Internal Win64 shim for absorb entry. It establishes xlate-compatible
+# unwind state and then jumps to the function entry after the prologue.
+# This is required for internal calls since the xlate ABI conversion
+# is already done in the caller function.
+.type SHA3_shake128_x4_inc_absorb_avx512vl_internal,\@abi-omnipotent
+.align 32
+.LSEH_begin_SHA3_shake128_x4_inc_absorb_avx512vl_internal:
+SHA3_shake128_x4_inc_absorb_avx512vl_internal:
+ mov %rsp, %rax
+ mov $arg1, 8(%rsp)
+ mov $arg2, 16(%rsp)
+ jmp .L_SHA3_shake128_x4_inc_absorb_avx512vl
+.LSEH_end_SHA3_shake128_x4_inc_absorb_avx512vl_internal:
+.size SHA3_shake128_x4_inc_absorb_avx512vl_internal,.-SHA3_shake128_x4_inc_absorb_avx512vl_internal
+___
+$code.=<<___;
+
+# SHA3_shake128_x4_inc_absorb_avx512vl
+# Absorb input data into 4 parallel SHAKE128 states
+# Arguments:
+# arg1 (rdi): pointer to state context (808 bytes)
+# arg2 (rsi): pointer to lane 0 input data
+# arg3 (rdx): pointer to lane 1 input data
+# arg4 (rcx): pointer to lane 2 input data
+# arg5 (r8): pointer to lane 3 input data
+# arg6 (r9): input length in bytes (must be same for all lanes)
+# Returns: void
+# Note: Input is XORed into state and Keccak permutation is applied for each rate-sized block
+.globl SHA3_shake128_x4_inc_absorb_avx512vl
+.type SHA3_shake128_x4_inc_absorb_avx512vl,\@function,6
+.align 32
+SHA3_shake128_x4_inc_absorb_avx512vl:
+.L_SHA3_shake128_x4_inc_absorb_avx512vl:
+.cfi_startproc
+ push %rbp
+.cfi_push %rbp
+ push %rbx
+.cfi_push %rbx
+ push %r12
+.cfi_push %r12
+ push %r13
+.cfi_push %r13
+ push %r14
+.cfi_push %r14
+ push %r15
+.cfi_push %r15
+___
+$code .= <<___ if ($win64);
+ sub \$160, %rsp
+ vmovups %xmm6, 0(%rsp)
+ vmovups %xmm7, 16(%rsp)
+ vmovups %xmm8, 32(%rsp)
+ vmovups %xmm9, 48(%rsp)
+ vmovups %xmm10, 64(%rsp)
+ vmovups %xmm11, 80(%rsp)
+ vmovups %xmm12, 96(%rsp)
+ vmovups %xmm13, 112(%rsp)
+ vmovups %xmm14, 128(%rsp)
+ vmovups %xmm15, 144(%rsp)
+___
+$code.=<<___;
+
+.Lshake128_absorb_body:
+ # check for partially processed block
+ mov 8*100($arg1), %r14
+ or %r14, %r14 # s[100] == 0?
+ je .Lshake128_absorb_main_loop_start
+
+ # process remaining bytes if message long enough
+ mov \$168, %r12 # SHAKE128_RATE = 168
+ sub %r14, %r12 # %r12 = capacity
+
+ cmp %r12, $arg6 # if mlen <= capacity then no permute
+ jbe .Lshake128_absorb_skip_permute
+
+ sub %r12, $arg6
+ mov $arg6, %r11 # preserve remaining length across helper calls
+
+ # r10/state, arg2-arg5/inputs, r12/length
+ mov $arg1, %r10 # %r10 = state
+ call keccak_1600_partial_add_x4 # arg2-arg5 are updated
+
+ call keccak_1600_load_state_x4
+
+ call keccak_1600_permute
+
+ movq \$0, 8*100($arg1) # clear s[100]
+ jmp .Lshake128_absorb_partial_block_done
+
+.Lshake128_absorb_skip_permute:
+ # r10/state, arg2-arg5/inputs, r12/length
+ mov $arg1, %r10
+ mov $arg6, %r12
+ mov $arg6, %r11 # preserve input length across helper call
+ call keccak_1600_partial_add_x4
+
+ lea (%r11,%r14), %r15
+ mov %r15, 8*100($arg1) # s[100] += inlen
+
+ cmp \$168, %r15 # check s[100] below SHAKE128_RATE
+ jb .Lshake128_absorb_exit
+
+ call keccak_1600_load_state_x4
+
+ call keccak_1600_permute
+
+ call keccak_1600_save_state_x4
+
+ movq \$0, 8*100($arg1) # clear s[100]
+ jmp .Lshake128_absorb_exit
+
+.Lshake128_absorb_main_loop_start:
+ call keccak_1600_load_state_x4
+ mov $arg6, %r11 # full input length when no prior partial block
+
+.Lshake128_absorb_partial_block_done:
+ xor %r12, %r12 # zero message offset
+
+ # Process the input message in blocks
+.align 32
+.Lshake128_absorb_while_loop:
+ cmp \$168, %r11 # compare mlen to SHAKE128_RATE
+ jb .Lshake128_absorb_while_loop_done
+
+ # Inline absorb_bytes_x4 for SHAKE128_RATE (168 bytes = 21 ymm registers)
+___
+
+# Generate absorb code for SHAKE128 rate (168 bytes)
+for (my $i = 0; $i < 21; $i++) {
+ my $offset = $i * 8;
+ $code.=<<___;
+ vmovq $offset($arg2,%r12), %xmm31
+ vpinsrq \$1, $offset($arg3,%r12), %xmm31, %xmm31
+ vmovq $offset($arg4,%r12), %xmm30
+ vpinsrq \$1, $offset($arg5,%r12), %xmm30, %xmm30
+ vinserti32x4 \$1, %xmm30, %ymm31, %ymm31
+ vpxorq %ymm31, %ymm$i, %ymm$i
+___
+}
+
+$code.=<<___;
+ sub \$168, %r11 # Subtract the rate from the remaining length
+ add \$168, %r12 # Adjust offset to next block
+ call keccak_1600_permute # Perform the Keccak permutation
+
+ jmp .Lshake128_absorb_while_loop
+
+.align 32
+.Lshake128_absorb_while_loop_done:
+ call keccak_1600_save_state_x4
+
+ mov %r11, 8*100($arg1) # update s[100]
+ or %r11, %r11
+ jz .Lshake128_absorb_exit
+
+ movq \$0, 8*100($arg1) # clear s[100]
+
+ # r10/state, arg2-arg5/input, r12/length
+ mov $arg1, %r10
+ add %r12, $arg2
+ add %r12, $arg3
+ add %r12, $arg4
+ add %r12, $arg5
+ mov %r11, %r12
+ call keccak_1600_partial_add_x4
+
+ mov %r11, 8*100($arg1) # update s[100]
+
+.Lshake128_absorb_exit:
+ # Clear sensitive registers
+ vpxorq %xmm16, %xmm16, %xmm16
+ vmovdqa64 %ymm16, %ymm17
+ vmovdqa64 %ymm16, %ymm18
+ vmovdqa64 %ymm16, %ymm19
+ vmovdqa64 %ymm16, %ymm20
+ vmovdqa64 %ymm16, %ymm21
+ vmovdqa64 %ymm16, %ymm22
+ vmovdqa64 %ymm16, %ymm23
+ vmovdqa64 %ymm16, %ymm24
+ vmovdqa64 %ymm16, %ymm25
+ vmovdqa64 %ymm16, %ymm26
+ vmovdqa64 %ymm16, %ymm27
+ vmovdqa64 %ymm16, %ymm28
+ vmovdqa64 %ymm16, %ymm29
+ vmovdqa64 %ymm16, %ymm30
+ vmovdqa64 %ymm16, %ymm31
+.Lshake128_absorb_epilogue:
+ vzeroall
+___
+$code .= <<___ if ($win64);
+ vmovups 0(%rsp), %xmm6
+ vmovups 16(%rsp), %xmm7
+ vmovups 32(%rsp), %xmm8
+ vmovups 48(%rsp), %xmm9
+ vmovups 64(%rsp), %xmm10
+ vmovups 80(%rsp), %xmm11
+ vmovups 96(%rsp), %xmm12
+ vmovups 112(%rsp), %xmm13
+ vmovups 128(%rsp), %xmm14
+ vmovups 144(%rsp), %xmm15
+ add \$160, %rsp
+___
+$code.=<<___;
+
+ pop %r15
+.cfi_pop %r15
+ pop %r14
+.cfi_pop %r14
+ pop %r13
+.cfi_pop %r13
+ pop %r12
+.cfi_pop %r12
+ pop %rbx
+.cfi_pop %rbx
+ pop %rbp
+.cfi_pop %rbp
+ ret
+.cfi_endproc
+.size SHA3_shake128_x4_inc_absorb_avx512vl,.-SHA3_shake128_x4_inc_absorb_avx512vl
+
+
+# SHA3_shake128_x4_inc_finalize_avx512vl
+# Finalize absorption phase for 4 parallel SHAKE-128 states
+# Adds padding and terminator bytes and clears the absorb offset
+# Arguments:
+# arg1 (rdi): pointer to state context (808 bytes)
+# Returns: void
+# Note: After this call, state is ready for squeezing output
+.globl SHA3_shake128_x4_inc_finalize_avx512vl
+.type SHA3_shake128_x4_inc_finalize_avx512vl,\@function,1
+.align 32
+SHA3_shake128_x4_inc_finalize_avx512vl:
+.L_SHA3_shake128_x4_inc_finalize_avx512vl:
+.cfi_startproc
+ mov 8*100($arg1), %r11 # load state offset from s[100]
+ mov %r11, %r10
+ and \$~7, %r10d # offset to the state register
+ and \$7, %r11d # offset within the register
+
+ # add EOM byte right after the message
+ vmovdqu32 ($arg1,%r10,4), %ymm31
+ lea shake_msg_pad_x4(%rip), %r9
+ sub %r11, %r9
+ vmovdqu32 (%r9), %ymm30
+ vpxorq %ymm30, %ymm31, %ymm31
+ vmovdqu32 %ymm31, ($arg1,%r10,4)
+
+ # add terminating byte at offset equal to rate - 1 (SHAKE128_RATE = 168)
+ vmovdqu32 640($arg1), %ymm31 # 168*4 - 32 = 672 - 32 = 640
+ vmovdqa32 shake_terminator_byte_x4(%rip), %ymm30
+ vpxorq %ymm30, %ymm31, %ymm31
+ vmovdqu32 %ymm31, 640($arg1)
+
+ movq \$0, 8*100($arg1) # clear s[100]
+ vpxorq %ymm31, %ymm31, %ymm31
+ ret
+.cfi_endproc
+.size SHA3_shake128_x4_inc_finalize_avx512vl,.-SHA3_shake128_x4_inc_finalize_avx512vl
+
+___
+
+$code .= <<___ if ($win64);
+# Internal Win64 shim for squeeze entry. It establishes xlate-compatible
+# unwind state and then jumps to the function entry after the prologue.
+# This is required for internal calls since the xlate ABI conversion
+# is already done in the caller function.
+.type SHA3_shake128_x4_inc_squeeze_avx512vl_internal,\@abi-omnipotent
+.align 32
+.LSEH_begin_SHA3_shake128_x4_inc_squeeze_avx512vl_internal:
+SHA3_shake128_x4_inc_squeeze_avx512vl_internal:
+ mov %rsp, %rax
+ mov $arg1, 8(%rsp)
+ mov $arg2, 16(%rsp)
+ jmp .L_SHA3_shake128_x4_inc_squeeze_avx512vl
+.LSEH_end_SHA3_shake128_x4_inc_squeeze_avx512vl_internal:
+.size SHA3_shake128_x4_inc_squeeze_avx512vl_internal,.-SHA3_shake128_x4_inc_squeeze_avx512vl_internal
+___
+$code.=<<___;
+
+# SHA3_shake128_x4_inc_squeeze_avx512vl
+# Squeeze output from 4 parallel SHAKE128 states
+# Arguments:
+# arg1 (rdi): pointer to lane 0 output buffer
+# arg2 (rsi): pointer to lane 1 output buffer
+# arg3 (rdx): pointer to lane 2 output buffer
+# arg4 (rcx): pointer to lane 3 output buffer
+# arg5 (r8): output length in bytes (must be same for all lanes)
+# arg6 (r9): pointer to state context (808 bytes)
+# Returns: void
+# Note: Can be called multiple times to generate arbitrary-length output
+.globl SHA3_shake128_x4_inc_squeeze_avx512vl
+.type SHA3_shake128_x4_inc_squeeze_avx512vl,\@function,6
+.align 32
+SHA3_shake128_x4_inc_squeeze_avx512vl:
+.L_SHA3_shake128_x4_inc_squeeze_avx512vl:
+.cfi_startproc
+ push %rbp
+.cfi_push %rbp
+ push %rbx
+.cfi_push %rbx
+ push %r12
+.cfi_push %r12
+ push %r13
+.cfi_push %r13
+ push %r14
+.cfi_push %r14
+ push %r15
+.cfi_push %r15
+___
+$code .= <<___ if ($win64);
+ sub \$160, %rsp
+ vmovups %xmm6, 0(%rsp)
+ vmovups %xmm7, 16(%rsp)
+ vmovups %xmm8, 32(%rsp)
+ vmovups %xmm9, 48(%rsp)
+ vmovups %xmm10, 64(%rsp)
+ vmovups %xmm11, 80(%rsp)
+ vmovups %xmm12, 96(%rsp)
+ vmovups %xmm13, 112(%rsp)
+ vmovups %xmm14, 128(%rsp)
+ vmovups %xmm15, 144(%rsp)
+___
+$code.=<<___;
+
+.Lshake128_squeeze_body:
+ or $arg5, $arg5
+ jz .Lshake128_squeeze_done
+
+ # check for partially processed block
+ mov 8*100($arg6), %r15 # s[100] - capacity
+ or %r15, %r15
+ jnz .Lshake128_squeeze_no_init_permute
+
+ mov $arg1, %r14
+ mov $arg6, $arg1
+ call keccak_1600_load_state_x4
+
+ mov %r14, $arg1
+
+ xor %rbp, %rbp
+ jmp .Lshake128_squeeze_loop
+
+.align 32
+.Lshake128_squeeze_no_init_permute:
+ # extract bytes: r10 - state/src, arg1-arg4 - output/dst, r12 - length = min(capacity, outlen), r11 - offset
+ mov $arg6, %r10
+ mov $arg6, %r14 # preserve state pointer across extract helper
+
+ mov %r15, %r12
+ cmp %r15, $arg5
+ cmovnae $arg5, %r12 # %r12 = min(capacity, outlen)
+
+ sub %r12, $arg5 # outlen -= length
+
+ mov \$168, %r11d # SHAKE128_RATE
+ sub %r15, %r11 # state offset
+
+ sub %r12, %r15 # capacity -= length
+ mov %r15, 8*100($arg6) # update s[100]
+
+ call keccak_1600_extract_bytes_x4
+ mov %r14, $arg6 # restore state pointer after helper clobbers
+
+ or %r15, %r15
+ jnz .Lshake128_squeeze_done # check s[100] not zero
+
+ mov $arg1, %r13 # preserve arg1
+ mov %r14, $arg1
+ call keccak_1600_load_state_x4
+
+ mov %r13, $arg1
+ xor %rbp, %rbp
+
+.align 32
+.Lshake128_squeeze_loop:
+ cmp \$168, $arg5 # outlen > SHAKE128_RATE
+ jb .Lshake128_squeeze_final_extract
+
+ call keccak_1600_permute
+
+ # Extract SHAKE128 rate bytes (168 bytes = 21 x 8 bytes) inline
+___
+
+# Generate extract code for SHAKE128 rate (168 bytes = 21 ymm registers)
+for (my $i = 0; $i < 21; $i++) {
+ my $offset = $i * 8;
+ $code.=<<___;
+ vextracti64x2 \$1, %ymm$i, %xmm31
+ vmovq %xmm$i, $offset($arg1,%rbp)
+ vpextrq \$1, %xmm$i, $offset($arg2,%rbp)
+ vmovq %xmm31, $offset($arg3,%rbp)
+ vpextrq \$1, %xmm31, $offset($arg4,%rbp)
+___
+}
+
+$code.=<<___;
+ add \$168, %rbp # dst offset += SHAKE128_RATE
+ sub \$168, $arg5 # outlen -= SHAKE128_RATE
+ jmp .Lshake128_squeeze_loop
+
+.align 32
+.Lshake128_squeeze_final_extract:
+ or $arg5, $arg5
+ jz .Lshake128_squeeze_no_end_permute
+
+ # update output pointers
+ add %rbp, $arg1
+ add %rbp, $arg2
+ add %rbp, $arg3
+ add %rbp, $arg4
+
+ mov \$168, %r15d # SHAKE128_RATE
+ sub $arg5, %r15
+ mov %r15, 8*100($arg6) # s[100] = capacity
+
+ call keccak_1600_permute
+
+ mov $arg1, %r14
+ mov $arg6, $arg1
+ call keccak_1600_save_state_x4
+
+ mov %r14, $arg1
+
+ # extract bytes: r10 - state/src, arg1-arg4 - output/dst, r12 - length, r11 - offset = 0
+ mov $arg6, %r10
+ mov $arg5, %r12
+ xor %r11, %r11
+ call keccak_1600_extract_bytes_x4
+
+ jmp .Lshake128_squeeze_done
+
+.Lshake128_squeeze_no_end_permute:
+ movq \$0, 8*100($arg6) # s[100] = 0
+ mov $arg6, $arg1
+ call keccak_1600_save_state_x4
+
+.Lshake128_squeeze_done:
+ # Clear sensitive registers
+ vpxorq %xmm16, %xmm16, %xmm16
+ vmovdqa64 %ymm16, %ymm17
+ vmovdqa64 %ymm16, %ymm18
+ vmovdqa64 %ymm16, %ymm19
+ vmovdqa64 %ymm16, %ymm20
+ vmovdqa64 %ymm16, %ymm21
+ vmovdqa64 %ymm16, %ymm22
+ vmovdqa64 %ymm16, %ymm23
+ vmovdqa64 %ymm16, %ymm24
+ vmovdqa64 %ymm16, %ymm25
+ vmovdqa64 %ymm16, %ymm26
+ vmovdqa64 %ymm16, %ymm27
+ vmovdqa64 %ymm16, %ymm28
+ vmovdqa64 %ymm16, %ymm29
+ vmovdqa64 %ymm16, %ymm30
+ vmovdqa64 %ymm16, %ymm31
+.Lshake128_squeeze_epilogue:
+ vzeroall
+___
+$code .= <<___ if ($win64);
+ vmovups 0(%rsp), %xmm6
+ vmovups 16(%rsp), %xmm7
+ vmovups 32(%rsp), %xmm8
+ vmovups 48(%rsp), %xmm9
+ vmovups 64(%rsp), %xmm10
+ vmovups 80(%rsp), %xmm11
+ vmovups 96(%rsp), %xmm12
+ vmovups 112(%rsp), %xmm13
+ vmovups 128(%rsp), %xmm14
+ vmovups 144(%rsp), %xmm15
+ add \$160, %rsp
+___
+$code.=<<___;
+
+ pop %r15
+.cfi_pop %r15
+ pop %r14
+.cfi_pop %r14
+ pop %r13
+.cfi_pop %r13
+ pop %r12
+.cfi_pop %r12
+ pop %rbx
+.cfi_pop %rbx
+ pop %rbp
+.cfi_pop %rbp
+ ret
+.cfi_endproc
+.size SHA3_shake128_x4_inc_squeeze_avx512vl,.-SHA3_shake128_x4_inc_squeeze_avx512vl
+
+
+# SHAKE256 x4 multi-buffer functions
+# These functions process 4 independent SHAKE256 streams in parallel using AVX-512VL
+# State layout: 25 ymm registers (200 bytes each) + 1 qword = 808 bytes per context
+# Rate: 136 bytes for SHAKE256
+
+# SHA3_shake256_x4_avx512vl
+# One-shot SHAKE-256 x4 function: init + absorb + finalize + squeeze
+# Arguments:
+# arg1 (rdi): pointer to output lane 0
+# arg2 (rsi): pointer to output lane 1
+# arg3 (rdx): pointer to output lane 2
+# arg4 (rcx): pointer to output lane 3
+# arg5 (r8): output length in bytes (must be same for all lanes)
+# arg6 (r9): pointer to input lane 0
+# [stack+0]: pointer to input lane 1
+# [stack+8]: pointer to input lane 2
+# [stack+16]: pointer to input lane 3
+# [stack+24]: input length in bytes (must be same for all lanes)
+# Returns: void
+.globl SHA3_shake256_x4_avx512vl
+.type SHA3_shake256_x4_avx512vl,\@function,10
+.align 32
+SHA3_shake256_x4_avx512vl:
+.cfi_startproc
+ push %rbp
+.cfi_push %rbp
+ mov %rsp, %rbp
+ push %rbx
+.cfi_push %rbx
+___
+$code .= <<___ if ($win64);
+ sub \$160, %rsp
+ vmovups %xmm6, 0(%rsp)
+ vmovups %xmm7, 16(%rsp)
+ vmovups %xmm8, 32(%rsp)
+ vmovups %xmm9, 48(%rsp)
+ vmovups %xmm10, 64(%rsp)
+ vmovups %xmm11, 80(%rsp)
+ vmovups %xmm12, 96(%rsp)
+ vmovups %xmm13, 112(%rsp)
+ vmovups %xmm14, 128(%rsp)
+ vmovups %xmm15, 144(%rsp)
+___
+$code.=<<___;
+
+ sub \$$sf_size, %rsp
+ mov %rsp, %rbx
+
+.Lshake256_x4_body:
+ mov $arg1, $sf_arg1(%rbx)
+ mov $arg2, $sf_arg2(%rbx)
+ mov $arg3, $sf_arg3(%rbx)
+ mov $arg4, $sf_arg4(%rbx)
+ mov $arg5, $sf_arg5(%rbx)
+
+ lea $sf_state_x4(%rbx), $arg1 # start of x4 state on the stack frame
+ mov $arg1, $sf_state_ptr(%rbx)
+
+ # Initialize the state array to zero
+ call keccak_1600_init_state
+
+ call keccak_1600_save_state_x4
+
+ movq \$0, 8*100($arg1) # clear s[100]
+
+ mov $sf_state_ptr(%rbx), $arg1
+ mov $arg6, $arg2
+___
+$code .= <<___ if ($win64);
+ # xlate prologue handles up to six arguments. For one-shot x4 wrappers
+ # (10 args), the remaining four stay in Win64 stack slots.
+ mov 64(%rbp), $arg3 # arg7 from stack
+ mov 72(%rbp), $arg4 # arg8 from stack
+ mov 80(%rbp), $arg5 # arg9 from stack
+ mov 88(%rbp), $arg6 # arg10 from stack
+___
+$code .= <<___ if (!$win64);
+ mov 16(%rbp), $arg3 # arg7 from stack
+ mov 24(%rbp), $arg4 # arg8 from stack
+ mov 32(%rbp), $arg5 # arg9 from stack
+ mov 40(%rbp), $arg6 # arg10 from stack
+___
+$code.=<<___;
+ # Internal entry avoids Win64 xlate prologue argument remapping.
+___
+$code .= call_internal("SHA3_shake256_x4_inc_absorb_avx512vl_internal");
+$code.=<<___;
+
+ mov $sf_state_ptr(%rbx), $arg1
+ call .L_SHA3_shake256_x4_inc_finalize_avx512vl
+
+ # squeeze
+ mov $sf_arg1(%rbx), $arg1
+ mov $sf_arg2(%rbx), $arg2
+ mov $sf_arg3(%rbx), $arg3
+ mov $sf_arg4(%rbx), $arg4
+ mov $sf_arg5(%rbx), $arg5
+ mov $sf_state_ptr(%rbx), $arg6
+___
+$code .= call_internal("SHA3_shake256_x4_inc_squeeze_avx512vl_internal");
+$code.=<<___;
+
+ # Clear the temporary buffer
+ lea $sf_state_x4(%rbx), %r9
+ vpxorq %ymm31, %ymm31, %ymm31
+ vmovdqu64 %ymm31, 32*0(%r9)
+ vmovdqu64 %ymm31, 32*1(%r9)
+ vmovdqu64 %ymm31, 32*2(%r9)
+ vmovdqu64 %ymm31, 32*3(%r9)
+ vmovdqu64 %ymm31, 32*4(%r9)
+ vmovdqu64 %ymm31, 32*5(%r9)
+ vmovdqu64 %ymm31, 32*6(%r9)
+ vmovdqu64 %ymm31, 32*7(%r9)
+ vmovdqu64 %ymm31, 32*8(%r9)
+ vmovdqu64 %ymm31, 32*9(%r9)
+ vmovdqu64 %ymm31, 32*10(%r9)
+ vmovdqu64 %ymm31, 32*11(%r9)
+ vmovdqu64 %ymm31, 32*12(%r9)
+ vmovdqu64 %ymm31, 32*13(%r9)
+ vmovdqu64 %ymm31, 32*14(%r9)
+ vmovdqu64 %ymm31, 32*15(%r9)
+ vmovdqu64 %ymm31, 32*16(%r9)
+ vmovdqu64 %ymm31, 32*17(%r9)
+ vmovdqu64 %ymm31, 32*18(%r9)
+ vmovdqu64 %ymm31, 32*19(%r9)
+ vmovdqu64 %ymm31, 32*20(%r9)
+ vmovdqu64 %ymm31, 32*21(%r9)
+ vmovdqu64 %ymm31, 32*22(%r9)
+ vmovdqu64 %ymm31, 32*23(%r9)
+ vmovdqu64 %ymm31, 32*24(%r9)
+ vmovq %xmm31, 32*25(%r9)
+
+.Lshake256_x4_epilogue:
+___
+$code .= <<___ if ($win64);
+ vmovups $sf_size+0(%rsp), %xmm6
+ vmovups $sf_size+16(%rsp), %xmm7
+ vmovups $sf_size+32(%rsp), %xmm8
+ vmovups $sf_size+48(%rsp), %xmm9
+ vmovups $sf_size+64(%rsp), %xmm10
+ vmovups $sf_size+80(%rsp), %xmm11
+ vmovups $sf_size+96(%rsp), %xmm12
+ vmovups $sf_size+112(%rsp), %xmm13
+ vmovups $sf_size+128(%rsp), %xmm14
+ vmovups $sf_size+144(%rsp), %xmm15
+ add \$160, %rsp
+___
+$code.=<<___;
+ add \$$sf_size, %rsp
+ pop %rbx
+.cfi_pop %rbx
+ pop %rbp
+.cfi_pop %rbp
+ ret
+.cfi_endproc
+.size SHA3_shake256_x4_avx512vl,.-SHA3_shake256_x4_avx512vl
+
+___
+
+$code .= <<___ if ($win64);
+# Internal Win64 shim for absorb entry. It establishes xlate-compatible
+# unwind state and then jumps to the function entry after the prologue.
+# This is required for internal calls since the xlate ABI conversion
+# is already done in the caller function.
+.type SHA3_shake256_x4_inc_absorb_avx512vl_internal,\@abi-omnipotent
+.align 32
+.LSEH_begin_SHA3_shake256_x4_inc_absorb_avx512vl_internal:
+SHA3_shake256_x4_inc_absorb_avx512vl_internal:
+ mov %rsp, %rax
+ mov $arg1, 8(%rsp)
+ mov $arg2, 16(%rsp)
+ jmp .L_SHA3_shake256_x4_inc_absorb_avx512vl
+.LSEH_end_SHA3_shake256_x4_inc_absorb_avx512vl_internal:
+.size SHA3_shake256_x4_inc_absorb_avx512vl_internal,.-SHA3_shake256_x4_inc_absorb_avx512vl_internal
+___
+$code.=<<___;
+
+# SHA3_shake256_x4_inc_absorb_avx512vl
+# Absorb input data into 4 parallel SHAKE256 states
+# Arguments:
+# arg1 (rdi): pointer to state context (808 bytes)
+# arg2 (rsi): pointer to lane 0 input data
+# arg3 (rdx): pointer to lane 1 input data
+# arg4 (rcx): pointer to lane 2 input data
+# arg5 (r8): pointer to lane 3 input data
+# arg6 (r9): input length in bytes (must be same for all lanes)
+# Returns: void
+# Note: Input is XORed into state and Keccak permutation is applied for each rate-sized block
+.globl SHA3_shake256_x4_inc_absorb_avx512vl
+.type SHA3_shake256_x4_inc_absorb_avx512vl,\@function,6
+.align 32
+SHA3_shake256_x4_inc_absorb_avx512vl:
+.L_SHA3_shake256_x4_inc_absorb_avx512vl:
+.cfi_startproc
+ push %rbp
+.cfi_push %rbp
+ push %rbx
+.cfi_push %rbx
+ push %r12
+.cfi_push %r12
+ push %r13
+.cfi_push %r13
+ push %r14
+.cfi_push %r14
+ push %r15
+.cfi_push %r15
+___
+$code .= <<___ if ($win64);
+ sub \$160, %rsp
+ vmovups %xmm6, 0(%rsp)
+ vmovups %xmm7, 16(%rsp)
+ vmovups %xmm8, 32(%rsp)
+ vmovups %xmm9, 48(%rsp)
+ vmovups %xmm10, 64(%rsp)
+ vmovups %xmm11, 80(%rsp)
+ vmovups %xmm12, 96(%rsp)
+ vmovups %xmm13, 112(%rsp)
+ vmovups %xmm14, 128(%rsp)
+ vmovups %xmm15, 144(%rsp)
+___
+$code.=<<___;
+
+.Lshake256_absorb_body:
+ # check for partially processed block
+ mov 8*100($arg1), %r14
+ or %r14, %r14 # s[100] == 0?
+ je .Lshake256_absorb_main_loop_start
+
+ # process remaining bytes if message long enough
+ mov \$136, %r12 # SHAKE256_RATE = 136
+ sub %r14, %r12 # %r12 = capacity
+
+ cmp %r12, $arg6 # if mlen <= capacity then no permute
+ jbe .Lshake256_absorb_skip_permute
+
+ sub %r12, $arg6
+ mov $arg6, %r11 # preserve remaining length across helper calls
+
+ # r10/state, arg2-arg5/inputs, r12/length
+ mov $arg1, %r10 # %r10 = state
+ call keccak_1600_partial_add_x4 # arg2-arg5 are updated
+
+ call keccak_1600_load_state_x4
+
+ call keccak_1600_permute
+
+ movq \$0, 8*100($arg1) # clear s[100]
+ jmp .Lshake256_absorb_partial_block_done
+
+.Lshake256_absorb_skip_permute:
+ # r10/state, arg2-arg5/inputs, r12/length
+ mov $arg1, %r10
+ mov $arg6, %r12
+ mov $arg6, %r11 # preserve input length across helper call
+ call keccak_1600_partial_add_x4
+
+ lea (%r11,%r14), %r15
+ mov %r15, 8*100($arg1) # s[100] += inlen
+
+ cmp \$136, %r15 # check s[100] below SHAKE256_RATE
+ jb .Lshake256_absorb_exit
+
+ call keccak_1600_load_state_x4
+
+ call keccak_1600_permute
+
+ call keccak_1600_save_state_x4
+
+ movq \$0, 8*100($arg1) # clear s[100]
+ jmp .Lshake256_absorb_exit
+
+.Lshake256_absorb_main_loop_start:
+ call keccak_1600_load_state_x4
+ mov $arg6, %r11 # full input length when no prior partial block
+
+.Lshake256_absorb_partial_block_done:
+ xor %r12, %r12 # zero message offset
+
+ # Process the input message in blocks
+.align 32
+.Lshake256_absorb_while_loop:
+ cmp \$136, %r11 # compare mlen to SHAKE256_RATE
+ jb .Lshake256_absorb_while_loop_done
+
+ # Inline absorb_bytes_x4 for SHAKE256_RATE (136 bytes = 17 ymm registers)
+___
+
+# Generate absorb code for SHAKE256 rate (136 bytes)
+for (my $i = 0; $i < 17; $i++) {
+ my $offset = $i * 8;
+ $code.=<<___;
+ vmovq $offset($arg2,%r12), %xmm31
+ vpinsrq \$1, $offset($arg3,%r12), %xmm31, %xmm31
+ vmovq $offset($arg4,%r12), %xmm30
+ vpinsrq \$1, $offset($arg5,%r12), %xmm30, %xmm30
+ vinserti32x4 \$1, %xmm30, %ymm31, %ymm31
+ vpxorq %ymm31, %ymm$i, %ymm$i
+___
+}
+
+$code.=<<___;
+ sub \$136, %r11 # Subtract the rate from the remaining length
+ add \$136, %r12 # Adjust offset to next block
+ call keccak_1600_permute # Perform the Keccak permutation
+
+ jmp .Lshake256_absorb_while_loop
+
+.align 32
+.Lshake256_absorb_while_loop_done:
+ call keccak_1600_save_state_x4
+
+ mov %r11, 8*100($arg1) # update s[100]
+ or %r11, %r11
+ jz .Lshake256_absorb_exit
+
+ movq \$0, 8*100($arg1) # clear s[100]
+
+ # r10/state, arg2-arg5/input, r12/length
+ mov $arg1, %r10
+ add %r12, $arg2
+ add %r12, $arg3
+ add %r12, $arg4
+ add %r12, $arg5
+ mov %r11, %r12
+ call keccak_1600_partial_add_x4
+
+ mov %r11, 8*100($arg1) # update s[100]
+
+.Lshake256_absorb_exit:
+ # Clear sensitive registers
+ vpxorq %xmm16, %xmm16, %xmm16
+ vmovdqa64 %ymm16, %ymm17
+ vmovdqa64 %ymm16, %ymm18
+ vmovdqa64 %ymm16, %ymm19
+ vmovdqa64 %ymm16, %ymm20
+ vmovdqa64 %ymm16, %ymm21
+ vmovdqa64 %ymm16, %ymm22
+ vmovdqa64 %ymm16, %ymm23
+ vmovdqa64 %ymm16, %ymm24
+ vmovdqa64 %ymm16, %ymm25
+ vmovdqa64 %ymm16, %ymm26
+ vmovdqa64 %ymm16, %ymm27
+ vmovdqa64 %ymm16, %ymm28
+ vmovdqa64 %ymm16, %ymm29
+ vmovdqa64 %ymm16, %ymm30
+ vmovdqa64 %ymm16, %ymm31
+.Lshake256_absorb_epilogue:
+ vzeroall
+___
+$code .= <<___ if ($win64);
+ vmovups 0(%rsp), %xmm6
+ vmovups 16(%rsp), %xmm7
+ vmovups 32(%rsp), %xmm8
+ vmovups 48(%rsp), %xmm9
+ vmovups 64(%rsp), %xmm10
+ vmovups 80(%rsp), %xmm11
+ vmovups 96(%rsp), %xmm12
+ vmovups 112(%rsp), %xmm13
+ vmovups 128(%rsp), %xmm14
+ vmovups 144(%rsp), %xmm15
+ add \$160, %rsp
+___
+$code.=<<___;
+
+ pop %r15
+.cfi_pop %r15
+ pop %r14
+.cfi_pop %r14
+ pop %r13
+.cfi_pop %r13
+ pop %r12
+.cfi_pop %r12
+ pop %rbx
+.cfi_pop %rbx
+ pop %rbp
+.cfi_pop %rbp
+ ret
+.cfi_endproc
+.size SHA3_shake256_x4_inc_absorb_avx512vl,.-SHA3_shake256_x4_inc_absorb_avx512vl
+
+
+# SHA3_shake256_x4_inc_finalize_avx512vl
+# Finalize absorption phase for 4 parallel SHAKE-256 states
+# Adds padding and terminator bytes and clears the absorb offset
+# Arguments:
+# arg1 (rdi): pointer to state context (808 bytes)
+# Returns: void
+# Note: After this call, state is ready for squeezing output
+.globl SHA3_shake256_x4_inc_finalize_avx512vl
+.type SHA3_shake256_x4_inc_finalize_avx512vl,\@function,1
+.align 32
+SHA3_shake256_x4_inc_finalize_avx512vl:
+.L_SHA3_shake256_x4_inc_finalize_avx512vl:
+.cfi_startproc
+ mov 8*100($arg1), %r11 # load state offset from s[100]
+ mov %r11, %r10
+ and \$~7, %r10d # offset to the state register
+ and \$7, %r11d # offset within the register
+
+ # add EOM byte right after the message
+ vmovdqu32 ($arg1,%r10,4), %ymm31
+ lea shake_msg_pad_x4(%rip), %r9
+ sub %r11, %r9
+ vmovdqu32 (%r9), %ymm30
+ vpxorq %ymm30, %ymm31, %ymm31
+ vmovdqu32 %ymm31, ($arg1,%r10,4)
+
+ # add terminating byte at offset equal to rate - 1 (SHAKE256_RATE = 136)
+ vmovdqu32 512($arg1), %ymm31 # 136*4 - 32 = 544 - 32 = 512
+ vmovdqa32 shake_terminator_byte_x4(%rip), %ymm30
+ vpxorq %ymm30, %ymm31, %ymm31
+ vmovdqu32 %ymm31, 512($arg1)
+
+ movq \$0, 8*100($arg1) # clear s[100]
+ vpxorq %ymm31, %ymm31, %ymm31
+ ret
+.cfi_endproc
+.size SHA3_shake256_x4_inc_finalize_avx512vl,.-SHA3_shake256_x4_inc_finalize_avx512vl
+
+___
+
+$code .= <<___ if ($win64);
+# Internal Win64 shim for squeeze entry. It establishes xlate-compatible
+# unwind state and then jumps to the function entry after the prologue.
+# This is required for internal calls since the xlate ABI conversion
+# is already done in the caller function.
+.type SHA3_shake256_x4_inc_squeeze_avx512vl_internal,\@abi-omnipotent
+.align 32
+.LSEH_begin_SHA3_shake256_x4_inc_squeeze_avx512vl_internal:
+SHA3_shake256_x4_inc_squeeze_avx512vl_internal:
+ mov %rsp, %rax
+ mov $arg1, 8(%rsp)
+ mov $arg2, 16(%rsp)
+ jmp .L_SHA3_shake256_x4_inc_squeeze_avx512vl
+.LSEH_end_SHA3_shake256_x4_inc_squeeze_avx512vl_internal:
+.size SHA3_shake256_x4_inc_squeeze_avx512vl_internal,.-SHA3_shake256_x4_inc_squeeze_avx512vl_internal
+___
+$code.=<<___;
+
+# SHA3_shake256_x4_inc_squeeze_avx512vl
+# Squeeze output from 4 parallel SHAKE256 states
+# Arguments:
+# arg1 (rdi): pointer to lane 0 output buffer
+# arg2 (rsi): pointer to lane 1 output buffer
+# arg3 (rdx): pointer to lane 2 output buffer
+# arg4 (rcx): pointer to lane 3 output buffer
+# arg5 (r8): output length in bytes (must be same for all lanes)
+# arg6 (r9): pointer to state context (808 bytes)
+# Returns: void
+# Note: Can be called multiple times to generate arbitrary-length output
+.globl SHA3_shake256_x4_inc_squeeze_avx512vl
+.type SHA3_shake256_x4_inc_squeeze_avx512vl,\@function,6
+.align 32
+SHA3_shake256_x4_inc_squeeze_avx512vl:
+.L_SHA3_shake256_x4_inc_squeeze_avx512vl:
+.cfi_startproc
+ push %rbp
+.cfi_push %rbp
+ push %rbx
+.cfi_push %rbx
+ push %r12
+.cfi_push %r12
+ push %r13
+.cfi_push %r13
+ push %r14
+.cfi_push %r14
+ push %r15
+.cfi_push %r15
+___
+$code .= <<___ if ($win64);
+ sub \$160, %rsp
+ vmovups %xmm6, 0(%rsp)
+ vmovups %xmm7, 16(%rsp)
+ vmovups %xmm8, 32(%rsp)
+ vmovups %xmm9, 48(%rsp)
+ vmovups %xmm10, 64(%rsp)
+ vmovups %xmm11, 80(%rsp)
+ vmovups %xmm12, 96(%rsp)
+ vmovups %xmm13, 112(%rsp)
+ vmovups %xmm14, 128(%rsp)
+ vmovups %xmm15, 144(%rsp)
+___
+$code.=<<___;
+
+.Lshake256_squeeze_body:
+ or $arg5, $arg5
+ jz .Lshake256_squeeze_done
+
+ # check for partially processed block
+ mov 8*100($arg6), %r15 # s[100] - capacity
+ or %r15, %r15
+ jnz .Lshake256_squeeze_no_init_permute
+
+ mov $arg1, %r14
+ mov $arg6, $arg1
+ call keccak_1600_load_state_x4
+
+ mov %r14, $arg1
+
+ xor %rbp, %rbp
+ jmp .Lshake256_squeeze_loop
+
+.align 32
+.Lshake256_squeeze_no_init_permute:
+ # extract bytes: r10 - state/src, arg1-arg4 - output/dst, r12 - length = min(capacity, outlen), r11 - offset
+ mov $arg6, %r10
+ mov $arg6, %r14 # preserve state pointer across extract helper
+
+ mov %r15, %r12
+ cmp %r15, $arg5
+ cmovnae $arg5, %r12 # %r12 = min(capacity, outlen)
+
+ sub %r12, $arg5 # outlen -= length
+
+ mov \$136, %r11d # SHAKE256_RATE
+ sub %r15, %r11 # state offset
+
+ sub %r12, %r15 # capacity -= length
+ mov %r15, 8*100($arg6) # update s[100]
+
+ call keccak_1600_extract_bytes_x4
+ mov %r14, $arg6 # restore state pointer after helper clobbers
+
+ or %r15, %r15
+ jnz .Lshake256_squeeze_done # check s[100] not zero
+
+ mov $arg1, %r13 # preserve arg1
+ mov %r14, $arg1
+ call keccak_1600_load_state_x4
+
+ mov %r13, $arg1
+ xor %rbp, %rbp
+
+.align 32
+.Lshake256_squeeze_loop:
+ cmp \$136, $arg5 # outlen > SHAKE256_RATE
+ jb .Lshake256_squeeze_final_extract
+
+ call keccak_1600_permute
+
+ # Extract SHAKE256 rate bytes (136 bytes = 17 x 8 bytes) inline
+___
+
+# Generate extract code for SHAKE256 rate (136 bytes = 17 ymm registers)
+for (my $i = 0; $i < 17; $i++) {
+ my $offset = $i * 8;
+ $code.=<<___;
+ vextracti64x2 \$1, %ymm$i, %xmm31
+ vmovq %xmm$i, $offset($arg1,%rbp)
+ vpextrq \$1, %xmm$i, $offset($arg2,%rbp)
+ vmovq %xmm31, $offset($arg3,%rbp)
+ vpextrq \$1, %xmm31, $offset($arg4,%rbp)
+___
+}
+
+$code.=<<___;
+ add \$136, %rbp # dst offset += SHAKE256_RATE
+ sub \$136, $arg5 # outlen -= SHAKE256_RATE
+ jmp .Lshake256_squeeze_loop
+
+.align 32
+.Lshake256_squeeze_final_extract:
+ or $arg5, $arg5
+ jz .Lshake256_squeeze_no_end_permute
+
+ # update output pointers
+ add %rbp, $arg1
+ add %rbp, $arg2
+ add %rbp, $arg3
+ add %rbp, $arg4
+
+ mov \$136, %r15d # SHAKE256_RATE
+ sub $arg5, %r15
+ mov %r15, 8*100($arg6) # s[100] = capacity
+
+ call keccak_1600_permute
+
+ mov $arg1, %r14
+ mov $arg6, $arg1
+ call keccak_1600_save_state_x4
+
+ mov %r14, $arg1
+
+ # extract bytes: r10 - state/src, arg1-arg4 - output/dst, r12 - length, r11 - offset = 0
+ mov $arg6, %r10
+ mov $arg5, %r12
+ xor %r11, %r11
+ call keccak_1600_extract_bytes_x4
+
+ jmp .Lshake256_squeeze_done
+
+.Lshake256_squeeze_no_end_permute:
+ movq \$0, 8*100($arg6) # s[100] = 0
+ mov $arg6, $arg1
+ call keccak_1600_save_state_x4
+
+.Lshake256_squeeze_done:
+ # Clear sensitive registers
+ vpxorq %xmm16, %xmm16, %xmm16
+ vmovdqa64 %ymm16, %ymm17
+ vmovdqa64 %ymm16, %ymm18
+ vmovdqa64 %ymm16, %ymm19
+ vmovdqa64 %ymm16, %ymm20
+ vmovdqa64 %ymm16, %ymm21
+ vmovdqa64 %ymm16, %ymm22
+ vmovdqa64 %ymm16, %ymm23
+ vmovdqa64 %ymm16, %ymm24
+ vmovdqa64 %ymm16, %ymm25
+ vmovdqa64 %ymm16, %ymm26
+ vmovdqa64 %ymm16, %ymm27
+ vmovdqa64 %ymm16, %ymm28
+ vmovdqa64 %ymm16, %ymm29
+ vmovdqa64 %ymm16, %ymm30
+ vmovdqa64 %ymm16, %ymm31
+.Lshake256_squeeze_epilogue:
+ vzeroall
+___
+$code .= <<___ if ($win64);
+ vmovups 0(%rsp), %xmm6
+ vmovups 16(%rsp), %xmm7
+ vmovups 32(%rsp), %xmm8
+ vmovups 48(%rsp), %xmm9
+ vmovups 64(%rsp), %xmm10
+ vmovups 80(%rsp), %xmm11
+ vmovups 96(%rsp), %xmm12
+ vmovups 112(%rsp), %xmm13
+ vmovups 128(%rsp), %xmm14
+ vmovups 144(%rsp), %xmm15
+ add \$160, %rsp
+___
+$code.=<<___;
+
+ pop %r15
+.cfi_pop %r15
+ pop %r14
+.cfi_pop %r14
+ pop %r13
+.cfi_pop %r13
+ pop %r12
+.cfi_pop %r12
+ pop %rbx
+.cfi_pop %rbx
+ pop %rbp
+.cfi_pop %rbp
+ ret
+.cfi_endproc
+.size SHA3_shake256_x4_inc_squeeze_avx512vl,.-SHA3_shake256_x4_inc_squeeze_avx512vl
+___
+
+if ($win64) {
+my $context = "%r8";
+my $disp = "%r9";
+
+$code.=<<___;
+.extern __imp_RtlVirtualUnwind
+.type keccak_se_handler,\@abi-omnipotent
+.align 16
+keccak_se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64, %rsp
+
+ mov 120($context), %rax # context->Rax = original %rsp from xlate prologue
+ mov 248($context), %rbx # context->Rip
+
+ mov 8($disp), %rsi # disp->ImageBase
+ mov 56($disp), %r11 # disp->HandlerData
+
+ mov 0(%r11), %r10d # HandlerData[0]: body label (rva)
+ lea (%rsi,%r10), %r10
+ cmp %r10, %rbx # Rip < body?
+ jb .Lkeccak_in_prologue
+
+ mov 4(%r11), %r10d # HandlerData[1]: epilogue label (rva)
+ lea (%rsi,%r10), %r10
+ cmp %r10, %rbx # Rip >= epilogue?
+ jae .Lkeccak_in_epilogue
+
+ # In function body:
+ # HandlerData[2]: delta from context->Rsp(body) to original %rsp
+ # HandlerData[3]: offset of XMM6 save area from context->Rsp(body), -1 if none
+ # HandlerData[4]: number of saved non-volatiles in stack frame layout (2 or 6)
+ # HandlerData[5]: delta from context->Rsp(epilogue) to original %rsp
+ mov 152($context), %rdx # body rsp
+ mov 8(%r11), %r10d
+ lea (%rdx,%r10), %rax # original rsp
+ jmp .Lkeccak_restore_body_or_epilogue
+
+.Lkeccak_in_epilogue:
+ mov 152($context), %rdx # epilogue rsp
+ mov 20(%r11), %r10d
+ lea (%rdx,%r10), %rax # original rsp
+
+.Lkeccak_restore_body_or_epilogue:
+ mov 8(%rax), %rcx # xlate shadow save of original rdi
+ mov 16(%rax), %rsi # xlate shadow save of original rsi
+ mov %rax, 152($context) # context->Rsp = original rsp
+ mov %rsi, 168($context) # context->Rsi
+ mov %rcx, 176($context) # context->Rdi
+
+ mov 16(%r11), %r10d # gpr save count
+ cmp \$6, %r10d
+ jne .Lkeccak_restore_two
+
+ mov -24(%rax), %r12
+ mov -32(%rax), %r13
+ mov -40(%rax), %r14
+ mov -48(%rax), %r15
+ mov %r12, 216($context) # context->R12
+ mov %r13, 224($context) # context->R13
+ mov %r14, 232($context) # context->R14
+ mov %r15, 240($context) # context->R15
+
+.Lkeccak_restore_two:
+ mov -8(%rax), %rbp
+ mov -16(%rax), %rbx
+ mov %rbp, 160($context) # context->Rbp
+ mov %rbx, 144($context) # context->Rbx
+
+ mov 12(%r11), %r10d # xmm save offset from body rsp
+ cmp \$-1, %r10d
+ je .Lkeccak_in_prologue
+
+ lea (%rdx,%r10), %rsi # source = xmm save area
+ lea 512($context), %rdi # &context->Xmm6
+ mov \$20, %ecx # 10 XMM * 2 qwords
+ .long 0xa548f3fc # cld; rep movsq
+
+.Lkeccak_in_prologue:
+ mov 8(%rax), %rcx
+ mov 16(%rax), %rdx
+ mov %rcx, 176($context) # context->Rdi
+ mov %rdx, 168($context) # context->Rsi
+ mov %rax, 152($context) # context->Rsp = original rsp
+
+ mov 40($disp), %rdi # disp->ContextRecord
+ mov $context, %rsi
+ mov \$154, %ecx # sizeof(CONTEXT)/8
+ .long 0xa548f3fc # cld; rep movsq
+
+ mov $disp, %rsi
+ xor %rcx, %rcx # UNW_FLAG_NHANDLER
+ mov 8(%rsi), %rdx # disp->ImageBase
+ mov 0(%rsi), %r8 # disp->ControlPc
+ mov 16(%rsi), %r9 # disp->FunctionEntry
+ mov 40(%rsi), %r10 # disp->ContextRecord
+ lea 56(%rsi), %r11 # &disp->HandlerData
+ lea 24(%rsi), %r12 # &disp->EstablisherFrame
+ mov %r10, 32(%rsp)
+ mov %r11, 40(%rsp)
+ mov %r12, 48(%rsp)
+ mov %rcx, 56(%rsp)
+ call *__imp_RtlVirtualUnwind(%rip)
+
+ mov \$1, %eax # ExceptionContinueSearch
+ add \$64, %rsp
+ popfq
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ pop %rdi
+ pop %rsi
+ ret
+.size keccak_se_handler,.-keccak_se_handler
+
+.section .pdata
+.align 4
+ .rva .LSEH_begin_SHA3_shake128_x4_avx512vl
+ .rva .LSEH_end_SHA3_shake128_x4_avx512vl
+ .rva .LSEH_info_SHA3_shake128_x4_avx512vl
+ .rva .LSEH_begin_SHA3_shake128_x4_inc_absorb_avx512vl_internal
+ .rva .LSEH_end_SHA3_shake128_x4_inc_absorb_avx512vl_internal
+ .rva .LSEH_info_SHA3_shake128_x4_inc_absorb_avx512vl_internal
+ .rva .LSEH_begin_SHA3_shake128_x4_inc_absorb_avx512vl
+ .rva .LSEH_end_SHA3_shake128_x4_inc_absorb_avx512vl
+ .rva .LSEH_info_SHA3_shake128_x4_inc_absorb_avx512vl
+ .rva .LSEH_begin_SHA3_shake128_x4_inc_squeeze_avx512vl_internal
+ .rva .LSEH_end_SHA3_shake128_x4_inc_squeeze_avx512vl_internal
+ .rva .LSEH_info_SHA3_shake128_x4_inc_squeeze_avx512vl_internal
+ .rva .LSEH_begin_SHA3_shake128_x4_inc_squeeze_avx512vl
+ .rva .LSEH_end_SHA3_shake128_x4_inc_squeeze_avx512vl
+ .rva .LSEH_info_SHA3_shake128_x4_inc_squeeze_avx512vl
+ .rva .LSEH_begin_SHA3_shake256_x4_avx512vl
+ .rva .LSEH_end_SHA3_shake256_x4_avx512vl
+ .rva .LSEH_info_SHA3_shake256_x4_avx512vl
+ .rva .LSEH_begin_SHA3_shake256_x4_inc_absorb_avx512vl_internal
+ .rva .LSEH_end_SHA3_shake256_x4_inc_absorb_avx512vl_internal
+ .rva .LSEH_info_SHA3_shake256_x4_inc_absorb_avx512vl_internal
+ .rva .LSEH_begin_SHA3_shake256_x4_inc_absorb_avx512vl
+ .rva .LSEH_end_SHA3_shake256_x4_inc_absorb_avx512vl
+ .rva .LSEH_info_SHA3_shake256_x4_inc_absorb_avx512vl
+ .rva .LSEH_begin_SHA3_shake256_x4_inc_squeeze_avx512vl_internal
+ .rva .LSEH_end_SHA3_shake256_x4_inc_squeeze_avx512vl_internal
+ .rva .LSEH_info_SHA3_shake256_x4_inc_squeeze_avx512vl_internal
+ .rva .LSEH_begin_SHA3_shake256_x4_inc_squeeze_avx512vl
+ .rva .LSEH_end_SHA3_shake256_x4_inc_squeeze_avx512vl
+ .rva .LSEH_info_SHA3_shake256_x4_inc_squeeze_avx512vl
+
+.section .xdata
+.align 8
+.LSEH_info_SHA3_shake128_x4_avx512vl:
+ .byte 9,0,0,0
+ .rva keccak_se_handler
+ .rva .Lshake128_x4_body,.Lshake128_x4_epilogue
+ .long 1032,856,2,1032
+.LSEH_info_SHA3_shake128_x4_inc_absorb_avx512vl:
+ .byte 9,0,0,0
+ .rva keccak_se_handler
+ .rva .Lshake128_absorb_body,.Lshake128_absorb_epilogue
+ .long 208,0,6,208
+.LSEH_info_SHA3_shake128_x4_inc_absorb_avx512vl_internal:
+ .byte 9,0,0,0
+ .rva keccak_se_handler
+ .rva .Lshake128_absorb_body,.Lshake128_absorb_epilogue
+ .long 208,0,6,208
+.LSEH_info_SHA3_shake128_x4_inc_squeeze_avx512vl:
+ .byte 9,0,0,0
+ .rva keccak_se_handler
+ .rva .Lshake128_squeeze_body,.Lshake128_squeeze_epilogue
+ .long 208,0,6,208
+.LSEH_info_SHA3_shake128_x4_inc_squeeze_avx512vl_internal:
+ .byte 9,0,0,0
+ .rva keccak_se_handler
+ .rva .Lshake128_squeeze_body,.Lshake128_squeeze_epilogue
+ .long 208,0,6,208
+.LSEH_info_SHA3_shake256_x4_avx512vl:
+ .byte 9,0,0,0
+ .rva keccak_se_handler
+ .rva .Lshake256_x4_body,.Lshake256_x4_epilogue
+ .long 1032,856,2,1032
+.LSEH_info_SHA3_shake256_x4_inc_absorb_avx512vl:
+ .byte 9,0,0,0
+ .rva keccak_se_handler
+ .rva .Lshake256_absorb_body,.Lshake256_absorb_epilogue
+ .long 208,0,6,208
+.LSEH_info_SHA3_shake256_x4_inc_absorb_avx512vl_internal:
+ .byte 9,0,0,0
+ .rva keccak_se_handler
+ .rva .Lshake256_absorb_body,.Lshake256_absorb_epilogue
+ .long 208,0,6,208
+.LSEH_info_SHA3_shake256_x4_inc_squeeze_avx512vl:
+ .byte 9,0,0,0
+ .rva keccak_se_handler
+ .rva .Lshake256_squeeze_body,.Lshake256_squeeze_epilogue
+ .long 208,0,6,208
+.LSEH_info_SHA3_shake256_x4_inc_squeeze_avx512vl_internal:
+ .byte 9,0,0,0
+ .rva keccak_se_handler
+ .rva .Lshake256_squeeze_body,.Lshake256_squeeze_epilogue
+ .long 208,0,6,208
+___
+}
+
+$code.=<<___;
+
+.section .rodata align=128
+.align 128
+.type iotas,\@object
+iotas:
+ .quad 0x0000000000000001
+ .quad 0x0000000000008082
+ .quad 0x800000000000808a
+ .quad 0x8000000080008000
+ .quad 0x000000000000808b
+ .quad 0x0000000080000001
+ .quad 0x8000000080008081
+ .quad 0x8000000000008009
+ .quad 0x000000000000008a
+ .quad 0x0000000000000088
+ .quad 0x0000000080008009
+ .quad 0x000000008000000a
+ .quad 0x000000008000808b
+ .quad 0x800000000000008b
+ .quad 0x8000000000008089
+ .quad 0x8000000000008003
+ .quad 0x8000000000008002
+ .quad 0x8000000000000080
+ .quad 0x000000000000800a
+ .quad 0x800000008000000a
+ .quad 0x8000000080008081
+ .quad 0x8000000000008080
+ .quad 0x0000000080000001
+ .quad 0x8000000080008008
+.size iotas,.-iotas
+
+.align 8
+byte_kmask_0_to_7:
+ .byte 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f
+
+.align 32
+shake_terminator_byte_x4:
+ .byte 0, 0, 0, 0, 0, 0, 0, 0x80
+ .byte 0, 0, 0, 0, 0, 0, 0, 0x80
+ .byte 0, 0, 0, 0, 0, 0, 0, 0x80
+ .byte 0, 0, 0, 0, 0, 0, 0, 0x80
+
+.align 8
+ .byte 0, 0, 0, 0, 0, 0, 0, 0
+shake_msg_pad_x4:
+ .byte 0x1F, 0, 0, 0, 0, 0, 0, 0
+ .byte 0x1F, 0, 0, 0, 0, 0, 0, 0
+ .byte 0x1F, 0, 0, 0, 0, 0, 0, 0
+ .byte 0x1F, 0, 0, 0, 0, 0, 0, 0
+
+.asciz "Keccak-1600 absorb and squeeze for AVX512VL, CRYPTOGAMS by "
+___
+
+}}} else {{{
+
+# When AVX512VL is not available, output stub functions
+# The capable function returns 0, and the operation functions are not defined (will use C fallback)
+
+$code .= <<___;
+.text
+
+.globl SHA3_avx512vl_capable
+.type SHA3_avx512vl_capable,\@abi-omnipotent
+SHA3_avx512vl_capable:
+ xor %eax, %eax
+ ret
+.size SHA3_avx512vl_capable, .-SHA3_avx512vl_capable
+
+.globl SHA3_shake128_x4_inc_absorb_avx512vl
+.globl SHA3_shake256_x4_inc_absorb_avx512vl
+.globl SHA3_shake128_x4_inc_finalize_avx512vl
+.globl SHA3_shake256_x4_inc_finalize_avx512vl
+.globl SHA3_shake128_x4_inc_squeeze_avx512vl
+.globl SHA3_shake256_x4_inc_squeeze_avx512vl
+.globl SHA3_shake128_x4_avx512vl
+.globl SHA3_shake256_x4_avx512vl
+.type SHA3_shake128_x4_inc_absorb_avx512vl,\@abi-omnipotent
+SHA3_shake128_x4_inc_absorb_avx512vl:
+SHA3_shake256_x4_inc_absorb_avx512vl:
+SHA3_shake128_x4_inc_finalize_avx512vl:
+SHA3_shake256_x4_inc_finalize_avx512vl:
+SHA3_shake128_x4_inc_squeeze_avx512vl:
+SHA3_shake256_x4_inc_squeeze_avx512vl:
+SHA3_shake128_x4_avx512vl:
+SHA3_shake256_x4_avx512vl:
+ .byte 0x0f,0x0b # ud2
+ ret
+.size SHA3_shake128_x4_inc_absorb_avx512vl, .-SHA3_shake128_x4_inc_absorb_avx512vl
+___
+}}}
+
+print $code;
+close STDOUT or die "error closing STDOUT: $!";
diff --git a/crypto/sha/build.info b/crypto/sha/build.info
index 457ac8d06a..88e8b9cc5e 100644
--- a/crypto/sha/build.info
+++ b/crypto/sha/build.info
@@ -65,7 +65,7 @@ ENDIF
$KECCAK1600ASM=keccak1600.c
IF[{- !$disabled{asm} -}]
$KECCAK1600ASM_x86=
- $KECCAK1600ASM_x86_64=keccak1600-x86_64.s
+ $KECCAK1600ASM_x86_64=keccak1600-x86_64.s keccak1600x4-avx512vl.s sha3_x4_avx512vl.c
$KECCAK1600ASM_s390x=keccak1600-s390x.S
@@ -198,4 +198,8 @@ GENERATE[keccak1600-avx512vl.S]=asm/keccak1600-avx512vl.pl
GENERATE[keccak1600-mmx.S]=asm/keccak1600-mmx.pl
GENERATE[keccak1600p8-ppc.S]=asm/keccak1600p8-ppc.pl
+# keccak1600x4-avx512vl.s supports multi-squeeze
+# Currently only used in ML-DSA on x86_64 with AVX-512VL support
+GENERATE[keccak1600x4-avx512vl.s]=asm/keccak1600x4-avx512vl.pl
+
GENERATE[sha1-thumb.S]=asm/sha1-thumb.pl
diff --git a/crypto/sha/keccak1600.c b/crypto/sha/keccak1600.c
index 59e688ce43..26d75f1b8e 100644
--- a/crypto/sha/keccak1600.c
+++ b/crypto/sha/keccak1600.c
@@ -111,7 +111,7 @@ static const uint64_t iotas[] = {
/*
* This is straightforward or "maximum clarity" implementation aiming
* to resemble section 3.2 of the FIPS PUB 202 "SHA-3 Standard:
- * Permutation-Based Hash and Extendible-Output Functions" as much as
+ * Permutation-Based Hash and Extendable-Output Functions" as much as
* possible. With one caveat. Because of the way C stores matrices,
* references to A[x,y] in the specification are presented as A[y][x].
* Implementation unrolls inner x-loops so that modulo 5 operations are
diff --git a/crypto/sha/sha256.c b/crypto/sha/sha256.c
index eab9487622..8cbbfdbb30 100644
--- a/crypto/sha/sha256.c
+++ b/crypto/sha/sha256.c
@@ -164,7 +164,7 @@ static const SHA_LONG K256[64] = {
};
#ifndef PEDANTIC
-#if defined(__GNUC__) && __GNUC__ >= 2 && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
+#if defined(__GNUC__) && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
#if defined(__riscv_zknh)
#define Sigma0(x) ({ MD32_REG_T ret; \
asm ("sha256sum0 %0, %1" \
diff --git a/crypto/sha/sha3_x4_avx512vl.c b/crypto/sha/sha3_x4_avx512vl.c
new file mode 100644
index 0000000000..86a8282814
--- /dev/null
+++ b/crypto/sha/sha3_x4_avx512vl.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright (c) 2026 Intel Corporation. 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
+ */
+
+/*
+ * SHAKE x4 multi-buffer implementation for AVX-512VL
+ *
+ * This file provides incremental API wrappers around the AVX-512VL
+ * assembly implementations for processing 4 SHAKE instances in parallel.
+ *
+ * Callers should check SHA3_avx512vl_capable() before calling.
+ */
+
+#include "internal/sha3.h"
+#include
+#include
+
+#if defined(KECCAK1600_ASM) \
+ && (defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)) \
+ && !defined(OPENSSL_NO_ASM)
+
+/* External assembly function declarations */
+extern void SHA3_shake128_x4_inc_absorb_avx512vl(
+ uint64_t *state,
+ const void *in0, const void *in1,
+ const void *in2, const void *in3,
+ size_t inlen);
+
+extern void SHA3_shake256_x4_inc_absorb_avx512vl(
+ uint64_t *state,
+ const void *in0, const void *in1,
+ const void *in2, const void *in3,
+ size_t inlen);
+
+extern void SHA3_shake128_x4_inc_finalize_avx512vl(uint64_t *state);
+extern void SHA3_shake256_x4_inc_finalize_avx512vl(uint64_t *state);
+
+extern void SHA3_shake128_x4_inc_squeeze_avx512vl(
+ void *out0, void *out1,
+ void *out2, void *out3,
+ size_t outlen,
+ uint64_t *state);
+
+extern void SHA3_shake256_x4_inc_squeeze_avx512vl(
+ void *out0, void *out1,
+ void *out2, void *out3,
+ size_t outlen,
+ uint64_t *state);
+
+/* One-shot assembly function declarations */
+extern void SHA3_shake128_x4_avx512vl(
+ void *out0, void *out1,
+ void *out2, void *out3,
+ size_t outlen,
+ const void *in0, const void *in1,
+ const void *in2, const void *in3,
+ size_t inlen);
+
+extern void SHA3_shake256_x4_avx512vl(
+ void *out0, void *out1,
+ void *out2, void *out3,
+ size_t outlen,
+ const void *in0, const void *in1,
+ const void *in2, const void *in3,
+ size_t inlen);
+
+/*
+ * SHAKE-128 x4 Implementation
+ */
+
+void ossl_sha3_shake128_x4_inc_init_avx512vl(KECCAK1600_X4_AVX512VL_CTX *ctx)
+{
+ memset(ctx->A, 0, sizeof(ctx->A));
+ ctx->rate = SHA3_BLOCKSIZE(128);
+ ctx->finalized = 0;
+}
+
+void ossl_sha3_shake128_x4_inc_absorb_avx512vl(
+ KECCAK1600_X4_AVX512VL_CTX *ctx,
+ const void *in0, const void *in1,
+ const void *in2, const void *in3,
+ size_t inlen)
+{
+ if (ctx->finalized) {
+ /* Error: cannot absorb after finalize */
+ return;
+ }
+
+ SHA3_shake128_x4_inc_absorb_avx512vl(
+ ctx->A, in0, in1, in2, in3, inlen);
+}
+
+void ossl_sha3_shake128_x4_inc_cleanup_avx512vl(KECCAK1600_X4_AVX512VL_CTX *ctx)
+{
+ OPENSSL_cleanse(ctx, sizeof(*ctx));
+}
+
+static void ossl_sha3_shake128_x4_inc_finalize_avx512vl(KECCAK1600_X4_AVX512VL_CTX *ctx)
+{
+ if (ctx->finalized) {
+ return; /* Already finalized */
+ }
+
+ SHA3_shake128_x4_inc_finalize_avx512vl(ctx->A);
+ ctx->finalized = 1;
+}
+
+void ossl_sha3_shake128_x4_inc_squeeze_avx512vl(
+ void *out0, void *out1,
+ void *out2, void *out3,
+ size_t outlen,
+ KECCAK1600_X4_AVX512VL_CTX *ctx)
+{
+ if (!ctx->finalized) {
+ /* Auto-finalize on first squeeze */
+ ossl_sha3_shake128_x4_inc_finalize_avx512vl(ctx);
+ }
+
+ SHA3_shake128_x4_inc_squeeze_avx512vl(
+ out0, out1, out2, out3, outlen, ctx->A);
+}
+
+/*
+ * SHAKE-256 x4 Implementation
+ */
+
+void ossl_sha3_shake256_x4_inc_init_avx512vl(KECCAK1600_X4_AVX512VL_CTX *ctx)
+{
+ memset(ctx->A, 0, sizeof(ctx->A));
+ ctx->rate = SHA3_BLOCKSIZE(256);
+ ctx->finalized = 0;
+}
+
+void ossl_sha3_shake256_x4_inc_absorb_avx512vl(
+ KECCAK1600_X4_AVX512VL_CTX *ctx,
+ const void *in0, const void *in1,
+ const void *in2, const void *in3,
+ size_t inlen)
+{
+ if (ctx->finalized) {
+ /* Error: cannot absorb after finalize */
+ return;
+ }
+
+ SHA3_shake256_x4_inc_absorb_avx512vl(
+ ctx->A, in0, in1, in2, in3, inlen);
+}
+
+void ossl_sha3_shake256_x4_inc_cleanup_avx512vl(KECCAK1600_X4_AVX512VL_CTX *ctx)
+{
+ OPENSSL_cleanse(ctx, sizeof(*ctx));
+}
+
+static void ossl_sha3_shake256_x4_inc_finalize_avx512vl(KECCAK1600_X4_AVX512VL_CTX *ctx)
+{
+ if (ctx->finalized) {
+ return; /* Already finalized */
+ }
+
+ SHA3_shake256_x4_inc_finalize_avx512vl(ctx->A);
+ ctx->finalized = 1;
+}
+
+void ossl_sha3_shake256_x4_inc_squeeze_avx512vl(
+ void *out0, void *out1,
+ void *out2, void *out3,
+ size_t outlen,
+ KECCAK1600_X4_AVX512VL_CTX *ctx)
+{
+ if (!ctx->finalized) {
+ /* Auto-finalize on first squeeze */
+ ossl_sha3_shake256_x4_inc_finalize_avx512vl(ctx);
+ }
+
+ SHA3_shake256_x4_inc_squeeze_avx512vl(
+ out0, out1, out2, out3, outlen, ctx->A);
+}
+
+/*
+ * Single-call wrapper APIs
+ */
+
+void ossl_sha3_shake128_x4_avx512vl(
+ void *out0, void *out1,
+ void *out2, void *out3,
+ size_t outlen,
+ const void *in0, const void *in1,
+ const void *in2, const void *in3,
+ size_t inlen)
+{
+ SHA3_shake128_x4_avx512vl(out0, out1, out2, out3, outlen,
+ in0, in1, in2, in3, inlen);
+}
+
+void ossl_sha3_shake256_x4_avx512vl(
+ void *out0, void *out1,
+ void *out2, void *out3,
+ size_t outlen,
+ const void *in0, const void *in1,
+ const void *in2, const void *in3,
+ size_t inlen)
+{
+ SHA3_shake256_x4_avx512vl(out0, out1, out2, out3, outlen,
+ in0, in1, in2, in3, inlen);
+}
+
+#endif /* KECCAK1600_ASM && x86_64 && !OPENSSL_NO_ASM */
diff --git a/crypto/sha/sha512.c b/crypto/sha/sha512.c
index 6ccc0070e0..9ba32f2926 100644
--- a/crypto/sha/sha512.c
+++ b/crypto/sha/sha512.c
@@ -343,7 +343,7 @@ static const SHA_LONG64 K512[80] = {
};
#ifndef PEDANTIC
-#if defined(__GNUC__) && __GNUC__ >= 2 && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
+#if defined(__GNUC__) && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
#if defined(__x86_64) || defined(__x86_64__)
#define ROTR(a, n) ({ SHA_LONG64 ret; \
asm ("rorq %1,%0" \
diff --git a/crypto/sha/sha_loongarch.c b/crypto/sha/sha_loongarch.c
index 55ececfe04..1576e6f493 100644
--- a/crypto/sha/sha_loongarch.c
+++ b/crypto/sha/sha_loongarch.c
@@ -16,9 +16,9 @@
void sha256_block_data_order_la64v100(void *ctx, const void *in, size_t num);
void sha256_block_data_order_lsx(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 (OPENSSL_loongarch_hwcap_P & LOONGARCH_HWCAP_LSX) {
sha256_block_data_order_lsx(ctx, in, num);
@@ -29,9 +29,9 @@ void sha256_block_data_order(SHA256_CTX *ctx, const void *in, size_t num)
void sha512_block_data_order_la64v100(void *ctx, const void *in, size_t num);
void sha512_block_data_order_lsx(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 (OPENSSL_loongarch_hwcap_P & LOONGARCH_HWCAP_LSX) {
sha512_block_data_order_lsx(ctx, in, num);
diff --git a/crypto/sha/sha_riscv.c b/crypto/sha/sha_riscv.c
index 28248fd5ac..100ecacdde 100644
--- a/crypto/sha/sha_riscv.c
+++ b/crypto/sha/sha_riscv.c
@@ -18,9 +18,9 @@ void sha256_block_data_order_zvkb_zvknha_or_zvknhb(void *ctx, const void *in,
size_t num);
void sha256_block_data_order_zbb(void *ctx, const void *in, size_t num);
void sha256_block_data_order_riscv64(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);
@@ -34,9 +34,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_zbb(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/crypto/sleep.c b/crypto/sleep.c
index 9273995be6..3d8be852c9 100644
--- a/crypto/sleep.c
+++ b/crypto/sleep.c
@@ -67,7 +67,6 @@ static void ossl_sleep_millis(uint64_t millis)
#endif
#elif defined(_WIN32) && !defined(OPENSSL_SYS_UEFI)
-#include
static void ossl_sleep_millis(uint64_t millis)
{
diff --git a/crypto/slh_dsa/slh_fors.c b/crypto/slh_dsa/slh_fors.c
index 78587589db..10335cc5df 100644
--- a/crypto/slh_dsa/slh_fors.c
+++ b/crypto/slh_dsa/slh_fors.c
@@ -156,7 +156,7 @@ int ossl_slh_fors_sign(SLH_DSA_HASH_CTX *ctx, const uint8_t *md,
/*
* Give each of the k trees a unique range at each level.
* e.g. If we have 4096 leaf nodes (2^a = 2^12) for each tree
- * tree i will use indexes from 4096 * i + (0..4095) for its bottom level.
+ * i will use indexes from 4096 * i + (0..4095) for its bottom level.
* For the next level up from the bottom there would be 2048 nodes
* (so tree i uses indexes 2048 * i + (0...2047) for this level)
*/
diff --git a/crypto/sm2/sm2_crypt.c b/crypto/sm2/sm2_crypt.c
index a1cbd88c2d..6e787f5d28 100644
--- a/crypto/sm2/sm2_crypt.c
+++ b/crypto/sm2/sm2_crypt.c
@@ -78,7 +78,7 @@ int ossl_sm2_plaintext_size(const unsigned char *ct, size_t ct_size,
return 0;
}
- *pt_size = ASN1_STRING_length(sm2_ctext->C2);
+ *pt_size = ASN1_STRING_length_ex(sm2_ctext->C2);
SM2_Ciphertext_free(sm2_ctext);
return 1;
@@ -309,7 +309,7 @@ int ossl_sm2_decrypt(const EC_KEY *key,
uint8_t *msg_mask = NULL;
const uint8_t *C2 = NULL;
const uint8_t *C3 = NULL;
- int msg_len = 0;
+ size_t c3_len, msg_len = 0;
EVP_MD_CTX *hash = NULL;
OSSL_LIB_CTX *libctx = ossl_ec_key_get_libctx(key);
const char *propq = ossl_ec_key_get0_propq(key);
@@ -326,14 +326,18 @@ int ossl_sm2_decrypt(const EC_KEY *key,
goto done;
}
- if (ASN1_STRING_length(sm2_ctext->C3) != hash_size) {
+ msg_len = ASN1_STRING_length_ex(sm2_ctext->C2);
+ if (msg_len > INT_MAX)
+ goto done;
+
+ c3_len = ASN1_STRING_length_ex(sm2_ctext->C3);
+ if (c3_len > INT_MAX || c3_len != (size_t)hash_size) {
ERR_raise(ERR_LIB_SM2, SM2_R_INVALID_ENCODING);
goto done;
}
C2 = ASN1_STRING_get0_data(sm2_ctext->C2);
C3 = ASN1_STRING_get0_data(sm2_ctext->C3);
- msg_len = ASN1_STRING_length(sm2_ctext->C2);
if (*ptext_len < (size_t)msg_len) {
ERR_raise(ERR_LIB_SM2, SM2_R_BUFFER_TOO_SMALL);
goto done;
@@ -378,7 +382,7 @@ int ossl_sm2_decrypt(const EC_KEY *key,
if (BN_bn2binpad(x2, x2y2, field_size) < 0
|| BN_bn2binpad(y2, x2y2 + field_size, field_size) < 0
- || !ossl_ecdh_kdf_X9_63(msg_mask, msg_len, x2y2, 2 * field_size,
+ || !ossl_ecdh_kdf_X9_63(msg_mask, (int)msg_len, x2y2, 2 * field_size,
NULL, 0, digest, libctx, propq)) {
ERR_raise(ERR_LIB_SM2, ERR_R_INTERNAL_ERROR);
goto done;
@@ -389,7 +393,7 @@ int ossl_sm2_decrypt(const EC_KEY *key,
goto done;
}
- for (i = 0; i != msg_len; ++i)
+ for (i = 0; i != (int)msg_len; ++i)
ptext_buf[i] = C2[i] ^ msg_mask[i];
hash = EVP_MD_CTX_new();
@@ -400,7 +404,7 @@ int ossl_sm2_decrypt(const EC_KEY *key,
if (!EVP_DigestInit(hash, digest)
|| !EVP_DigestUpdate(hash, x2y2, field_size)
- || !EVP_DigestUpdate(hash, ptext_buf, msg_len)
+ || !EVP_DigestUpdate(hash, ptext_buf, (int)msg_len)
|| !EVP_DigestUpdate(hash, x2y2 + field_size, field_size)
|| !EVP_DigestFinal(hash, computed_C3, NULL)) {
ERR_raise(ERR_LIB_SM2, ERR_R_EVP_LIB);
@@ -413,7 +417,7 @@ int ossl_sm2_decrypt(const EC_KEY *key,
}
rc = 1;
- *ptext_len = msg_len;
+ *ptext_len = (int)msg_len;
done:
if (rc == 0)
diff --git a/crypto/sm3/asm/sm3-armv8.pl b/crypto/sm3/asm/sm3-armv8.pl
index e0c33ecb95..6c51df28f8 100644
--- a/crypto/sm3/asm/sm3-armv8.pl
+++ b/crypto/sm3/asm/sm3-armv8.pl
@@ -51,7 +51,7 @@ $code.=<<___;
___
}
-# A round of compresson function
+# A round of compression function
# Input:
# ab - choose instruction among sm3tt1a, sm3tt1b, sm3tt2a, sm3tt2b
# vstate0 - vstate1, store digest status(A - H)
diff --git a/crypto/sm3/asm/sm3-x86_64.pl b/crypto/sm3/asm/sm3-x86_64.pl
index d3c9d0541a..2f6ddf5616 100755
--- a/crypto/sm3/asm/sm3-x86_64.pl
+++ b/crypto/sm3/asm/sm3-x86_64.pl
@@ -35,8 +35,8 @@ if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
}
if (!$avx2_sm3_ni && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
- `nasm -v 2>&1` =~ /NASM version ([2-9])\.([0-9]+)\.([0-9]+)/) {
- my ($major, $minor, $patch) = ($1, $2, $3);
+ `nasm -v 2>&1` =~ /NASM version ([2-9])\.([0-9]+)(?:\.([0-9]+))?/) {
+ my ($major, $minor, $patch) = ($1, $2, defined($3) ? $3 : 0);
$avx2_sm3_ni = ($major > 2) || ($major == 2 && $minor > 10); # minimal avx2 supported version, binary translation for SM3 instructions (sub sm3op) is used
$avx2_sm3_ni_native = ($major > 2) || ($major == 2 && $minor > 16) || ($major == 2 && $minor == 16 && $patch >= 2); # support added at NASM 2.16.02
}
diff --git a/crypto/sm3/sm3_local.h b/crypto/sm3/sm3_local.h
index 6cb8dca61b..41639b3c95 100644
--- a/crypto/sm3/sm3_local.h
+++ b/crypto/sm3/sm3_local.h
@@ -77,7 +77,7 @@ void ossl_sm3_transform(SM3_CTX *c, const unsigned char *data);
/* clang-format on */
#ifndef PEDANTIC
-#if defined(__GNUC__) && __GNUC__ >= 2 && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
+#if defined(__GNUC__) && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
#if defined(__riscv_zksh)
#define P0(x) ({ MD32_REG_T ret; \
asm ("sm3p0 %0, %1" \
diff --git a/crypto/sm4/asm/sm4-x86_64.pl b/crypto/sm4/asm/sm4-x86_64.pl
index 9fc40fb96a..f5b485968e 100644
--- a/crypto/sm4/asm/sm4-x86_64.pl
+++ b/crypto/sm4/asm/sm4-x86_64.pl
@@ -35,8 +35,8 @@ if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
}
if (!$avx2_sm4_ni && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
- `nasm -v 2>&1` =~ /NASM version ([2-9])\.([0-9]+)\.([0-9]+)/) {
- my ($major, $minor, $patch) = ($1, $2, $3);
+ `nasm -v 2>&1` =~ /NASM version ([2-9])\.([0-9]+)(?:\.([0-9]+))?/) {
+ my ($major, $minor, $patch) = ($1, $2, defined($3) ? $3 : 0);
$avx2_sm4_ni = ($major > 2) || ($major == 2 && $minor > 10); # minimal avx2 supported version, binary translation for SM4 instructions (sub sm4op) is used
$avx2_sm4_ni_native = ($major > 2) || ($major == 2 && $minor > 16) || ($major == 2 && $minor == 16 && $patch >= 2); # support added at NASM 2.16.02
}
diff --git a/crypto/sparcv9cap.c b/crypto/sparcv9cap.c
index c9cc2b9575..cea44ada9b 100644
--- a/crypto/sparcv9cap.c
+++ b/crypto/sparcv9cap.c
@@ -71,7 +71,7 @@ static void common_handler(int sig)
}
#if defined(__sun) && defined(__SVR4)
-#if defined(__GNUC__) && __GNUC__ >= 2
+#if defined(__GNUC__)
extern unsigned int getisax(unsigned int vec[], unsigned int sz) __attribute__((weak));
#elif defined(__SUNPRO_C)
#pragma weak getisax
diff --git a/crypto/ssl_err.c b/crypto/ssl_err.c
index 0dca54bb1d..9766b64314 100644
--- a/crypto/ssl_err.c
+++ b/crypto/ssl_err.c
@@ -426,36 +426,6 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
"srtp protection profile list too long" },
{ ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE),
"srtp unknown protection profile" },
- { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_EXT_INVALID_MAX_FRAGMENT_LENGTH),
- "tls ext invalid max fragment length" },
- { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_EXT_INVALID_SERVERNAME),
- "tls ext invalid servername" },
- { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_EXT_INVALID_SERVERNAME_TYPE),
- "tls ext invalid servername type" },
- { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_SESSION_ID_TOO_LONG),
- "tls session id too long" },
- { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_BAD_CERTIFICATE),
- "tls alert bad certificate" },
- { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_BAD_RECORD_MAC),
- "tls alert bad record mac" },
- { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_CERTIFICATE_EXPIRED),
- "tls alert certificate expired" },
- { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_CERTIFICATE_REVOKED),
- "tls alert certificate revoked" },
- { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_CERTIFICATE_UNKNOWN),
- "tls alert certificate unknown" },
- { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_DECOMPRESSION_FAILURE),
- "tls alert decompression failure" },
- { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_HANDSHAKE_FAILURE),
- "tls alert handshake failure" },
- { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_ILLEGAL_PARAMETER),
- "tls alert illegal parameter" },
- { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_NO_CERTIFICATE),
- "tls alert no certificate" },
- { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_UNEXPECTED_MESSAGE),
- "tls alert unexpected message" },
- { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_UNSUPPORTED_CERTIFICATE),
- "tls alert unsupported certificate" },
{ ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_COMMAND_SECTION_EMPTY),
"ssl command section empty" },
{ ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_COMMAND_SECTION_NOT_FOUND),
@@ -534,10 +504,40 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
"tlsv1 unrecognized name" },
{ ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_UNSUPPORTED_EXTENSION),
"tlsv1 unsupported extension" },
+ { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_BAD_CERTIFICATE),
+ "tls alert bad certificate" },
+ { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_BAD_RECORD_MAC),
+ "tls alert bad record mac" },
+ { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_CERTIFICATE_EXPIRED),
+ "tls alert certificate expired" },
+ { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_CERTIFICATE_REVOKED),
+ "tls alert certificate revoked" },
+ { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_CERTIFICATE_UNKNOWN),
+ "tls alert certificate unknown" },
+ { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_DECOMPRESSION_FAILURE),
+ "tls alert decompression failure" },
+ { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_HANDSHAKE_FAILURE),
+ "tls alert handshake failure" },
+ { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_ILLEGAL_PARAMETER),
+ "tls alert illegal parameter" },
+ { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_NO_CERTIFICATE),
+ "tls alert no certificate" },
+ { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_UNEXPECTED_MESSAGE),
+ "tls alert unexpected message" },
+ { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ALERT_UNSUPPORTED_CERTIFICATE),
+ "tls alert unsupported certificate" },
+ { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_EXT_INVALID_MAX_FRAGMENT_LENGTH),
+ "tls ext invalid max fragment length" },
+ { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_EXT_INVALID_SERVERNAME),
+ "tls ext invalid servername" },
+ { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_EXT_INVALID_SERVERNAME_TYPE),
+ "tls ext invalid servername type" },
{ ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL),
"tls illegal exporter label" },
{ ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST),
"tls invalid ecpointformat list" },
+ { ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_SESSION_ID_TOO_LONG),
+ "tls session id too long" },
{ ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TOO_MANY_KEY_UPDATES),
"too many key updates" },
{ ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TOO_MANY_WARN_ALERTS),
diff --git a/crypto/sslerr.h b/crypto/sslerr.h
index 968f27b00a..f2936b7d99 100644
--- a/crypto/sslerr.h
+++ b/crypto/sslerr.h
@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
- * 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
diff --git a/crypto/store/store_local.h b/crypto/store/store_local.h
index f668d4bbbc..995024d5c9 100644
--- a/crypto/store/store_local.h
+++ b/crypto/store/store_local.h
@@ -104,6 +104,7 @@ struct ossl_store_loader_st {
const char *propdef;
const char *description;
+ int no_store;
CRYPTO_REF_COUNT refcnt;
OSSL_FUNC_store_open_fn *p_open;
diff --git a/crypto/store/store_meth.c b/crypto/store/store_meth.c
index 04c8a8d5f9..1d54d89978 100644
--- a/crypto/store/store_meth.c
+++ b/crypto/store/store_meth.c
@@ -16,17 +16,20 @@
#include "store_local.h"
#include "crypto/context.h"
-int OSSL_STORE_LOADER_up_ref(OSSL_STORE_LOADER *loader)
+static int up_ref_loader(void *method)
{
+ OSSL_STORE_LOADER *loader = (OSSL_STORE_LOADER *)method;
int ref = 0;
if (loader->prov != NULL)
- CRYPTO_UP_REF(&loader->refcnt, &ref);
+ return CRYPTO_UP_REF(&loader->refcnt, &ref);
return 1;
}
-void OSSL_STORE_LOADER_free(OSSL_STORE_LOADER *loader)
+static void free_loader(void *method)
{
+ OSSL_STORE_LOADER *loader = (OSSL_STORE_LOADER *)method;
+
if (loader != NULL && loader->prov != NULL) {
int i;
@@ -39,6 +42,27 @@ void OSSL_STORE_LOADER_free(OSSL_STORE_LOADER *loader)
OPENSSL_free(loader);
}
+int OSSL_STORE_LOADER_up_ref(OSSL_STORE_LOADER *loader)
+{
+#ifdef OPENSSL_NO_CACHED_FETCH
+ return up_ref_loader(loader);
+#else
+ if (loader->no_store != 0)
+ return up_ref_loader(loader);
+ return 1;
+#endif
+}
+
+void OSSL_STORE_LOADER_free(OSSL_STORE_LOADER *loader)
+{
+#ifdef OPENSSL_NO_CACHED_FETCH
+ free_loader(loader);
+#else
+ if (loader != NULL && (loader->no_store != 0))
+ free_loader(loader);
+#endif
+}
+
/*
* OSSL_STORE_LOADER_new() expects the scheme as a constant string,
* which we currently don't have, so we need an alternative allocator.
@@ -61,16 +85,6 @@ static OSSL_STORE_LOADER *new_loader(OSSL_PROVIDER *prov)
return loader;
}
-static int up_ref_loader(void *method)
-{
- return OSSL_STORE_LOADER_up_ref(method);
-}
-
-static void free_loader(void *method)
-{
- OSSL_STORE_LOADER_free(method);
-}
-
/* Data to be passed through ossl_method_construct() */
struct loader_data_st {
OSSL_LIB_CTX *libctx;
@@ -176,7 +190,7 @@ static int put_loader_in_store(void *store, void *method,
}
static void *loader_from_algorithm(int scheme_id, const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov)
+ OSSL_PROVIDER *prov, int no_store)
{
OSSL_STORE_LOADER *loader = NULL;
const OSSL_DISPATCH *fns = algodef->implementation;
@@ -186,6 +200,7 @@ static void *loader_from_algorithm(int scheme_id, const OSSL_ALGORITHM *algodef,
loader->scheme_id = scheme_id;
loader->propdef = algodef->property_definition;
loader->description = algodef->algorithm_description;
+ loader->no_store = no_store;
for (; fns->function_id != 0; fns++) {
switch (fns->function_id) {
@@ -237,7 +252,7 @@ static void *loader_from_algorithm(int scheme_id, const OSSL_ALGORITHM *algodef,
|| loader->p_eof == NULL
|| loader->p_close == NULL) {
/* Only set_ctx_params is optional */
- OSSL_STORE_LOADER_free(loader);
+ free_loader(loader);
ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_LOADER_INCOMPLETE);
return NULL;
}
@@ -250,7 +265,7 @@ static void *loader_from_algorithm(int scheme_id, const OSSL_ALGORITHM *algodef,
* then call loader_from_algorithm() with that identity number.
*/
static void *construct_loader(const OSSL_ALGORITHM *algodef,
- OSSL_PROVIDER *prov, void *data)
+ OSSL_PROVIDER *prov, void *data, int no_store)
{
/*
* This function is only called if get_loader_from_store() returned
@@ -266,7 +281,7 @@ static void *construct_loader(const OSSL_ALGORITHM *algodef,
void *method = NULL;
if (id != 0)
- method = loader_from_algorithm(id, algodef, prov);
+ method = loader_from_algorithm(id, algodef, prov, no_store);
/*
* Flag to indicate that there was actual construction errors. This
@@ -282,7 +297,7 @@ static void *construct_loader(const OSSL_ALGORITHM *algodef,
/* Intermediary function to avoid ugly casts, used below */
static void destruct_loader(void *method, void *data)
{
- OSSL_STORE_LOADER_free(method);
+ free_loader(method);
}
/* Fetching support. Can fetch by numeric identity or by scheme */
@@ -338,8 +353,19 @@ inner_loader_fetch(struct loader_data_st *methdata,
*/
if (id == 0)
id = ossl_namemap_name2num(namemap, scheme);
- ossl_method_store_cache_set(store, prov, id, propq, method,
- up_ref_loader, free_loader);
+ if (id != 0 && methdata->tmp_store == NULL) {
+ ossl_method_store_cache_set(store, prov, id, propq, method,
+ up_ref_loader, free_loader);
+ } else {
+ /*
+ * Like with EVP methods, if the provider requests no caching we need
+ * to take an extra refcount here so that the tmp_stored loader
+ * lives beyond the freeing of that tmp_store
+ */
+#ifndef OPENSSL_NO_CACHED_FETCH
+ OSSL_STORE_LOADER_up_ref((OSSL_STORE_LOADER *)method);
+#endif
+ }
}
/*
diff --git a/crypto/thread/arch/thread_win.c b/crypto/thread/arch/thread_win.c
index b26a1d917a..1026ed3de3 100644
--- a/crypto/thread/arch/thread_win.c
+++ b/crypto/thread/arch/thread_win.c
@@ -7,11 +7,11 @@
* https://www.openssl.org/source/license.html
*/
-#include
+#include "internal/thread_arch.h"
+#include "internal/e_os.h"
#if defined(OPENSSL_THREADS_WINNT)
#include
-#include
static unsigned __stdcall thread_start_thunk(LPVOID vthread)
{
diff --git a/crypto/threads_win.c b/crypto/threads_win.c
index 4fedf24e90..d777010cd8 100644
--- a/crypto/threads_win.c
+++ b/crypto/threads_win.c
@@ -7,14 +7,13 @@
* https://www.openssl.org/source/license.html
*/
-#if defined(_WIN32)
-#include
+#include "internal/e_os.h"
+
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600
#define USE_RWLOCK
#endif
-#endif
-#include
+#include
#include
#include
#include "internal/common.h"
@@ -443,15 +442,11 @@ CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void)
/* Don't set error, to avoid recursion blowup. */
return NULL;
-#if !defined(_WIN32_WCE)
/* 0x400 is the spin count value suggested in the documentation */
if (!InitializeCriticalSectionAndSpinCount(lock, 0x400)) {
OPENSSL_free(lock);
return NULL;
}
-#else
- InitializeCriticalSection(lock);
-#endif
#endif
return lock;
@@ -532,6 +527,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/crypto/ts/ts_asn1.c b/crypto/ts/ts_asn1.c
index b44002ef2f..56d41df554 100644
--- a/crypto/ts/ts_asn1.c
+++ b/crypto/ts/ts_asn1.c
@@ -208,6 +208,7 @@ TS_TST_INFO *PKCS7_to_TS_TST_INFO(PKCS7 *token)
ASN1_TYPE *tst_info_wrapper;
ASN1_OCTET_STRING *tst_info_der;
const unsigned char *p;
+ size_t len;
if (!PKCS7_type_is_signed(token)) {
ERR_raise(ERR_LIB_TS, TS_R_BAD_PKCS7_TYPE);
@@ -230,5 +231,10 @@ TS_TST_INFO *PKCS7_to_TS_TST_INFO(PKCS7 *token)
}
tst_info_der = tst_info_wrapper->value.octet_string;
p = ASN1_STRING_get0_data(tst_info_der);
- return d2i_TS_TST_INFO(NULL, &p, ASN1_STRING_length(tst_info_der));
+ len = ASN1_STRING_length_ex(tst_info_der);
+ if (len > INT_MAX) {
+ ERR_raise(ERR_LIB_TS, TS_R_BAD_TYPE);
+ return NULL;
+ }
+ return d2i_TS_TST_INFO(NULL, &p, (int)len);
}
diff --git a/crypto/ts/ts_lib.c b/crypto/ts/ts_lib.c
index 8b46fb4744..26b3994ccb 100644
--- a/crypto/ts/ts_lib.c
+++ b/crypto/ts/ts_lib.c
@@ -86,7 +86,7 @@ int TS_MSG_IMPRINT_print_bio(BIO *bio, TS_MSG_IMPRINT *a)
BIO_printf(bio, "Message data:\n");
msg = a->hashed_msg;
BIO_dump_indent(bio, (const char *)ASN1_STRING_get0_data(msg),
- ASN1_STRING_length(msg), 4);
+ (int)ASN1_STRING_length_ex(msg), 4);
return 1;
}
diff --git a/crypto/ts/ts_rsp_sign.c b/crypto/ts/ts_rsp_sign.c
index 1421275fd9..e9151f750e 100644
--- a/crypto/ts/ts_rsp_sign.c
+++ b/crypto/ts/ts_rsp_sign.c
@@ -298,7 +298,7 @@ int TS_RESP_CTX_set_status_info(TS_RESP_CTX *ctx,
}
if (text) {
if ((utf8_text = ASN1_UTF8STRING_new()) == NULL
- || !ASN1_STRING_set(utf8_text, text, (int)strlen(text))) {
+ || !ASN1_STRING_set_string(utf8_text, text)) {
ERR_raise(ERR_LIB_TS, ERR_R_ASN1_LIB);
goto err;
}
@@ -487,7 +487,7 @@ static int ts_RESP_check_request(TS_RESP_CTX *ctx)
return 0;
}
digest = msg_imprint->hashed_msg;
- if (ASN1_STRING_length(digest) != md_size) {
+ if (ASN1_STRING_length_ex(digest) != (size_t)md_size) {
TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
"Bad message digest.");
TS_RESP_CTX_add_failure_info(ctx, TS_INFO_BAD_DATA_FORMAT);
@@ -645,7 +645,7 @@ static int ossl_ess_add1_signing_cert(PKCS7_SIGNER_INFO *si,
p = pp;
i2d_ESS_SIGNING_CERT(sc, &p);
- if ((seq = ASN1_STRING_new()) == NULL || !ASN1_STRING_set(seq, pp, len)) {
+ if ((seq = ASN1_STRING_new()) == NULL || !ASN1_STRING_set_data(seq, pp, len)) {
ASN1_STRING_free(seq);
OPENSSL_free(pp);
return 0;
@@ -676,7 +676,7 @@ static int ossl_ess_add1_signing_cert_v2(PKCS7_SIGNER_INFO *si,
p = pp;
i2d_ESS_SIGNING_CERT_V2(sc, &p);
- if ((seq = ASN1_STRING_new()) == NULL || !ASN1_STRING_set(seq, pp, len)) {
+ if ((seq = ASN1_STRING_new()) == NULL || !ASN1_STRING_set_data(seq, pp, len)) {
ASN1_STRING_free(seq);
OPENSSL_free(pp);
return 0;
diff --git a/crypto/ts/ts_rsp_verify.c b/crypto/ts/ts_rsp_verify.c
index 1dc70c125b..1b45243ca8 100644
--- a/crypto/ts/ts_rsp_verify.c
+++ b/crypto/ts/ts_rsp_verify.c
@@ -207,24 +207,32 @@ static ESS_SIGNING_CERT *ossl_ess_get_signing_cert(const PKCS7_SIGNER_INFO *si)
{
const ASN1_TYPE *attr;
const unsigned char *p;
+ size_t len;
attr = PKCS7_get_signed_attribute(si, NID_id_smime_aa_signingCertificate);
if (attr == NULL || attr->type != V_ASN1_SEQUENCE)
return NULL;
p = ASN1_STRING_get0_data(attr->value.sequence);
- return d2i_ESS_SIGNING_CERT(NULL, &p, ASN1_STRING_length(attr->value.sequence));
+ len = ASN1_STRING_length_ex(attr->value.sequence);
+ if (len > INT_MAX)
+ return NULL;
+ return d2i_ESS_SIGNING_CERT(NULL, &p, (int)len);
}
static ESS_SIGNING_CERT_V2 *ossl_ess_get_signing_cert_v2(const PKCS7_SIGNER_INFO *si)
{
const ASN1_TYPE *attr;
const unsigned char *p;
+ size_t len;
attr = PKCS7_get_signed_attribute(si, NID_id_smime_aa_signingCertificateV2);
if (attr == NULL || attr->type != V_ASN1_SEQUENCE)
return NULL;
p = ASN1_STRING_get0_data(attr->value.sequence);
- return d2i_ESS_SIGNING_CERT_V2(NULL, &p, ASN1_STRING_length(attr->value.sequence));
+ len = ASN1_STRING_length_ex(attr->value.sequence);
+ if (len > INT_MAX)
+ return NULL;
+ return d2i_ESS_SIGNING_CERT_V2(NULL, &p, (int)len);
}
static int ts_check_signing_certs(const PKCS7_SIGNER_INFO *si,
@@ -482,6 +490,7 @@ static int ts_check_imprints(X509_ALGOR *algor_a,
TS_MSG_IMPRINT *b = tst_info->msg_imprint;
X509_ALGOR *algor_b = b->hash_algo;
int ret = 0;
+ size_t len;
if (algor_a) {
if (OBJ_cmp(algor_a->algorithm, algor_b->algorithm))
@@ -495,7 +504,11 @@ static int ts_check_imprints(X509_ALGOR *algor_a,
goto err;
}
- ret = len_a == (unsigned)ASN1_STRING_length(b->hashed_msg) && memcmp(imprint_a, ASN1_STRING_get0_data(b->hashed_msg), len_a) == 0;
+ len = ASN1_STRING_length_ex(b->hashed_msg);
+ if (len > INT_MAX)
+ goto err;
+
+ ret = len_a == (unsigned)len && memcmp(imprint_a, ASN1_STRING_get0_data(b->hashed_msg), len) == 0;
err:
if (!ret)
ERR_raise(ERR_LIB_TS, TS_R_MESSAGE_IMPRINT_MISMATCH);
diff --git a/crypto/ts/ts_verify_ctx.c b/crypto/ts/ts_verify_ctx.c
index ec9993ed9f..76835866d7 100644
--- a/crypto/ts/ts_verify_ctx.c
+++ b/crypto/ts/ts_verify_ctx.c
@@ -142,6 +142,7 @@ TS_VERIFY_CTX *TS_REQ_to_TS_VERIFY_CTX(TS_REQ *req, TS_VERIFY_CTX *ctx)
X509_ALGOR *md_alg;
ASN1_OCTET_STRING *msg;
const ASN1_INTEGER *nonce;
+ size_t tmp;
OPENSSL_assert(req != NULL);
if (ret)
@@ -162,8 +163,11 @@ TS_VERIFY_CTX *TS_REQ_to_TS_VERIFY_CTX(TS_REQ *req, TS_VERIFY_CTX *ctx)
if ((ret->md_alg = X509_ALGOR_dup(md_alg)) == NULL)
goto err;
msg = imprint->hashed_msg;
- ret->imprint_len = ASN1_STRING_length(msg);
- if (ret->imprint_len <= 0)
+ tmp = ASN1_STRING_length_ex(msg);
+ if (tmp > INT_MAX)
+ goto err;
+ ret->imprint_len = (unsigned int)tmp;
+ if (ret->imprint_len == 0)
goto err;
if ((ret->imprint = OPENSSL_malloc(ret->imprint_len)) == NULL)
goto err;
diff --git a/crypto/ui/ui_openssl.c b/crypto/ui/ui_openssl.c
index 1da5369287..5b97cc6448 100644
--- a/crypto/ui/ui_openssl.c
+++ b/crypto/ui/ui_openssl.c
@@ -60,11 +60,8 @@
#endif
#ifdef WIN_CONSOLE_BUG
-#include
-#ifndef OPENSSL_SYS_WINCE
#include
#endif
-#endif
/*
* There are 6 types of terminal interface supported, TERMIO, TERMIOS, VMS,
@@ -166,7 +163,7 @@ static long tty_orig[3], tty_new[3]; /* XXX Is there any guarantee that this
* structures? */
static long status;
static unsigned short channel = 0;
-#elif defined(_WIN32) && !defined(_WIN32_WCE)
+#elif defined(_WIN32)
static DWORD tty_orig, tty_new;
#else
#if !defined(OPENSSL_SYS_MSDOS) || defined(__DJGPP__)
@@ -177,12 +174,10 @@ static FILE *tty_in, *tty_out;
static int is_a_tty;
/* Declare static functions */
-#if !defined(OPENSSL_SYS_WINCE)
static int read_till_nl(FILE *);
static void recsig(int);
static void pushsig(void);
static void popsig(void);
-#endif
#if defined(OPENSSL_SYS_MSDOS) && !defined(_WIN32)
static int noecho_fgets(char *buf, int size, FILE *tty);
#endif
@@ -256,7 +251,6 @@ static int read_string(UI *ui, UI_STRING *uis)
return 1;
}
-#if !defined(OPENSSL_SYS_WINCE)
/* Internal functions to read a string without echoing */
static int read_till_nl(FILE *in)
{
@@ -271,7 +265,6 @@ static int read_till_nl(FILE *in)
}
static volatile sig_atomic_t intr_signal;
-#endif
static int read_string_inner(UI *ui, UI_STRING *uis, int echo, int strip_nl)
{
@@ -279,7 +272,6 @@ static int read_string_inner(UI *ui, UI_STRING *uis, int echo, int strip_nl)
int ok;
char result[BUFSIZ];
int maxsize = BUFSIZ - 1;
-#if !defined(OPENSSL_SYS_WINCE)
char *p = NULL;
int echo_eol = !echo;
@@ -359,9 +351,6 @@ error:
if (ps >= 1)
popsig();
-#else
- ok = 1;
-#endif
OPENSSL_cleanse(result, BUFSIZ);
return ok;
@@ -377,7 +366,7 @@ static int open_console(UI *ui)
#if defined(OPENSSL_SYS_VXWORKS)
tty_in = stdin;
tty_out = stderr;
-#elif defined(_WIN32) && !defined(_WIN32_WCE)
+#elif defined(_WIN32)
if ((tty_out = fopen("conout$", "w")) == NULL)
tty_out = stderr;
@@ -506,7 +495,7 @@ static int noecho_console(UI *ui)
}
}
#endif
-#if defined(_WIN32) && !defined(_WIN32_WCE)
+#if defined(_WIN32)
if (is_a_tty) {
tty_new = tty_orig;
tty_new &= ~ENABLE_ECHO_INPUT;
@@ -538,7 +527,7 @@ static int echo_console(UI *ui)
}
}
#endif
-#if defined(_WIN32) && !defined(_WIN32_WCE)
+#if defined(_WIN32)
if (is_a_tty) {
tty_new = tty_orig;
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), tty_new);
@@ -568,7 +557,6 @@ static int close_console(UI *ui)
return ret;
}
-#if !defined(OPENSSL_SYS_WINCE)
/* Internal functions to handle signals and act on them */
static void pushsig(void)
{
@@ -649,7 +637,6 @@ static void recsig(int i)
{
intr_signal = i;
}
-#endif
/* Internal functions specific for Windows */
#if defined(OPENSSL_SYS_MSDOS) && !defined(_WIN32)
diff --git a/crypto/whrlpool/wp_block.c b/crypto/whrlpool/wp_block.c
index 13b3f7b37f..62fa849dad 100644
--- a/crypto/whrlpool/wp_block.c
+++ b/crypto/whrlpool/wp_block.c
@@ -103,7 +103,7 @@ typedef uint64_t u64_aX;
#pragma intrinsic(_rotl64)
#define ROTATE(a, n) _rotl64((a), n)
#endif
-#elif defined(__GNUC__) && __GNUC__ >= 2
+#elif defined(__GNUC__)
#if defined(__x86_64) || defined(__x86_64__)
#if defined(L_ENDIAN)
#define ROTATE(a, n) ({ uint64_t ret; asm ("rolq %1,%0" \
diff --git a/crypto/x509/pcy_cache.c b/crypto/x509/pcy_cache.c
index d1ee35377b..bffa96fd6c 100644
--- a/crypto/x509/pcy_cache.c
+++ b/crypto/x509/pcy_cache.c
@@ -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/crypto/x509/t_x509.c b/crypto/x509/t_x509.c
index cf8062a902..abe1b7557d 100644
--- a/crypto/x509/t_x509.c
+++ b/crypto/x509/t_x509.c
@@ -244,7 +244,7 @@ int X509_ocspid_print(BIO *bp, const X509 *x)
goto err;
if (!EVP_Digest(ASN1_STRING_get0_data(keybstr),
- ASN1_STRING_length(keybstr), SHA1md, NULL, md, NULL))
+ ASN1_STRING_length_ex(keybstr), SHA1md, NULL, md, NULL))
goto err;
for (i = 0; i < SHA_DIGEST_LENGTH; i++) {
if (BIO_printf(bp, "%02X", SHA1md[i]) <= 0)
diff --git a/crypto/x509/v3_addr.c b/crypto/x509/v3_addr.c
index 1e0d94babf..e245e2b08a 100644
--- a/crypto/x509/v3_addr.c
+++ b/crypto/x509/v3_addr.c
@@ -409,6 +409,11 @@ static int make_addressPrefix(IPAddressOrRange **result, unsigned char *addr,
{
int bytelen = (prefixlen + 7) / 8, bitlen = prefixlen % 8;
IPAddressOrRange *aor;
+ unsigned char *prefix = NULL;
+ uint8_t unused_bits = 0;
+
+ if (bitlen > 0)
+ unused_bits = 8 - bitlen;
if (prefixlen < 0 || prefixlen > (afilen * 8))
return 0;
@@ -417,19 +422,23 @@ static int make_addressPrefix(IPAddressOrRange **result, unsigned char *addr,
aor->type = IPAddressOrRange_addressPrefix;
if (aor->u.addressPrefix == NULL && (aor->u.addressPrefix = ASN1_BIT_STRING_new()) == NULL)
goto err;
- /* BIT_STRING is a typedef of STRING
- * this function allows to set value without checking invalid bits
- * as they are nullified after setting */
- if (!ASN1_STRING_set(aor->u.addressPrefix, addr, bytelen))
+ if (bytelen > 0) {
+ prefix = OPENSSL_malloc(bytelen);
+ if (prefix == NULL)
+ goto err;
+ memcpy(prefix, addr, bytelen);
+ if (unused_bits)
+ prefix[bytelen - 1] &= ~(0xFF >> bitlen);
+ }
+ if (!ASN1_BIT_STRING_set1(aor->u.addressPrefix, prefix, bytelen, unused_bits))
goto err;
- if (bitlen > 0)
- aor->u.addressPrefix->data[bytelen - 1] &= ~(0xFF >> bitlen);
- ossl_asn1_bit_string_set_unused_bits(aor->u.addressPrefix, 8 - bitlen);
-
*result = aor;
+
+ OPENSSL_free(prefix);
return 1;
err:
+ OPENSSL_free(prefix);
IPAddressOrRange_free(aor);
return 0;
}
@@ -760,6 +769,7 @@ int X509v3_addr_is_canonical(IPAddrBlocks *addr)
aors = f->ipAddressChoice->u.addressesOrRanges;
if (sk_IPAddressOrRange_num(aors) == 0)
return 0;
+
for (j = 0; j < sk_IPAddressOrRange_num(aors) - 1; j++) {
IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, j);
IPAddressOrRange *b = sk_IPAddressOrRange_value(aors, j + 1);
@@ -814,78 +824,106 @@ int X509v3_addr_is_canonical(IPAddrBlocks *addr)
/*
* Whack an IPAddressOrRanges into canonical form.
+ *
+ * After the initial sort, the merge runs as a single linear sweep
+ * over the list using a write index. Adjacent entries are folded
+ * into the previous output by replacing it with a freshly built
+ * merged range; both old entries are then freed and the source slot
+ * is left NULL so the asn1 free machinery does not double-free on a
+ * subsequent abort. Total cost is O(N log N) sort + O(N) merge,
+ * with no stack deletes inside the loop.
*/
static int IPAddressOrRanges_canonize(IPAddressOrRanges *aors,
const unsigned afi)
{
- int i, j, length = length_from_afi(afi);
+ int length = length_from_afi(afi);
+ int read, write = 0, n;
- /*
- * Sort the IPAddressOrRanges sequence.
- */
sk_IPAddressOrRange_sort(aors);
+ n = sk_IPAddressOrRange_num(aors);
/*
- * Clean up representation issues, punt on duplicates or overlaps.
+ * Error paths below all `return 0` directly. Slots at
+ * [write..read-1] are NULL (from earlier iterations) and slots at
+ * [read..n-1] still hold their original entries; the caller's
+ * normal teardown walks the whole stack and frees each non-NULL
+ * slot safely, so leaving the stack in this mixed state is sound.
*/
- for (i = 0; i < sk_IPAddressOrRange_num(aors) - 1; i++) {
- IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, i);
- IPAddressOrRange *b = sk_IPAddressOrRange_value(aors, i + 1);
- unsigned char a_min[ADDR_RAW_BUF_LEN], a_max[ADDR_RAW_BUF_LEN];
- unsigned char b_min[ADDR_RAW_BUF_LEN], b_max[ADDR_RAW_BUF_LEN];
+ for (read = 0; read < n; read++) {
+ IPAddressOrRange *cur = sk_IPAddressOrRange_value(aors, read);
+ unsigned char c_min[ADDR_RAW_BUF_LEN], c_max[ADDR_RAW_BUF_LEN];
- if (!extract_min_max(a, a_min, a_max, length) || !extract_min_max(b, b_min, b_max, length))
+ if (!extract_min_max(cur, c_min, c_max, length))
return 0;
/*
- * Punt inverted ranges.
+ * Punt inverted range.
*/
- if (memcmp(a_min, a_max, length) > 0 || memcmp(b_min, b_max, length) > 0)
+ if (memcmp(c_min, c_max, length) > 0)
return 0;
- /*
- * Punt overlaps.
- */
- if (memcmp(a_max, b_min, length) >= 0)
- return 0;
+ if (write > 0) {
+ IPAddressOrRange *prev = sk_IPAddressOrRange_value(aors,
+ write - 1);
+ unsigned char p_min[ADDR_RAW_BUF_LEN], p_max[ADDR_RAW_BUF_LEN];
+ unsigned char c_min_minus_one[ADDR_RAW_BUF_LEN];
+ int j;
- /*
- * Merge if a and b are adjacent. We check for
- * adjacency by subtracting one from b_min first.
- */
- for (j = length - 1; j >= 0 && b_min[j]-- == 0x00; j--)
- ;
- if (memcmp(a_max, b_min, length) == 0) {
- IPAddressOrRange *merged;
-
- if (!make_addressRange(&merged, a_min, b_max, length))
+ if (!extract_min_max(prev, p_min, p_max, length))
return 0;
- (void)sk_IPAddressOrRange_set(aors, i, merged);
- (void)sk_IPAddressOrRange_delete(aors, i + 1);
- IPAddressOrRange_free(a);
- IPAddressOrRange_free(b);
- --i;
- continue;
+
+ /*
+ * Reject overlap with the previous accepted entry.
+ */
+ if (memcmp(p_max, c_min, length) >= 0)
+ return 0;
+
+ /*
+ * Adjacency test: does c_min - 1 equal p_max? Work on a
+ * scratch copy so the original c_min stays intact for use
+ * as the lower bound if we end up keeping cur.
+ */
+ memcpy(c_min_minus_one, c_min, length);
+ for (j = length - 1;
+ j >= 0 && c_min_minus_one[j]-- == 0x00;
+ j--)
+ ;
+ if (memcmp(p_max, c_min_minus_one, length) == 0) {
+ IPAddressOrRange *merged;
+
+ if (!make_addressRange(&merged, p_min, c_max, length))
+ return 0;
+ /*
+ * Replace prev with merged, free the originals, and
+ * NULL the source slot so the stack does not retain a
+ * second reference to cur.
+ */
+ (void)sk_IPAddressOrRange_set(aors, write - 1, merged);
+ IPAddressOrRange_free(prev);
+ IPAddressOrRange_free(cur);
+ (void)sk_IPAddressOrRange_set(aors, read, NULL);
+ continue;
+ }
}
+
+ /*
+ * Keep cur. Slide it forward into the write slot if we have
+ * fallen behind, and NULL the source slot to avoid duplicate
+ * ownership.
+ */
+ if (write != read) {
+ (void)sk_IPAddressOrRange_set(aors, write, cur);
+ (void)sk_IPAddressOrRange_set(aors, read, NULL);
+ }
+ write++;
}
/*
- * Check for inverted final range.
+ * Compaction succeeded: every slot at [write..n-1] is NULL, so
+ * popping the tail leaves the canonicalised list at [0..write-1].
*/
- j = sk_IPAddressOrRange_num(aors) - 1;
- {
- IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, j);
-
- if (a != NULL && a->type == IPAddressOrRange_addressRange) {
- unsigned char a_min[ADDR_RAW_BUF_LEN], a_max[ADDR_RAW_BUF_LEN];
-
- if (!extract_min_max(a, a_min, a_max, length))
- return 0;
- if (memcmp(a_min, a_max, length) > 0)
- return 0;
- }
- }
-
+ while (sk_IPAddressOrRange_num(aors) > write)
+ (void)sk_IPAddressOrRange_pop(aors);
return 1;
}
diff --git a/crypto/x509/v3_akid.c b/crypto/x509/v3_akid.c
index 9c93e88267..95b904c757 100644
--- a/crypto/x509/v3_akid.c
+++ b/crypto/x509/v3_akid.c
@@ -179,14 +179,14 @@ static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method,
/*
* The subject key identifier of the issuer cert is acceptable unless
* the issuer cert is same as subject cert, but the subject will not
- * not be self-signed (i.e. will be signed with a different key).
+ * be self-signed (i.e. will be signed with a different key).
*/
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);
/* Ignore empty keyids in the issuer cert */
- if (ASN1_STRING_length(ikeyid) == 0) {
+ if (ASN1_STRING_length_ex(ikeyid) == 0) {
ASN1_OCTET_STRING_free(ikeyid);
ikeyid = NULL;
}
diff --git a/crypto/x509/v3_asid.c b/crypto/x509/v3_asid.c
index 8470e0f134..c00ded15f9 100644
--- a/crypto/x509/v3_asid.c
+++ b/crypto/x509/v3_asid.c
@@ -347,13 +347,22 @@ int X509v3_asid_is_canonical(ASIdentifiers *asid)
/*
* Whack an ASIdentifierChoice into canonical form.
+ *
+ * After the initial sort, the merge runs as a single linear sweep
+ * over the list using a write index. Each entry is examined once;
+ * adjacent / mergeable entries extend the previous output's upper
+ * bound in O(1) and the source slot is left NULL so the asn1 free
+ * machinery does not double-free on a subsequent abort. Total cost
+ * is O(N log N) sort + O(N) merge, with no stack deletes inside the
+ * loop.
*/
static int ASIdentifierChoice_canonize(ASIdentifierChoice *choice)
{
ASN1_INTEGER *a_max_plus_one = NULL;
ASN1_INTEGER *orig;
BIGNUM *bn = NULL;
- int i, ret = 0;
+ int read, write = 0, n;
+ int ret = 0;
/*
* Nothing to do for empty element or inheritance.
@@ -370,112 +379,135 @@ static int ASIdentifierChoice_canonize(ASIdentifierChoice *choice)
}
/*
- * We have a non-empty list. Sort it.
+ * Sort the list, then merge in a single sweep using a write index.
*/
sk_ASIdOrRange_sort(choice->u.asIdsOrRanges);
+ n = sk_ASIdOrRange_num(choice->u.asIdsOrRanges);
- /*
- * Now check for errors and suboptimal encoding, rejecting the
- * former and fixing the latter.
- */
- for (i = 0; i < sk_ASIdOrRange_num(choice->u.asIdsOrRanges) - 1; i++) {
- ASIdOrRange *a = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i);
- ASIdOrRange *b = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i + 1);
- ASN1_INTEGER *a_min = NULL, *a_max = NULL, *b_min = NULL, *b_max = NULL;
+ for (read = 0; read < n; read++) {
+ ASIdOrRange *cur = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, read);
+ ASN1_INTEGER *c_min = NULL, *c_max = NULL;
- if (!extract_min_max(a, &a_min, &a_max)
- || !extract_min_max(b, &b_min, &b_max))
+ if (!extract_min_max(cur, &c_min, &c_max))
goto done;
/*
- * Make sure we're properly sorted (paranoia).
+ * Punt inverted range.
*/
- if (!ossl_assert(ASN1_INTEGER_cmp(a_min, b_min) <= 0))
+ if (ASN1_INTEGER_cmp(c_min, c_max) > 0)
goto done;
- /*
- * Punt inverted ranges.
- */
- if (ASN1_INTEGER_cmp(a_min, a_max) > 0 || ASN1_INTEGER_cmp(b_min, b_max) > 0)
- goto done;
+ if (write > 0) {
+ ASIdOrRange *prev = sk_ASIdOrRange_value(choice->u.asIdsOrRanges,
+ write - 1);
+ ASN1_INTEGER *p_min = NULL, *p_max = NULL;
- /*
- * Check for overlaps.
- */
- if (ASN1_INTEGER_cmp(a_max, b_min) >= 0) {
- ERR_raise(ERR_LIB_X509V3, X509V3_R_EXTENSION_VALUE_ERROR);
- goto done;
- }
-
- /*
- * Calculate a_max + 1 to check for adjacency.
- */
- if ((bn == NULL && (bn = BN_new()) == NULL) || ASN1_INTEGER_to_BN(a_max, bn) == NULL || !BN_add_word(bn, 1)) {
- ERR_raise(ERR_LIB_X509V3, ERR_R_BN_LIB);
- goto done;
- }
-
- if ((a_max_plus_one = BN_to_ASN1_INTEGER(bn, orig = a_max_plus_one)) == NULL) {
- a_max_plus_one = orig;
- ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
- goto done;
- }
-
- /*
- * If a and b are adjacent, merge them.
- */
- if (ASN1_INTEGER_cmp(a_max_plus_one, b_min) == 0) {
- ASRange *r;
- switch (a->type) {
- case ASIdOrRange_id:
- if ((r = OPENSSL_malloc(sizeof(*r))) == NULL)
- goto done;
- r->min = a_min;
- r->max = b_max;
- a->type = ASIdOrRange_range;
- a->u.range = r;
- break;
- case ASIdOrRange_range:
- ASN1_INTEGER_free(a->u.range->max);
- a->u.range->max = b_max;
- break;
- }
- switch (b->type) {
- case ASIdOrRange_id:
- b->u.id = NULL;
- break;
- case ASIdOrRange_range:
- b->u.range->max = NULL;
- break;
- }
- ASIdOrRange_free(b);
- (void)sk_ASIdOrRange_delete(choice->u.asIdsOrRanges, i + 1);
- i--;
- continue;
- }
- }
-
- /*
- * Check for final inverted range.
- */
- i = sk_ASIdOrRange_num(choice->u.asIdsOrRanges) - 1;
- {
- ASIdOrRange *a = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i);
- ASN1_INTEGER *a_min, *a_max;
- if (a != NULL && a->type == ASIdOrRange_range) {
- if (!extract_min_max(a, &a_min, &a_max)
- || ASN1_INTEGER_cmp(a_min, a_max) > 0)
+ if (!extract_min_max(prev, &p_min, &p_max))
goto done;
- }
- }
- /* Paranoia */
- if (!ossl_assert(ASIdentifierChoice_is_canonical(choice)))
- goto done;
+ /*
+ * Make sure we're properly sorted (paranoia).
+ */
+ if (!ossl_assert(ASN1_INTEGER_cmp(p_min, c_min) <= 0))
+ goto done;
+
+ /*
+ * Reject overlap with the previous accepted entry.
+ */
+ if (ASN1_INTEGER_cmp(p_max, c_min) >= 0) {
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_EXTENSION_VALUE_ERROR);
+ goto done;
+ }
+
+ /*
+ * Calculate p_max + 1 to check for adjacency.
+ */
+ if ((bn == NULL && (bn = BN_new()) == NULL)
+ || ASN1_INTEGER_to_BN(p_max, bn) == NULL
+ || !BN_add_word(bn, 1)) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_BN_LIB);
+ goto done;
+ }
+ if ((a_max_plus_one = BN_to_ASN1_INTEGER(bn,
+ orig = a_max_plus_one))
+ == NULL) {
+ a_max_plus_one = orig;
+ ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
+ goto done;
+ }
+
+ /*
+ * If prev and cur are adjacent, fold cur into prev.
+ */
+ if (ASN1_INTEGER_cmp(a_max_plus_one, c_min) == 0) {
+ ASRange *r;
+
+ switch (prev->type) {
+ case ASIdOrRange_id:
+ if ((r = OPENSSL_malloc(sizeof(*r))) == NULL)
+ goto done;
+ r->min = p_min;
+ r->max = c_max;
+ prev->type = ASIdOrRange_range;
+ prev->u.range = r;
+ break;
+ case ASIdOrRange_range:
+ ASN1_INTEGER_free(prev->u.range->max);
+ prev->u.range->max = c_max;
+ break;
+ }
+ /*
+ * Detach c_max from cur so freeing cur does not free
+ * the value we just transferred to prev.
+ */
+ switch (cur->type) {
+ case ASIdOrRange_id:
+ cur->u.id = NULL;
+ break;
+ case ASIdOrRange_range:
+ cur->u.range->max = NULL;
+ break;
+ }
+ ASIdOrRange_free(cur);
+ /*
+ * NULL the source slot so any later teardown does not
+ * walk a freed pointer. We do not advance `write`.
+ */
+ (void)sk_ASIdOrRange_set(choice->u.asIdsOrRanges, read, NULL);
+ continue;
+ }
+ }
+
+ /*
+ * Keep cur. Slide it forward into the write slot if we have
+ * fallen behind, and NULL the source slot to avoid duplicate
+ * ownership.
+ */
+ if (write != read) {
+ (void)sk_ASIdOrRange_set(choice->u.asIdsOrRanges, write, cur);
+ (void)sk_ASIdOrRange_set(choice->u.asIdsOrRanges, read, NULL);
+ }
+ write++;
+ }
ret = 1;
done:
+ /*
+ * On success every slot at [write..n-1] is NULL, so popping the
+ * tail leaves the canonicalised list at [0..write-1]. On error we
+ * leave the tail untouched; the slots are either NULL (from earlier
+ * iterations) or original entries the loop never reached, both of
+ * which the caller's ASIdentifierChoice_free path handles safely.
+ */
+ if (ret) {
+ while (sk_ASIdOrRange_num(choice->u.asIdsOrRanges) > write)
+ (void)sk_ASIdOrRange_pop(choice->u.asIdsOrRanges);
+ /* Paranoia */
+ if (!ossl_assert(ASIdentifierChoice_is_canonical(choice)))
+ ret = 0;
+ }
+
ASN1_INTEGER_free(a_max_plus_one);
BN_free(bn);
return ret;
diff --git a/crypto/x509/v3_bitst.c b/crypto/x509/v3_bitst.c
index 89c3deddd3..1b0204bf75 100644
--- a/crypto/x509/v3_bitst.c
+++ b/crypto/x509/v3_bitst.c
@@ -52,7 +52,7 @@ STACK_OF(CONF_VALUE) *i2v_ASN1_BIT_STRING(X509V3_EXT_METHOD *method,
for (bnam = method->usr_data; bnam->lname; bnam++) {
/*
* If the bitnumber did not change from the last iteration, this entry
- * is an an alias for the previous bit; treat the first result as
+ * is an alias for the previous bit; treat the first result as
* canonical and ignore the rest.
*/
if (last_seen_bit == bnam->bitnum)
diff --git a/crypto/x509/v3_cpols.c b/crypto/x509/v3_cpols.c
index 0dc8f76ad4..2cc71f567b 100644
--- a/crypto/x509/v3_cpols.c
+++ b/crypto/x509/v3_cpols.c
@@ -208,8 +208,7 @@ static POLICYINFO *policy_section(X509V3_CTX *ctx,
ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
goto err;
}
- if (!ASN1_STRING_set(qual->d.cpsuri, cnf->value,
- (int)strlen(cnf->value))) {
+ if (!ASN1_STRING_set_string(qual->d.cpsuri, cnf->value)) {
ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
goto err;
}
@@ -325,7 +324,7 @@ static POLICYQUALINFO *notice_section(X509V3_CTX *ctx,
if (tag_len != 0)
value += tag_len + 1;
len = (int)strlen(value);
- if (!ASN1_STRING_set(not->exptext, value, len)) {
+ if (!ASN1_STRING_set_data(not->exptext, (uint8_t *)value, len)) {
ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
goto err;
}
@@ -344,8 +343,7 @@ static POLICYQUALINFO *notice_section(X509V3_CTX *ctx,
nref->organization->type = V_ASN1_IA5STRING;
else
nref->organization->type = V_ASN1_VISIBLESTRING;
- if (!ASN1_STRING_set(nref->organization, cnf->value,
- (int)strlen(cnf->value))) {
+ if (!ASN1_STRING_set_string(nref->organization, cnf->value)) {
ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
goto err;
}
diff --git a/crypto/x509/v3_genn.c b/crypto/x509/v3_genn.c
index d63168a77a..23a2435842 100644
--- a/crypto/x509/v3_genn.c
+++ b/crypto/x509/v3_genn.c
@@ -49,13 +49,7 @@ ASN1_ITEM_TEMPLATE(GENERAL_NAMES) = ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF,
ASN1_ITEM_TEMPLATE_END(GENERAL_NAMES)
IMPLEMENT_ASN1_FUNCTIONS(GENERAL_NAMES)
-
-GENERAL_NAME *GENERAL_NAME_dup(const GENERAL_NAME *a)
-{
- return (GENERAL_NAME *)ASN1_dup((i2d_of_void *)i2d_GENERAL_NAME,
- (d2i_of_void *)d2i_GENERAL_NAME,
- (char *)a);
-}
+IMPLEMENT_ASN1_DUP_FUNCTION(GENERAL_NAME)
int GENERAL_NAME_set1_X509_NAME(GENERAL_NAME **tgt, const X509_NAME *src)
{
diff --git a/crypto/x509/v3_ia5.c b/crypto/x509/v3_ia5.c
index 539c43a141..a8fa52a439 100644
--- a/crypto/x509/v3_ia5.c
+++ b/crypto/x509/v3_ia5.c
@@ -52,7 +52,7 @@ ASN1_IA5STRING *s2i_ASN1_IA5STRING(X509V3_EXT_METHOD *method,
ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
return NULL;
}
- if (!ASN1_STRING_set((ASN1_STRING *)ia5, str, (int)strlen(str))) {
+ if (!ASN1_STRING_set_string((ASN1_STRING *)ia5, str)) {
ASN1_IA5STRING_free(ia5);
return NULL;
}
diff --git a/crypto/x509/v3_ist.c b/crypto/x509/v3_ist.c
index 0409b52d60..a4d3437192 100644
--- a/crypto/x509/v3_ist.c
+++ b/crypto/x509/v3_ist.c
@@ -52,28 +52,28 @@ static ISSUER_SIGN_TOOL *v2i_issuer_sign_tool(X509V3_EXT_METHOD *method, X509V3_
if (strcmp(cnf->name, "signTool") == 0) {
if (ist->signTool == NULL
|| cnf->value == NULL
- || !ASN1_STRING_set(ist->signTool, cnf->value, (int)strlen(cnf->value))) {
+ || !ASN1_STRING_set_string(ist->signTool, cnf->value)) {
ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
goto err;
}
} else if (strcmp(cnf->name, "cATool") == 0) {
if (ist->cATool == NULL
|| cnf->value == NULL
- || !ASN1_STRING_set(ist->cATool, cnf->value, (int)strlen(cnf->value))) {
+ || !ASN1_STRING_set_string(ist->cATool, cnf->value)) {
ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
goto err;
}
} else if (strcmp(cnf->name, "signToolCert") == 0) {
if (ist->signToolCert == NULL
|| cnf->value == NULL
- || !ASN1_STRING_set(ist->signToolCert, cnf->value, (int)strlen(cnf->value))) {
+ || !ASN1_STRING_set_string(ist->signToolCert, cnf->value)) {
ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
goto err;
}
} else if (strcmp(cnf->name, "cAToolCert") == 0) {
if (ist->cAToolCert == NULL
|| cnf->value == NULL
- || !ASN1_STRING_set(ist->cAToolCert, cnf->value, (int)strlen(cnf->value))) {
+ || !ASN1_STRING_set_string(ist->cAToolCert, cnf->value)) {
ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
goto err;
}
diff --git a/crypto/x509/v3_lib.c b/crypto/x509/v3_lib.c
index aee7ad119f..a099177dba 100644
--- a/crypto/x509/v3_lib.c
+++ b/crypto/x509/v3_lib.c
@@ -169,16 +169,18 @@ void *X509V3_EXT_d2i(const X509_EXTENSION *ext)
const X509V3_EXT_METHOD *method;
const unsigned char *p;
const ASN1_STRING *extvalue;
- int extlen;
+ size_t extlen;
if ((method = X509V3_EXT_get(ext)) == NULL)
return NULL;
extvalue = X509_EXTENSION_get_data(ext);
p = ASN1_STRING_get0_data(extvalue);
- extlen = ASN1_STRING_length(extvalue);
+ extlen = ASN1_STRING_length_ex(extvalue);
+ if (extlen > INT_MAX)
+ return NULL;
if (method->it)
- return ASN1_item_d2i(NULL, &p, extlen, ASN1_ITEM_ptr(method->it));
- return method->d2i(NULL, &p, extlen);
+ return ASN1_item_d2i(NULL, &p, (int)extlen, ASN1_ITEM_ptr(method->it));
+ return method->d2i(NULL, &p, (int)extlen);
}
/*-
diff --git a/crypto/x509/v3_ncons.c b/crypto/x509/v3_ncons.c
index 1a9cf61122..5f2710e9f5 100644
--- a/crypto/x509/v3_ncons.c
+++ b/crypto/x509/v3_ncons.c
@@ -615,6 +615,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;
@@ -791,6 +797,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/crypto/x509/v3_prn.c b/crypto/x509/v3_prn.c
index 4a0df33ea3..0fb7c9e38a 100644
--- a/crypto/x509/v3_prn.c
+++ b/crypto/x509/v3_prn.c
@@ -73,24 +73,26 @@ int X509V3_EXT_print(BIO *out, const X509_EXTENSION *ext, unsigned long flag,
char *value = NULL;
const ASN1_OCTET_STRING *extoct;
const unsigned char *p;
- int extlen;
+ size_t extlen;
const X509V3_EXT_METHOD *method;
STACK_OF(CONF_VALUE) *nval = NULL;
int ok = 1;
extoct = X509_EXTENSION_get_data(ext);
p = ASN1_STRING_get0_data(extoct);
- extlen = ASN1_STRING_length(extoct);
+ extlen = ASN1_STRING_length_ex(extoct);
+ if (extlen > INT_MAX)
+ return 0;
if ((method = X509V3_EXT_get(ext)) == NULL)
- return unknown_ext_print(out, p, extlen, flag, indent, 0);
+ return unknown_ext_print(out, p, (int)extlen, flag, indent, 0);
if (method->it)
- ext_str = ASN1_item_d2i(NULL, &p, extlen, ASN1_ITEM_ptr(method->it));
+ ext_str = ASN1_item_d2i(NULL, &p, (int)extlen, ASN1_ITEM_ptr(method->it));
else
- ext_str = method->d2i(NULL, &p, extlen);
+ ext_str = method->d2i(NULL, &p, (int)extlen);
if (!ext_str)
- return unknown_ext_print(out, p, extlen, flag, indent, 1);
+ return unknown_ext_print(out, p, (int)extlen, flag, indent, 1);
if (method->i2s) {
if ((value = method->i2s(method, ext_str)) == NULL) {
diff --git a/crypto/x509/v3_san.c b/crypto/x509/v3_san.c
index 0f12939d6d..f1b028f78c 100644
--- a/crypto/x509/v3_san.c
+++ b/crypto/x509/v3_san.c
@@ -575,7 +575,8 @@ GENERAL_NAME *a2i_GENERAL_NAME(GENERAL_NAME *out,
}
if (is_string) {
- if ((gen->d.ia5 = ASN1_IA5STRING_new()) == NULL || !ASN1_STRING_set(gen->d.ia5, (unsigned char *)value, (int)strlen(value))) {
+ if ((gen->d.ia5 = ASN1_IA5STRING_new()) == NULL
+ || !ASN1_STRING_set_string(gen->d.ia5, value)) {
ASN1_IA5STRING_free(gen->d.ia5);
gen->d.ia5 = NULL;
ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
diff --git a/crypto/x509/v3_utf8.c b/crypto/x509/v3_utf8.c
index 49095ffdd9..dc7c86fb7f 100644
--- a/crypto/x509/v3_utf8.c
+++ b/crypto/x509/v3_utf8.c
@@ -55,7 +55,7 @@ ASN1_UTF8STRING *s2i_ASN1_UTF8STRING(X509V3_EXT_METHOD *method,
ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
return NULL;
}
- if (!ASN1_STRING_set((ASN1_STRING *)utf8, str, (int)strlen(str))) {
+ if (!ASN1_STRING_set_string(utf8, str)) {
ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
ASN1_UTF8STRING_free(utf8);
return NULL;
diff --git a/crypto/x509/x509_att.c b/crypto/x509/x509_att.c
index ee631db75a..e08e490274 100644
--- a/crypto/x509/x509_att.c
+++ b/crypto/x509/x509_att.c
@@ -365,7 +365,7 @@ int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype,
atype = stmp->type;
} else if (len != -1) {
if ((stmp = ASN1_STRING_type_new(attrtype)) == NULL
- || !ASN1_STRING_set(stmp, data, len)) {
+ || !ASN1_STRING_set_data(stmp, data, len)) {
ERR_raise(ERR_LIB_X509, ERR_R_ASN1_LIB);
goto err;
}
diff --git a/crypto/x509/x509_ext.c b/crypto/x509/x509_ext.c
index 3cd4ac51fc..8c9c5d96bc 100644
--- a/crypto/x509/x509_ext.c
+++ b/crypto/x509/x509_ext.c
@@ -84,7 +84,7 @@ int X509_get_ext_by_OBJ(const X509 *x, const ASN1_OBJECT *obj, int lastpos)
int X509_get_ext_by_critical(const X509 *x, int crit, int lastpos)
{
- return (X509v3_get_ext_by_critical(x->cert_info.extensions, crit, lastpos));
+ return X509v3_get_ext_by_critical(x->cert_info.extensions, crit, lastpos);
}
const X509_EXTENSION *X509_get_ext(const X509 *x, int loc)
diff --git a/crypto/x509/x509_lu.c b/crypto/x509/x509_lu.c
index e9cc7145e3..5be50c2195 100644
--- a/crypto/x509/x509_lu.c
+++ b/crypto/x509/x509_lu.c
@@ -287,7 +287,7 @@ int X509_STORE_up_ref(X509_STORE *xs)
{
int i;
- if (CRYPTO_UP_REF(&xs->references, &i) <= 0)
+ if (!CRYPTO_UP_REF(&xs->references, &i))
return 0;
REF_PRINT_COUNT("X509_STORE", i, xs);
@@ -741,7 +741,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;
}
@@ -764,6 +769,7 @@ static int obj_ht_foreach_object(HT_VALUE *v, void *arg)
return 1;
err:
+ X509_OBJECT_free(dup);
sk_X509_OBJECT_pop_free(*sk, X509_OBJECT_free);
*sk = NULL;
diff --git a/crypto/x509/x509_set.c b/crypto/x509/x509_set.c
index 8a2a12e4b6..11439bcafb 100644
--- a/crypto/x509/x509_set.c
+++ b/crypto/x509/x509_set.c
@@ -117,7 +117,7 @@ int X509_up_ref(X509 *x)
{
int i;
- if (CRYPTO_UP_REF(&x->references, &i) <= 0)
+ if (!CRYPTO_UP_REF(&x->references, &i))
return 0;
REF_PRINT_COUNT("X509", i, x);
diff --git a/crypto/x509/x509_vpm.c b/crypto/x509/x509_vpm.c
index f0858e357e..44b116923b 100644
--- a/crypto/x509/x509_vpm.c
+++ b/crypto/x509/x509_vpm.c
@@ -35,7 +35,7 @@ static X509_BUFFER *buffer_from_bytes(const uint8_t *bytes, size_t length)
{
X509_BUFFER *buf;
- if ((buf = OPENSSL_zalloc(sizeof *buf)) != NULL
+ if ((buf = OPENSSL_zalloc(sizeof(*buf))) != NULL
&& (buf->data = OPENSSL_memdup(bytes, length)) != NULL) {
buf->len = length;
} else {
@@ -56,7 +56,7 @@ static X509_BUFFER *buffer_from_string(const uint8_t *bytes, size_t length)
X509_BUFFER *buf, *ret = NULL;
uint8_t *data = NULL;
- if ((buf = OPENSSL_zalloc(sizeof *buf)) == NULL)
+ if ((buf = OPENSSL_zalloc(sizeof(*buf))) == NULL)
goto err;
if ((data = (uint8_t *)OPENSSL_strndup((char *)bytes, length)) == NULL)
diff --git a/crypto/x509/x509cset.c b/crypto/x509/x509cset.c
index 20de6a340e..ec3e1f5360 100644
--- a/crypto/x509/x509cset.c
+++ b/crypto/x509/x509cset.c
@@ -75,7 +75,7 @@ int X509_CRL_up_ref(X509_CRL *crl)
{
int i;
- if (CRYPTO_UP_REF(&crl->references, &i) <= 0)
+ if (!CRYPTO_UP_REF(&crl->references, &i))
return 0;
REF_PRINT_COUNT("X509_CRL", i, crl);
diff --git a/crypto/x509/x509name.c b/crypto/x509/x509name.c
index ebd58a2012..58167d9a78 100644
--- a/crypto/x509/x509name.c
+++ b/crypto/x509/x509name.c
@@ -332,9 +332,12 @@ int X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *ne, int type,
OBJ_obj2nid(ne->object))
? 1
: 0;
- if (len < 0)
- len = (int)strlen((const char *)bytes);
- i = ASN1_STRING_set(ne->value, bytes, len);
+ if (len < -1)
+ return 0;
+ if (len == -1)
+ i = ASN1_STRING_set_string(ne->value, (const char *)bytes);
+ else
+ i = ASN1_STRING_set_data(ne->value, bytes, (size_t)len);
if (!i)
return 0;
if (type != V_ASN1_UNDEF) {
diff --git a/crypto/x509/x_all.c b/crypto/x509/x_all.c
index 2659886748..ef16a7fc88 100644
--- a/crypto/x509/x_all.c
+++ b/crypto/x509/x_all.c
@@ -32,6 +32,103 @@
#include "crypto/rsa.h"
#include "x509_local.h"
+static void *RSA_new_thunk(void)
+{
+ return RSA_new();
+}
+
+static void *d2i_RSA_PUBKEY_thunk(void **a, const unsigned char **in, long len)
+{
+ return d2i_RSA_PUBKEY((RSA **)a, in, len);
+}
+
+static int i2d_RSA_PUBKEY_thunk(const void *a, unsigned char **out)
+{
+ return i2d_RSA_PUBKEY((const RSA *)a, out);
+}
+
+static void *EVP_PKEY_new_thunk(void)
+{
+ return EVP_PKEY_new();
+}
+
+static void *d2i_AutoPrivateKey_thunk(void **a, const unsigned char **in,
+ long len)
+{
+ return d2i_AutoPrivateKey((EVP_PKEY **)a, in, len);
+}
+
+static void *d2i_PUBKEY_thunk(void **a, const unsigned char **in, long len)
+{
+ return d2i_PUBKEY((EVP_PKEY **)a, in, len);
+}
+
+static int i2d_PrivateKey_thunk(const void *a, unsigned char **out)
+{
+ return i2d_PrivateKey((const EVP_PKEY *)a, out);
+}
+
+static int i2d_PUBKEY_thunk(const void *a, unsigned char **out)
+{
+ return i2d_PUBKEY((const EVP_PKEY *)a, out);
+}
+
+#ifndef OPENSSL_NO_DSA
+static void *DSA_new_thunk(void)
+{
+ return DSA_new();
+}
+
+static void *d2i_DSAPrivateKey_thunk(void **a, const unsigned char **in,
+ long len)
+{
+ return d2i_DSAPrivateKey((DSA **)a, in, len);
+}
+
+static int i2d_DSAPrivateKey_thunk(const void *a, unsigned char **out)
+{
+ return i2d_DSAPrivateKey((const DSA *)a, out);
+}
+
+static void *d2i_DSA_PUBKEY_thunk(void **a, const unsigned char **in, long len)
+{
+ return d2i_DSA_PUBKEY((DSA **)a, in, len);
+}
+
+static int i2d_DSA_PUBKEY_thunk(const void *a, unsigned char **out)
+{
+ return i2d_DSA_PUBKEY((const DSA *)a, out);
+}
+#endif
+
+#ifndef OPENSSL_NO_EC
+static void *EC_KEY_new_thunk(void)
+{
+ return EC_KEY_new();
+}
+
+static void *d2i_EC_PUBKEY_thunk(void **a, const unsigned char **in, long len)
+{
+ return d2i_EC_PUBKEY((EC_KEY **)a, in, len);
+}
+
+static int i2d_EC_PUBKEY_thunk(const void *a, unsigned char **out)
+{
+ return i2d_EC_PUBKEY((const EC_KEY *)a, out);
+}
+
+static void *d2i_ECPrivateKey_thunk(void **a, const unsigned char **in,
+ long len)
+{
+ return d2i_ECPrivateKey((EC_KEY **)a, in, len);
+}
+
+static int i2d_ECPrivateKey_thunk(const void *a, unsigned char **out)
+{
+ return i2d_ECPrivateKey((const EC_KEY *)a, out);
+}
+#endif
+
int X509_verify(const X509 *a, EVP_PKEY *r)
{
if (X509_ALGOR_cmp(&a->sig_alg, &a->cert_info.signature) != 0)
@@ -390,10 +487,8 @@ RSA *d2i_RSAPublicKey_fp(FILE *fp, RSA **rsa)
RSA *d2i_RSA_PUBKEY_fp(FILE *fp, RSA **rsa)
{
- return ASN1_d2i_fp((void *(*)(void))
- RSA_new,
- (D2I_OF(void))d2i_RSA_PUBKEY, fp,
- (void **)rsa);
+ return ASN1_d2i_fp(RSA_new_thunk, d2i_RSA_PUBKEY_thunk, fp,
+ CHECKED_PPTR_OF(RSA, rsa));
}
int i2d_RSAPublicKey_fp(FILE *fp, const RSA *rsa)
@@ -403,7 +498,7 @@ int i2d_RSAPublicKey_fp(FILE *fp, const RSA *rsa)
int i2d_RSA_PUBKEY_fp(FILE *fp, const RSA *rsa)
{
- return ASN1_i2d_fp((I2D_OF(void))i2d_RSA_PUBKEY, fp, rsa);
+ return ASN1_i2d_fp(i2d_RSA_PUBKEY_thunk, fp, rsa);
}
#endif
@@ -424,7 +519,8 @@ RSA *d2i_RSAPublicKey_bio(BIO *bp, RSA **rsa)
RSA *d2i_RSA_PUBKEY_bio(BIO *bp, RSA **rsa)
{
- return ASN1_d2i_bio_of(RSA, RSA_new, d2i_RSA_PUBKEY, bp, rsa);
+ return ASN1_d2i_bio(RSA_new_thunk, d2i_RSA_PUBKEY_thunk, bp,
+ CHECKED_PPTR_OF(RSA, rsa));
}
int i2d_RSAPublicKey_bio(BIO *bp, const RSA *rsa)
@@ -434,50 +530,55 @@ int i2d_RSAPublicKey_bio(BIO *bp, const RSA *rsa)
int i2d_RSA_PUBKEY_bio(BIO *bp, const RSA *rsa)
{
- return ASN1_i2d_bio_of(RSA, i2d_RSA_PUBKEY, bp, rsa);
+ return ASN1_i2d_bio(i2d_RSA_PUBKEY_thunk, bp, rsa);
}
#ifndef OPENSSL_NO_DSA
#ifndef OPENSSL_NO_STDIO
DSA *d2i_DSAPrivateKey_fp(FILE *fp, DSA **dsa)
{
- return ASN1_d2i_fp_of(DSA, DSA_new, d2i_DSAPrivateKey, fp, dsa);
+ return ASN1_d2i_fp(DSA_new_thunk, d2i_DSAPrivateKey_thunk, fp,
+ CHECKED_PPTR_OF(DSA, dsa));
}
int i2d_DSAPrivateKey_fp(FILE *fp, const DSA *dsa)
{
- return ASN1_i2d_fp_of(DSA, i2d_DSAPrivateKey, fp, dsa);
+ return ASN1_i2d_fp(i2d_DSAPrivateKey_thunk, fp,
+ CHECKED_PTR_OF(const DSA, dsa));
}
DSA *d2i_DSA_PUBKEY_fp(FILE *fp, DSA **dsa)
{
- return ASN1_d2i_fp_of(DSA, DSA_new, d2i_DSA_PUBKEY, fp, dsa);
+ return ASN1_d2i_fp(DSA_new_thunk, d2i_DSA_PUBKEY_thunk, fp,
+ CHECKED_PPTR_OF(DSA, dsa));
}
int i2d_DSA_PUBKEY_fp(FILE *fp, const DSA *dsa)
{
- return ASN1_i2d_fp_of(DSA, i2d_DSA_PUBKEY, fp, dsa);
+ return ASN1_i2d_fp(i2d_DSA_PUBKEY_thunk, fp,
+ CHECKED_PTR_OF(const DSA, dsa));
}
#endif
DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa)
{
- return ASN1_d2i_bio_of(DSA, DSA_new, d2i_DSAPrivateKey, bp, dsa);
+ return ASN1_d2i_bio(DSA_new_thunk, d2i_DSAPrivateKey_thunk, bp, (void **)dsa);
}
int i2d_DSAPrivateKey_bio(BIO *bp, const DSA *dsa)
{
- return ASN1_i2d_bio_of(DSA, i2d_DSAPrivateKey, bp, dsa);
+ return ASN1_i2d_bio(i2d_DSAPrivateKey_thunk, bp,
+ CHECKED_PTR_OF(const DSA, dsa));
}
DSA *d2i_DSA_PUBKEY_bio(BIO *bp, DSA **dsa)
{
- return ASN1_d2i_bio_of(DSA, DSA_new, d2i_DSA_PUBKEY, bp, dsa);
+ return ASN1_d2i_bio(DSA_new_thunk, d2i_DSA_PUBKEY_thunk, bp, (void **)dsa);
}
int i2d_DSA_PUBKEY_bio(BIO *bp, const DSA *dsa)
{
- return ASN1_i2d_bio_of(DSA, i2d_DSA_PUBKEY, bp, dsa);
+ return ASN1_i2d_bio(i2d_DSA_PUBKEY_thunk, bp, dsa);
}
#endif
@@ -486,42 +587,49 @@ int i2d_DSA_PUBKEY_bio(BIO *bp, const DSA *dsa)
#ifndef OPENSSL_NO_STDIO
EC_KEY *d2i_EC_PUBKEY_fp(FILE *fp, EC_KEY **eckey)
{
- return ASN1_d2i_fp_of(EC_KEY, EC_KEY_new, d2i_EC_PUBKEY, fp, eckey);
+ return ASN1_d2i_fp(EC_KEY_new_thunk, d2i_EC_PUBKEY_thunk, fp,
+ CHECKED_PPTR_OF(EC_KEY, eckey));
}
int i2d_EC_PUBKEY_fp(FILE *fp, const EC_KEY *eckey)
{
- return ASN1_i2d_fp_of(EC_KEY, i2d_EC_PUBKEY, fp, eckey);
+ return ASN1_i2d_fp(i2d_EC_PUBKEY_thunk, fp, CHECKED_PTR_OF(const EC_KEY, eckey));
}
EC_KEY *d2i_ECPrivateKey_fp(FILE *fp, EC_KEY **eckey)
{
- return ASN1_d2i_fp_of(EC_KEY, EC_KEY_new, d2i_ECPrivateKey, fp, eckey);
+ return ASN1_d2i_fp(EC_KEY_new_thunk, d2i_ECPrivateKey_thunk, fp,
+ CHECKED_PPTR_OF(EC_KEY, eckey));
}
int i2d_ECPrivateKey_fp(FILE *fp, const EC_KEY *eckey)
{
- return ASN1_i2d_fp_of(EC_KEY, i2d_ECPrivateKey, fp, eckey);
+ return ASN1_i2d_fp(i2d_ECPrivateKey_thunk, fp,
+ CHECKED_PTR_OF(const EC_KEY, eckey));
}
#endif
EC_KEY *d2i_EC_PUBKEY_bio(BIO *bp, EC_KEY **eckey)
{
- return ASN1_d2i_bio_of(EC_KEY, EC_KEY_new, d2i_EC_PUBKEY, bp, eckey);
+ return ASN1_d2i_bio(EC_KEY_new_thunk, d2i_EC_PUBKEY_thunk, bp,
+ CHECKED_PPTR_OF(EC_KEY, eckey));
}
int i2d_EC_PUBKEY_bio(BIO *bp, const EC_KEY *ecdsa)
{
- return ASN1_i2d_bio_of(EC_KEY, i2d_EC_PUBKEY, bp, ecdsa);
+ return ASN1_i2d_bio(i2d_EC_PUBKEY_thunk, bp,
+ CHECKED_PTR_OF(const EC_KEY, ecdsa));
}
EC_KEY *d2i_ECPrivateKey_bio(BIO *bp, EC_KEY **eckey)
{
- return ASN1_d2i_bio_of(EC_KEY, EC_KEY_new, d2i_ECPrivateKey, bp, eckey);
+ return ASN1_d2i_bio(EC_KEY_new_thunk, d2i_ECPrivateKey_thunk, bp,
+ CHECKED_PPTR_OF(EC_KEY, eckey));
}
int i2d_ECPrivateKey_bio(BIO *bp, const EC_KEY *eckey)
{
- return ASN1_i2d_bio_of(EC_KEY, i2d_ECPrivateKey, bp, eckey);
+ return ASN1_i2d_bio(i2d_ECPrivateKey_thunk, bp,
+ CHECKED_PTR_OF(const EC_KEY, eckey));
}
#endif
@@ -689,61 +797,57 @@ int PKCS7_ISSUER_AND_SERIAL_digest(PKCS7_ISSUER_AND_SERIAL *data,
#ifndef OPENSSL_NO_STDIO
X509_SIG *d2i_PKCS8_fp(FILE *fp, X509_SIG **p8)
{
- return ASN1_d2i_fp_of(X509_SIG, X509_SIG_new, d2i_X509_SIG, fp, p8);
+ return ASN1_item_d2i_fp(ASN1_ITEM_rptr(X509_SIG), fp, p8);
}
int i2d_PKCS8_fp(FILE *fp, const X509_SIG *p8)
{
- return ASN1_i2d_fp_of(X509_SIG, i2d_X509_SIG, fp, p8);
+ return ASN1_item_i2d_fp(ASN1_ITEM_rptr(X509_SIG), fp, p8);
}
#endif
X509_SIG *d2i_PKCS8_bio(BIO *bp, X509_SIG **p8)
{
- return ASN1_d2i_bio_of(X509_SIG, X509_SIG_new, d2i_X509_SIG, bp, p8);
+ return ASN1_item_d2i_bio(ASN1_ITEM_rptr(X509_SIG), bp, p8);
}
int i2d_PKCS8_bio(BIO *bp, const X509_SIG *p8)
{
- return ASN1_i2d_bio_of(X509_SIG, i2d_X509_SIG, bp, p8);
+ return ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509_SIG), bp, p8);
}
#ifndef OPENSSL_NO_STDIO
X509_PUBKEY *d2i_X509_PUBKEY_fp(FILE *fp, X509_PUBKEY **xpk)
{
- return ASN1_d2i_fp_of(X509_PUBKEY, X509_PUBKEY_new, d2i_X509_PUBKEY,
- fp, xpk);
+ return ASN1_item_d2i_fp(ASN1_ITEM_rptr(X509_PUBKEY), fp, xpk);
}
int i2d_X509_PUBKEY_fp(FILE *fp, const X509_PUBKEY *xpk)
{
- return ASN1_i2d_fp_of(X509_PUBKEY, i2d_X509_PUBKEY, fp, xpk);
+ return ASN1_item_i2d_fp(ASN1_ITEM_rptr(X509_PUBKEY), fp, xpk);
}
#endif
X509_PUBKEY *d2i_X509_PUBKEY_bio(BIO *bp, X509_PUBKEY **xpk)
{
- return ASN1_d2i_bio_of(X509_PUBKEY, X509_PUBKEY_new, d2i_X509_PUBKEY,
- bp, xpk);
+ return ASN1_item_d2i_bio(ASN1_ITEM_rptr(X509_PUBKEY), bp, xpk);
}
int i2d_X509_PUBKEY_bio(BIO *bp, const X509_PUBKEY *xpk)
{
- return ASN1_i2d_bio_of(X509_PUBKEY, i2d_X509_PUBKEY, bp, xpk);
+ return ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509_PUBKEY), bp, xpk);
}
#ifndef OPENSSL_NO_STDIO
PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_fp(FILE *fp,
PKCS8_PRIV_KEY_INFO **p8inf)
{
- return ASN1_d2i_fp_of(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_new,
- d2i_PKCS8_PRIV_KEY_INFO, fp, p8inf);
+ return ASN1_item_d2i_fp(ASN1_ITEM_rptr(PKCS8_PRIV_KEY_INFO), fp, p8inf);
}
int i2d_PKCS8_PRIV_KEY_INFO_fp(FILE *fp, const PKCS8_PRIV_KEY_INFO *p8inf)
{
- return ASN1_i2d_fp_of(PKCS8_PRIV_KEY_INFO, i2d_PKCS8_PRIV_KEY_INFO, fp,
- p8inf);
+ return ASN1_item_i2d_fp(ASN1_ITEM_rptr(PKCS8_PRIV_KEY_INFO), fp, p8inf);
}
int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, const EVP_PKEY *key)
@@ -761,12 +865,14 @@ int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, const EVP_PKEY *key)
int i2d_PrivateKey_fp(FILE *fp, const EVP_PKEY *pkey)
{
- return ASN1_i2d_fp_of(EVP_PKEY, i2d_PrivateKey, fp, pkey);
+ return ASN1_i2d_fp(i2d_PrivateKey_thunk, fp,
+ CHECKED_PTR_OF(const EVP_PKEY, pkey));
}
EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a)
{
- return ASN1_d2i_fp_of(EVP_PKEY, EVP_PKEY_new, d2i_AutoPrivateKey, fp, a);
+ return ASN1_d2i_fp(EVP_PKEY_new_thunk, d2i_AutoPrivateKey_thunk,
+ fp, CHECKED_PPTR_OF(EVP_PKEY, a));
}
EVP_PKEY *d2i_PrivateKey_ex_fp(FILE *fp, EVP_PKEY **a, OSSL_LIB_CTX *libctx,
@@ -787,7 +893,8 @@ EVP_PKEY *d2i_PrivateKey_ex_fp(FILE *fp, EVP_PKEY **a, OSSL_LIB_CTX *libctx,
int i2d_PUBKEY_fp(FILE *fp, const EVP_PKEY *pkey)
{
- return ASN1_i2d_fp_of(EVP_PKEY, i2d_PUBKEY, fp, pkey);
+ return ASN1_i2d_fp(i2d_PUBKEY_thunk, fp,
+ CHECKED_PTR_OF(const EVP_PKEY, pkey));
}
EVP_PKEY *d2i_PUBKEY_ex_fp(FILE *fp, EVP_PKEY **a, OSSL_LIB_CTX *libctx,
@@ -808,7 +915,8 @@ EVP_PKEY *d2i_PUBKEY_ex_fp(FILE *fp, EVP_PKEY **a, OSSL_LIB_CTX *libctx,
EVP_PKEY *d2i_PUBKEY_fp(FILE *fp, EVP_PKEY **a)
{
- return ASN1_d2i_fp_of(EVP_PKEY, EVP_PKEY_new, d2i_PUBKEY, fp, a);
+ return ASN1_d2i_fp(EVP_PKEY_new_thunk, d2i_PUBKEY_thunk, fp,
+ CHECKED_PPTR_OF(EVP_PKEY, a));
}
#endif
@@ -816,14 +924,12 @@ EVP_PKEY *d2i_PUBKEY_fp(FILE *fp, EVP_PKEY **a)
PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio(BIO *bp,
PKCS8_PRIV_KEY_INFO **p8inf)
{
- return ASN1_d2i_bio_of(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_new,
- d2i_PKCS8_PRIV_KEY_INFO, bp, p8inf);
+ return ASN1_item_d2i_bio(ASN1_ITEM_rptr(PKCS8_PRIV_KEY_INFO), bp, p8inf);
}
int i2d_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, const PKCS8_PRIV_KEY_INFO *p8inf)
{
- return ASN1_i2d_bio_of(PKCS8_PRIV_KEY_INFO, i2d_PKCS8_PRIV_KEY_INFO, bp,
- p8inf);
+ return ASN1_item_i2d_bio(ASN1_ITEM_rptr(PKCS8_PRIV_KEY_INFO), bp, p8inf);
}
int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, const EVP_PKEY *key)
@@ -841,12 +947,14 @@ int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, const EVP_PKEY *key)
int i2d_PrivateKey_bio(BIO *bp, const EVP_PKEY *pkey)
{
- return ASN1_i2d_bio_of(EVP_PKEY, i2d_PrivateKey, bp, pkey);
+ return ASN1_i2d_bio(i2d_PrivateKey_thunk, bp,
+ CHECKED_PTR_OF(const EVP_PKEY, pkey));
}
EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a)
{
- return ASN1_d2i_bio_of(EVP_PKEY, EVP_PKEY_new, d2i_AutoPrivateKey, bp, a);
+ return ASN1_d2i_bio(EVP_PKEY_new_thunk, d2i_AutoPrivateKey_thunk,
+ bp, CHECKED_PPTR_OF(EVP_PKEY, a));
}
EVP_PKEY *d2i_PrivateKey_ex_bio(BIO *bp, EVP_PKEY **a, OSSL_LIB_CTX *libctx,
@@ -870,7 +978,8 @@ err:
int i2d_PUBKEY_bio(BIO *bp, const EVP_PKEY *pkey)
{
- return ASN1_i2d_bio_of(EVP_PKEY, i2d_PUBKEY, bp, pkey);
+ return ASN1_i2d_bio(i2d_PUBKEY_thunk, bp,
+ CHECKED_PTR_OF(const EVP_PKEY, pkey));
}
EVP_PKEY *d2i_PUBKEY_ex_bio(BIO *bp, EVP_PKEY **a, OSSL_LIB_CTX *libctx,
@@ -894,7 +1003,8 @@ err:
EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a)
{
- return ASN1_d2i_bio_of(EVP_PKEY, EVP_PKEY_new, d2i_PUBKEY, bp, a);
+ return ASN1_d2i_bio(EVP_PKEY_new_thunk, d2i_PUBKEY_thunk, bp,
+ CHECKED_PPTR_OF(EVP_PKEY, a));
}
#ifndef OPENSSL_NO_STDIO
diff --git a/crypto/x509/x_name.c b/crypto/x509/x_name.c
index 90588c8c67..961f474e5b 100644
--- a/crypto/x509/x_name.c
+++ b/crypto/x509/x_name.c
@@ -404,8 +404,10 @@ static int asn1_string_canon(ASN1_STRING *out, const ASN1_STRING *in)
out->type = V_ASN1_UTF8STRING;
out->length = ASN1_STRING_to_UTF8(&out->data, in);
- if (out->length == -1)
+ if (out->length < 0)
return 0;
+ if (out->length == 0)
+ return 1;
to = out->data;
from = to;
diff --git a/crypto/x509/x_x509a.c b/crypto/x509/x_x509a.c
index 6dfd68f74d..3fa17fb925 100644
--- a/crypto/x509/x_x509a.c
+++ b/crypto/x509/x_x509a.c
@@ -50,6 +50,8 @@ static X509_CERT_AUX *aux_get(X509 *x)
int X509_alias_set1(X509 *x, const unsigned char *name, int len)
{
X509_CERT_AUX *aux;
+ size_t len_s;
+
if (!name) {
if (!x || !x->aux || !x->aux->alias)
return 1;
@@ -59,14 +61,25 @@ int X509_alias_set1(X509 *x, const unsigned char *name, int len)
}
if ((aux = aux_get(x)) == NULL)
return 0;
+
+ if (len < -1)
+ return 0;
+
+ if (len == -1)
+ len_s = strlen((const char *)name);
+ else
+ len_s = len;
+
if (aux->alias == NULL && (aux->alias = ASN1_UTF8STRING_new()) == NULL)
return 0;
- return ASN1_STRING_set(aux->alias, name, len);
+ return ASN1_STRING_set_data(aux->alias, name, len_s);
}
int X509_keyid_set1(X509 *x, const unsigned char *id, int len)
{
X509_CERT_AUX *aux;
+ size_t len_s;
+
if (!id) {
if (!x || !x->aux || !x->aux->keyid)
return 1;
@@ -76,10 +89,19 @@ int X509_keyid_set1(X509 *x, const unsigned char *id, int len)
}
if ((aux = aux_get(x)) == NULL)
return 0;
+
+ if (len < -1)
+ return 0;
+
+ if (len == -1)
+ len_s = strlen((const char *)id);
+ else
+ len_s = len;
+
if (aux->keyid == NULL
&& (aux->keyid = ASN1_OCTET_STRING_new()) == NULL)
return 0;
- return ASN1_STRING_set(aux->keyid, id, len);
+ return ASN1_STRING_set_data(aux->keyid, id, len_s);
}
const unsigned char *X509_alias_get0(const X509 *x, int *len)
diff --git a/demos/Makefile b/demos/Makefile
index 208249e0fd..3b411fe052 100644
--- a/demos/Makefile
+++ b/demos/Makefile
@@ -6,6 +6,7 @@ MODULES = bio \
encrypt \
guide \
http3 \
+ info \
kdf \
keyexch \
mac \
diff --git a/demos/README.txt b/demos/README.txt
index 1a7d4f447f..9caafcad77 100644
--- a/demos/README.txt
+++ b/demos/README.txt
@@ -36,12 +36,18 @@ guide: Sample code from the OpenSSL Guide tutorials. See
quic-client-block.c: A simple blocking QUIC client
quic-client-non-block.c: A simple non-blocking QUIC client
quic-multi-stream.c: A simple QUIC client using multiple streams
+quic-server-block.c: A simple blocking QUIC server
+quic-server-non-block.c: A simple non-blocking QUIC server
tls-client-block.c: A simple blocking SSL/TLS client
tls-client-non-block.c: A simple non-blocking SSL/TLS client
+tls-server-block.c: A simple blocking SSL/TLS server
http3: Demonstration of how to use OpenSSL's QUIC capabilities
for HTTP/3.
+info:
+fips-version.c Demonstration of how to query the FIPS provider version
+
kdf:
hkdf.c Demonstration of HMAC based key derivation
pbkdf2.c Demonstration of PBKDF2 password based key derivation
@@ -78,4 +84,5 @@ rsa_pss_hash.c Compute and verify an RSA-PSS signature over a buffer
smime: Demonstrations related to S/MIME
sslecho:
+echecho.c Simple SSL/TLS echo client/server that uses ECH.
main.c Simple SSL/TLS echo client/server.
diff --git a/demos/build.info b/demos/build.info
index 3c74e8f331..be3252fa9d 100644
--- a/demos/build.info
+++ b/demos/build.info
@@ -1,4 +1,4 @@
-SUBDIRS=bio cipher digest keyexch mac kdf pkey signature \
+SUBDIRS=bio cipher digest info keyexch mac kdf pkcs12 pkey signature \
encrypt encode sslecho
IF[{- !$disabled{"h3demo"} -}]
diff --git a/demos/guide/build.info b/demos/guide/build.info
index de184ff0d1..7b5b54f073 100644
--- a/demos/guide/build.info
+++ b/demos/guide/build.info
@@ -5,6 +5,7 @@
# LD_LIBRARY_PATH=../.. ./tls-client-block www.example.com 443
PROGRAMS{noinst} = tls-client-block \
+ tls-server-block \
quic-client-block \
quic-multi-stream \
tls-client-non-block \
@@ -17,6 +18,10 @@ INCLUDE[tls-client-block]=../../include
SOURCE[tls-client-block]=tls-client-block.c
DEPEND[tls-client-block]=../../libcrypto ../../libssl
+INCLUDE[tls-server-block]=../../include
+SOURCE[tls-server-block]=tls-server-block.c
+DEPEND[tls-server-block]=../../libcrypto ../../libssl
+
INCLUDE[quic-client-block]=../../include
SOURCE[quic-client-block]=quic-client-block.c
DEPEND[quic-client-block]=../../libcrypto ../../libssl
diff --git a/demos/guide/tls-server-block.c b/demos/guide/tls-server-block.c
index 2bee2219ed..8e8410f995 100644
--- a/demos/guide/tls-server-block.c
+++ b/demos/guide/tls-server-block.c
@@ -64,6 +64,7 @@ int main(int argc, char *argv[])
{
int res = EXIT_FAILURE;
long opts;
+ long old_timeout;
const char *hostport;
SSL_CTX *ctx = NULL;
BIO *acceptor_bio;
@@ -174,7 +175,11 @@ int main(int argc, char *argv[])
* byte array, that identifies the server application, and reduces the
* chance of inappropriate cache sharing.
*/
- SSL_CTX_set_session_id_context(ctx, (void *)cache_id, sizeof(cache_id));
+ if (SSL_CTX_set_session_id_context(ctx, (void *)cache_id, sizeof(cache_id)) <= 0) {
+ SSL_CTX_free(ctx);
+ ERR_print_errors_fp(stderr);
+ errx(res, "Failed to set server session ID context");
+ }
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER);
/*
@@ -191,7 +196,9 @@ int main(int argc, char *argv[])
* loaded servers with sporadic connections from any given client, a longer
* time may be appropriate.
*/
- SSL_CTX_set_timeout(ctx, 3600);
+ old_timeout = SSL_CTX_set_timeout(ctx, 3600);
+ if (old_timeout != 3600)
+ warnx("Changing session timeout from %ld to 3600", old_timeout);
/*
* Clients rarely employ certificate-based authentication, and so we don't
diff --git a/demos/http3/ossl-nghttp3-demo-server.c b/demos/http3/ossl-nghttp3-demo-server.c
index 92cc10c067..227ac6e264 100644
--- a/demos/http3/ossl-nghttp3-demo-server.c
+++ b/demos/http3/ossl-nghttp3-demo-server.c
@@ -291,7 +291,7 @@ static int on_recv_header(nghttp3_conn *conn, int64_t stream_id, int32_t token,
fprintf(stdout, "\n");
if (token == NGHTTP3_QPACK_TOKEN__PATH) {
- int len = (((vvalue.len) < (MAXURL)) ? (vvalue.len) : (MAXURL));
+ int len = (((vvalue.len) < (MAXURL)) ? (vvalue.len) : (MAXURL - 1));
memset(h3ssl->url, 0, sizeof(h3ssl->url));
if (vvalue.base[0] == '/') {
@@ -1035,7 +1035,7 @@ static int wait_for_activity(SSL *ssl)
* "select" (with updated timeouts).
*/
- return (select(sock + 1, &read_fd, &write_fd, NULL, tvp));
+ return select(sock + 1, &read_fd, &write_fd, NULL, tvp);
}
/* Main loop for server to accept QUIC connections. */
diff --git a/demos/http3/ossl-nghttp3.c b/demos/http3/ossl-nghttp3.c
index 2461df73c2..e75f226221 100644
--- a/demos/http3/ossl-nghttp3.c
+++ b/demos/http3/ossl-nghttp3.c
@@ -543,7 +543,7 @@ static void h3_conn_pump_stream(OSSL_DEMO_H3_STREAM *s, void *conn_)
break;
/*
- * This function is confusingly named as it is is named from nghttp3's
+ * This function is confusingly named as it is named from nghttp3's
* 'perspective'; it is used to pass data *into* the HTTP/3 stack which
* has been received from the network.
*/
diff --git a/demos/info/Makefile b/demos/info/Makefile
new file mode 100644
index 0000000000..05f1707ba5
--- /dev/null
+++ b/demos/info/Makefile
@@ -0,0 +1,32 @@
+#
+# To run the demos when linked with a shared library (default) ensure
+# that libcrypto is on the library path. For example:
+#
+
+TESTS = fips-version
+
+CFLAGS = -I../../include -g -Wall
+LDFLAGS = -L../..
+LDLIBS = -lcrypto
+
+all: $(TESTS)
+
+fips-version: fips-version.o
+
+$(TESTS):
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LDLIBS)
+
+clean:
+ $(RM) *.o $(TESTS)
+
+.PHONY: test
+test: all
+ @echo "\nINFO tests:"
+ @set -e; for tst in $(TESTS); do \
+ echo "\n"$$tst; \
+ LD_LIBRARY_PATH=../.. \
+ OPENSSL_CONF=../../test/fips-and-base.cnf \
+ OPENSSL_MODULES=../../providers \
+ OPENSSL_CONF_INCLUDE=../../providers \
+ ./$$tst; \
+ done
diff --git a/demos/info/build.info b/demos/info/build.info
new file mode 100644
index 0000000000..b5339cec91
--- /dev/null
+++ b/demos/info/build.info
@@ -0,0 +1,11 @@
+#
+# To run the demos when linked with a shared library (default) ensure
+# that libcrypto is on the library path. For example:
+#
+# LD_LIBRARY_PATH=../.. ./info
+
+PROGRAMS{noinst} = fips-version
+
+INCLUDE[fips-version]=../../include
+SOURCE[fips-version]=fips-version.c
+DEPEND[fips-version]=../../libcrypto
diff --git a/demos/info/fips-version.c b/demos/info/fips-version.c
new file mode 100644
index 0000000000..6b1bb4bfab
--- /dev/null
+++ b/demos/info/fips-version.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+int main(int argc, char **argv)
+{
+ int ret = EXIT_FAILURE;
+ OSSL_LIB_CTX *libctx;
+ OSSL_PROVIDER *fips_provider = NULL;
+ OSSL_PARAM params[2];
+ char *version;
+
+ /* Replace this with your libctx if you are using a non-default one */
+ libctx = NULL;
+
+ /* Check if the FIPS provider is available in this libctx */
+ if (!OSSL_PROVIDER_available(libctx, "fips")) {
+ puts("FIPS provider is not available");
+ goto done;
+ }
+
+ /* Load the FIPS provider */
+ fips_provider = OSSL_PROVIDER_load(libctx, "fips");
+ if (fips_provider == NULL) {
+ puts("Failed to load FIPS provider");
+ goto done;
+ }
+
+ /* Query the FIPS provider version */
+ params[0] = OSSL_PARAM_construct_utf8_ptr(OSSL_PROV_PARAM_VERSION,
+ &version, 0);
+ params[1] = OSSL_PARAM_construct_end();
+ OSSL_PARAM_set_all_unmodified(params);
+ if (!OSSL_PROVIDER_get_params(fips_provider, params)) {
+ puts("Failed to query FIPS provider version");
+ goto done;
+ }
+
+ /* Check if the FIPS provider returned a version to us */
+ if (!OSSL_PARAM_modified(params)) {
+ puts("FIPS provider failed to set version");
+ goto done;
+ }
+
+ printf("FIPS provider version is %s\n", version);
+ ret = EXIT_SUCCESS;
+done:
+ OSSL_PROVIDER_unload(fips_provider);
+ return ret;
+}
diff --git a/demos/pkcs12/build.info b/demos/pkcs12/build.info
new file mode 100644
index 0000000000..6fd35d1822
--- /dev/null
+++ b/demos/pkcs12/build.info
@@ -0,0 +1,16 @@
+#
+# To run the demos when linked with a shared library (default) ensure that
+# libcrypto is on the library path. For example:
+#
+# LD_LIBRARY_PATH=../.. ./pkread
+
+PROGRAMS{noinst} = pkread \
+ pkwrite
+
+INCLUDE[pkread]=../../include
+SOURCE[pkread]=pkread.c
+DEPEND[pkread]=../../libcrypto
+
+INCLUDE[pkwrite]=../../include
+SOURCE[pkwrite]=pkwrite.c
+DEPEND[pkwrite]=../../libcrypto
diff --git a/demos/pkcs12/pkwrite.c b/demos/pkcs12/pkwrite.c
index 7bb73f35a4..b274943ce8 100644
--- a/demos/pkcs12/pkwrite.c
+++ b/demos/pkcs12/pkwrite.c
@@ -25,8 +25,6 @@ int main(int argc, char **argv)
fprintf(stderr, "Usage: pkwrite infile password name p12file\n");
exit(EXIT_FAILURE);
}
- OpenSSL_add_all_algorithms();
- ERR_load_crypto_strings();
if ((fp = fopen(argv[1], "r")) == NULL) {
fprintf(stderr, "Error opening file %s\n", argv[1]);
exit(EXIT_FAILURE);
diff --git a/demos/sslecho/build.info b/demos/sslecho/build.info
index d42716cd51..7784357ed6 100644
--- a/demos/sslecho/build.info
+++ b/demos/sslecho/build.info
@@ -6,6 +6,15 @@
PROGRAMS{noinst} = sslecho
+
INCLUDE[sslecho]=../../include
SOURCE[sslecho]=main.c
DEPEND[sslecho]=../../libcrypto ../../libssl
+
+IF[{- !$disabled{"ech"} -}]
+ PROGRAMS{noinst} = echecho
+
+ INCLUDE[echecho]=../../include
+ SOURCE[echecho]=echecho.c
+ DEPEND[echecho]=../../libcrypto ../../libssl
+ENDIF
diff --git a/demos/sslecho/echecho.c b/demos/sslecho/echecho.c
index bcd097d383..d9c757cba2 100644
--- a/demos/sslecho/echecho.c
+++ b/demos/sslecho/echecho.c
@@ -7,27 +7,38 @@
* https://www.openssl.org/source/license.html
*/
+#include
#include
-#include
#include
-#include
-#include
#include
#include
+#if !defined(OPENSSL_SYS_WINDOWS)
+#include
+#include
+#include
+
+#define SOCKET int
+#define INVALID_SOCKET -1
+#define closesocket(s) close(s)
+#else /* defined(OPENSSL_SYS_WINDOWS) */
+#include
+#include
+#endif /* !defined(OPENSSL_SYS_WINDOWS) */
+
static const int server_port = 4433;
-static const char echconfig[] = "AD7+DQA65wAgACA8wVN2BtscOl3vQheUzHeIkVmKIiydUhDCliA4iyQRCwAEAAEAAQALZXhhbXBsZS5jb20AAA==";
-static const char echprivbuf[] = "-----BEGIN PRIVATE KEY-----\n"
- "MC4CAQAwBQYDK2VuBCIEICjd4yGRdsoP9gU7YT7My8DHx1Tjme8GYDXrOMCi8v1V\n"
- "-----END PRIVATE KEY-----\n"
- "-----BEGIN ECHCONFIG-----\n"
- "AD7+DQA65wAgACA8wVN2BtscOl3vQheUzHeIkVmKIiydUhDCliA4iyQRCwAEAAEAAQALZXhhbXBsZS5jb20AAA==\n"
- "-----END ECHCONFIG-----\n";
-
-typedef unsigned char bool;
-#define true 1
-#define false 0
+static const char echconfig[]
+ = "AD7+DQA65wAgACA8wVN2BtscOl3vQheUzHeIkVmKIiydUhDCliA4iyQRCwAEAAEA"
+ "AQALZXhhbXBsZS5jb20AAA==";
+static const char echprivbuf[]
+ = "-----BEGIN PRIVATE KEY-----\n"
+ "MC4CAQAwBQYDK2VuBCIEICjd4yGRdsoP9gU7YT7My8DHx1Tjme8GYDXrOMCi8v1V\n"
+ "-----END PRIVATE KEY-----\n"
+ "-----BEGIN ECHCONFIG-----\n"
+ "AD7+DQA65wAgACA8wVN2BtscOl3vQheUzHeIkVmKIiydUhDCliA4iyQRCwAEAAEA"
+ "AQALZXhhbXBsZS5jb20AAA==\n"
+ "-----END ECHCONFIG-----\n";
/*
* This flag won't be useful until both accept/read (TCP & SSL) methods
@@ -35,14 +46,14 @@ typedef unsigned char bool;
*/
static volatile bool server_running = true;
-int create_socket(bool isServer)
+static SOCKET create_socket(bool isServer)
{
- int s;
+ SOCKET s;
int optval = 1;
struct sockaddr_in addr = { 0 };
s = socket(AF_INET, SOCK_STREAM, 0);
- if (s < 0) {
+ if (s == INVALID_SOCKET) {
perror("Unable to create socket");
exit(EXIT_FAILURE);
}
@@ -53,7 +64,7 @@ int create_socket(bool isServer)
addr.sin_addr.s_addr = INADDR_ANY;
/* Reuse the address; good for quick restarts */
- if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))
+ if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&optval, sizeof(optval))
< 0) {
perror("setsockopt(SO_REUSEADDR) failed");
exit(EXIT_FAILURE);
@@ -73,7 +84,7 @@ int create_socket(bool isServer)
return s;
}
-SSL_CTX *create_context(bool isServer)
+static SSL_CTX *create_context(bool isServer)
{
const SSL_METHOD *method;
SSL_CTX *ctx;
@@ -97,7 +108,7 @@ static int configure_ech(SSL_CTX *ctx, int server,
unsigned char *buf, size_t len)
{
OSSL_ECHSTORE *es = NULL;
- BIO *es_in = BIO_new_mem_buf(buf, len);
+ BIO *es_in = BIO_new_mem_buf(buf, (int)len);
if (es_in == NULL || (es = OSSL_ECHSTORE_new(NULL, NULL)) == NULL)
goto err;
@@ -115,7 +126,7 @@ err:
return 0;
}
-void configure_server_context(SSL_CTX *ctx)
+static void configure_server_context(SSL_CTX *ctx)
{
/* Set the key and cert */
if (SSL_CTX_use_certificate_chain_file(ctx, "cert.pem") <= 0) {
@@ -136,7 +147,7 @@ void configure_server_context(SSL_CTX *ctx)
}
}
-void configure_client_context(SSL_CTX *ctx)
+static void configure_client_context(SSL_CTX *ctx)
{
/*
* Configure the client to abort the handshake if certificate verification
@@ -144,9 +155,11 @@ void configure_client_context(SSL_CTX *ctx)
*/
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
/*
- * In a real application you would probably just use the default system certificate trust store and call:
+ * In a real application you would probably just use the default system
+ * certificate trust store and call:
* SSL_CTX_set_default_verify_paths(ctx);
- * In this demo though we are using a self-signed certificate, so the client must trust it directly.
+ * In this demo though we are using a self-signed certificate,
+ * so the client must trust it directly.
*/
if (!SSL_CTX_load_verify_locations(ctx, "cert.pem", NULL)) {
ERR_print_errors_fp(stderr);
@@ -160,7 +173,7 @@ void configure_client_context(SSL_CTX *ctx)
}
}
-void usage()
+static void usage(void)
{
printf("Usage: echecho s\n");
printf(" --or--\n");
@@ -169,6 +182,7 @@ void usage()
exit(1);
}
+#define BUFFERSIZE 1024
int main(int argc, char **argv)
{
bool isServer;
@@ -177,13 +191,13 @@ int main(int argc, char **argv)
SSL_CTX *ssl_ctx = NULL;
SSL *ssl = NULL;
- int server_skt = -1;
- int client_skt = -1;
+ SOCKET server_skt = INVALID_SOCKET;
+ SOCKET client_skt = INVALID_SOCKET;
- /* used by getline relying on realloc, can't be statically allocated */
+ /* used by fgets */
+ char buffer[BUFFERSIZE];
char *txbuf = NULL;
size_t txcap = 0;
- int txlen;
char rxbuf[128];
size_t rxcap = sizeof(rxbuf);
@@ -192,7 +206,7 @@ int main(int argc, char **argv)
char *rem_server_ip = NULL;
struct sockaddr_in addr = { 0 };
- unsigned int addr_len = sizeof(addr);
+ socklen_t addr_len = (socklen_t)sizeof(addr);
char *outer_sni = NULL, *inner_sni = NULL;
int ech_status;
@@ -239,7 +253,7 @@ int main(int argc, char **argv)
/* Wait for TCP connection from client */
client_skt = accept(server_skt, (struct sockaddr *)&addr,
&addr_len);
- if (client_skt < 0) {
+ if (client_skt == INVALID_SOCKET) {
perror("Unable to accept");
exit(EXIT_FAILURE);
}
@@ -248,7 +262,11 @@ int main(int argc, char **argv)
/* Create server SSL structure using newly accepted client socket */
ssl = SSL_new(ssl_ctx);
- SSL_set_fd(ssl, client_skt);
+ if (SSL_set_fd(ssl, (int)client_skt) <= 0) {
+ puts("Unable to set fd for the SSL object");
+ ERR_print_errors_fp(stderr);
+ exit(EXIT_FAILURE);
+ }
/* Wait for SSL connection from the client */
if (SSL_accept(ssl) <= 0) {
@@ -268,8 +286,11 @@ int main(int argc, char **argv)
/* Echo loop */
while (true) {
- /* Get message from client; will fail if client closes connection */
- if ((rxlen = SSL_read(ssl, rxbuf, rxcap)) <= 0) {
+ /*
+ * Get message from client; will fail if client closes
+ * connection
+ */
+ if ((rxlen = SSL_read(ssl, rxbuf, (int)rxcap)) <= 0) {
if (rxlen == 0) {
printf("Client closed connection\n");
}
@@ -297,7 +318,12 @@ int main(int argc, char **argv)
/* Cleanup for next client */
SSL_shutdown(ssl);
SSL_free(ssl);
- close(client_skt);
+ closesocket(client_skt);
+ /*
+ * Set client_skt to INVALID_SOCKET to avoid double close when
+ * server_running become false before next accept
+ */
+ client_skt = INVALID_SOCKET;
}
}
printf("Server exiting...\n");
@@ -326,11 +352,19 @@ int main(int argc, char **argv)
/* Create client SSL structure using dedicated client socket */
ssl = SSL_new(ssl_ctx);
- SSL_set_fd(ssl, client_skt);
+ if (SSL_set_fd(ssl, (int)client_skt) <= 0) {
+ puts("Unable to set fd for the SSL object");
+ ERR_print_errors_fp(stderr);
+ exit(EXIT_FAILURE);
+ }
/* Set hostname for SNI */
SSL_set_tlsext_host_name(ssl, rem_server_ip);
/* Configure server hostname check */
- SSL_set1_host(ssl, rem_server_ip);
+ if (SSL_set1_ipaddr(ssl, rem_server_ip) <= 0) {
+ puts("Unable to set IP address for the SSL object");
+ ERR_print_errors_fp(stderr);
+ exit(EXIT_FAILURE);
+ }
/* Now do SSL connect with server */
if (SSL_connect(ssl) == 1) {
@@ -348,9 +382,11 @@ int main(int argc, char **argv)
/* Loop to send input from keyboard */
while (true) {
/* Get a line of input */
- txlen = getline(&txbuf, &txcap, stdin);
+ memset(buffer, 0, BUFFERSIZE);
+ txbuf = fgets(buffer, BUFFERSIZE, stdin);
+
/* Exit loop on error */
- if (txlen < 0 || txbuf == NULL) {
+ if (txbuf == NULL) {
break;
}
/* Exit loop if just a carriage return */
@@ -358,14 +394,14 @@ int main(int argc, char **argv)
break;
}
/* Send it to the server */
- if ((result = SSL_write(ssl, txbuf, txlen)) <= 0) {
+ if ((result = SSL_write(ssl, txbuf, (int)strlen(txbuf))) <= 0) {
printf("Server closed connection\n");
ERR_print_errors_fp(stderr);
break;
}
/* Wait for the echo */
- rxlen = SSL_read(ssl, rxbuf, rxcap);
+ rxlen = SSL_read(ssl, rxbuf, (int)rxcap);
if (rxlen <= 0) {
printf("Server closed connection\n");
ERR_print_errors_fp(stderr);
@@ -392,10 +428,10 @@ exit:
}
SSL_CTX_free(ssl_ctx);
- if (client_skt != -1)
- close(client_skt);
- if (server_skt != -1)
- close(server_skt);
+ if (client_skt != INVALID_SOCKET)
+ closesocket(client_skt);
+ if (server_skt != INVALID_SOCKET)
+ closesocket(server_skt);
if (txbuf != NULL && txcap > 0)
free(txbuf);
diff --git a/doc/build.info b/doc/build.info
index 6e8dfedb5c..44b06941e4 100644
--- a/doc/build.info
+++ b/doc/build.info
@@ -1499,6 +1499,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
@@ -3426,6 +3430,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 \
@@ -4101,6 +4106,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 \
diff --git a/doc/designs/fixed-size-large-numbers.md b/doc/designs/fixed-size-large-numbers.md
deleted file mode 100644
index e6f059cd80..0000000000
--- a/doc/designs/fixed-size-large-numbers.md
+++ /dev/null
@@ -1,623 +0,0 @@
-Fixed size large numbers
-========================
-
-*`BIGNUM` redesign for better constant time calculations*
----------------------------------------------------------
-
-
-Abstract
-
-
-In this design, we explore and define how OpenSSL's `BIGNUM` library can
-be remodelled for constant-size calculations. Furthermore, we explore and
-define a fixed size large number library, which never changes the in-memory
-size of a number once it has been allocated.
-
-
-
-
-### Table of contents:
-
-- [Background][]
-- [Goals][]
-- [Challenges][]
-- [Design][]
- - [The `OSSL_FN` type][]
- - [The `OSSL_FN_CTX` type][]
- - [The `OSSL_FN_CTX` type, with frames][]
- - [The `OSSL_FN_CTX` type, without frames][]
- - [The `BIGNUM` type][]
- - [Mutability][]
- - [Memory functionality for `OSSL_FN`][]
- - [Memory functionality for `OSSL_FN_CTX`][]
- - [Failures][]
-- [Repurposing existing code][]
-- [How to apply `OSSL_FN`][]
-- [Where to apply `OSSL_FN`][]
-- [How to apply `OSSL_FN_CTX`][]
- - [The variant with frames][]
- - [The variant without frames][]
-- [Testing][]
-- [Appendix][]
- - [Using the C99 flexible array member feature][]
-
-Background
-==========
-
-[Background]: #background
-
-The current internal definition of OpenSSL's `BIGNUM` looks like this:
-
-```c
-struct bignum_st {
- BN_ULONG *d; /*
- * Pointer to an array of 'BN_BITS2' bit
- * chunks. These chunks are organised in
- * a least significant chunk first order.
- */
- int top; /* Index of last used d +1. */
- /* The next are internal book keeping for bn_expand. */
- int dmax; /* Size of the d array. */
- int neg; /* one if the number is negative */
- int flags;
-};
-```
-
-The fields `d`, `top` and `dmax` allow the numbers to be quite dynamic in
-terms of its memory footprint, as it can both increase in size[^1] and
-decrease in size.[^2]
-
-Furthermore, the result of any `BIGNUM` operation may be the same `BIGNUM`
-instance as any of the operands, which means that any `BIGNUM` may have its
-memory footprint adjusted at any time.
-
-While this is very flexible, it leaves uncertainties about the time any
-calculation may take, following any earlier calculation, which is a security
-vulnerability.
-
-[^1]: the array `d` is reallocated to a larger size and `dmax` as well as top
- are updated
-[^2]: `top` is diminished
-
-Goals
-=====
-
-[Goals]: #goals
-
-Overall goal: Introduce a new type and API that are inherently constant size
-to replace the existing `BIGNUM` usage.
-
-The intention is to enhance this one aspect of constant time calculations.
-Other aspects are considered out of scope for this design.
-
-The included sub-goals are:
-
-* To define a new large number type and accompanying API, that doesn't allow
- size adjustments of the large numbers once their individual size has been
- established
-* To define that large number type and API in such a way it's compatible
- with the `BIGNUM` type, so that a `BIGNUM` may use an `OSSL_FN` as its
- backing storage and selected call sites may acquire an `OSSL_FN` view of
- a `BIGNUM`.
-* To ensure that the new large number API is constant-size
-* To repurpose as much as possible of our current `BIGNUM` code for the new
- large number API, especially our assembler code (with the assumption that
- everything that doesn't change the `BIGNUM` sizes can be repurposed as is)
-* To replace all security critical large number calculations so that they
- are not just constant-size in themselves, but that the whole set of
- calculations remains constant-size, within OpenSSL code
-
-Challenges
-==========
-
-[Challenges]: #challenges
-
-The challenges we have are:
-
-- **`BIGNUM` usage**
-
- Because `BIGNUM` is a public facing API, it's likely to be used by OpenSSL
- users. This existing API needs to be backward compatible, but performance
- isn't necessarily critical.
-
-- **constant-time through constant-size**
-
- To make calculation time predictable on a broader scale than on a
- per-operation basis, there's a need to ensure that each large number being
- used in the calculations involved has a fixed size, i.e. to avoid the sort
- of dynamic sizing that the `BIGNUM` functionality does.
-
-Design
-======
-
-[Design]: #design
-
-The overall design defines a new type, `OSSL_FN` (where FN is short for
-"FIXNUM"), which can somehow be made compatible with `BIGNUM`, but yet be
-distinct. Early thoughts on this was to make them essentially the same type
-internally, and cast between them, but unfortunately, a compliant C compiler
-is very likely to auto-cast between them, making it difficult to keep them
-separate yet castable back and forth.
-
-To allow a stricter or more explicit way to remedy the flexibility of the C
-language, this design therefore defines a `OSSL_FN` which is separate from
-the `BIGNUM`, yet compatible with BIGNUM insofar that the `BIGNUM` type
-wraps around the `OSSL_FN` type.
-
-The compatibility is primarily at the storage and acquisition boundary. A
-`BIGNUM` may use an `OSSL_FN` as its backing storage, and selected internal
-crypto call sites that already receive `BIGNUM` values may acquire the
-embedded `OSSL_FN` and perform security-critical calculations with `OSSL_FN`
-functions.
-
-This does not mean that ordinary `BIGNUM` (`BN_`) operation functions are
-wrappers around corresponding `OSSL_FN` operation functions. `BN_`
-functions retain their dynamic `BIGNUM` semantics. Conversely, once
-execution has entered an `OSSL_FN` operation, that operation must remain
-inside the "`OSSL_FN` only" bubble and must not call functions that take
-`BIGNUM` arguments.
-
-This restriction does not apply to low-level helpers that operate only on
-`BN_ULONG` arrays or primitive limb values, such as existing `bn_` word
-functions. `BN_ULONG` and `OSSL_FN_ULONG` are compatible, so such helpers
-may be reused by `OSSL_FN` code as long as they do not allocate, resize, or
-otherwise operate on `BIGNUM` objects.
-
-The overall design also defines new associated types to replace their
-`BIGNUM` counterparts: `OSSL_FN_CTX`, `OSSL_FN_BLINDING`, `OSSL_FN_MONT_CTX`,
-and `OSSL_FN_RECP_CTX`. Notably, however, the callback type `BN_GENCB`
-isn't replaced, as it contains nothing `BIGNUM`, and can therefore be reused
-unchanged with an `OSSL_FN` API.
-
-The `OSSL_FN` type and API will be designed in such a way to enable it to
-become public at some point in the future. *The initial version will not be
-public and will only be used internally within OpenSSL.*
-
-Let's go over the details
-
-The `OSSL_FN` type
-------------------
-
-[The `OSSL_FN` type]: #the-ossl_fn-type
-
-The `OSSL_FN` type would be a structure derived from the existing `BIGNUM`
-type, retaining a minimum amount of data. Just as was previously with
-`BIGNUM`, the absolute value of the number is stored in a `BN_ULONG` array.
-`OSSL_FN` itself is unsigned; sign handling remains with `BIGNUM` when
-`BIGNUM` values are used as carriers.
-
-```c
-typedef struct ossl_fn_st OSSL_FN;
-
-struct ossl_fn_st {
- /* Flag: alloced with OSSL_FN_new() or OSSL_FN_secure_new() */
- unsigned int is_dynamically_allocated : 1;
- /* Flag: alloced with OSSL_FN_secure_new() */
- unsigned int is_securely_allocated : 1;
-
- /*
- * The d array, with its size in number of BN_ULONG.
- * This stores the number itself
- */
- size_t dsize;
- BN_ULONG d[];
-};
-```
-
-The `OSSL_FN_CTX` type
-----------------------
-
-[The `OSSL_FN_CTX` type]: #the-ossl_fn_ctx-type
-
-The `OSSL_FN_CTX` type is made to replace the `BN_CTX` type where `OSSL_FN`
-type is used instead of `BIGNUM`.
-
-The `OSSL_FN_CTX` type is to be implemented as an arena (a large enough chunk
-of memory) in which `OSSL_FN` instances are allocated. More in detail, there
-are two possibilities.
-
-### The `OSSL_FN_CTX` type, with frames
-
-[The `OSSL_FN_CTX` type, with frames]: #the-ossl_fn_ctx-type-with-frames
-
-This variant is intended to mimic all `BN_CTX` functionality. The idea is to
-create a large `OSSL_FN_CTX` at the top function of a complex calculation, and
-pass it around to all sub-function calls.
-
-Each sub-function would begin with starting a frame (using `OSSL_FN_CTX_begin()`,
-similar in spirit to `BN_CTX_start()`) in the passed `OSSL_FN_CTX` arena,
-obtain what temporary `OSSL_FN`s it needs from it (using `OSSL_FN_CTX_get()`,
-similar in spirit to `BN_CTX_get()`), perform what calculations it needs, and
-finish with ending the frame (using `OSSL_FN_CTX_end()`, similar in spirit to
-`BN_CTX_end()`), which relinquishing that frame's space in the `OSSL_FN_CTX`
-arena, and thereby making that same space available for the next sub-function.
-
-```c
-typedef struct ossl_fn_ctx_st OSSL_FN_CTX;
-
-struct ossl_fn_ctx_frame_st; /* forwarding, see below */
-struct ossl_fn_ctx_st {
- /*
- * Pointer to the last OSSL_FN_CTX_start() location (a simple pointer into
- * the memory area). See the struct ossl_fn_ctx_frame_st definition below
- * for details.
- */
- struct ossl_fn_ctx_frame_st *last_frame;
- /*
- * The arena itself.
- */
- size_t msize; /* bytes */
- unsigned char memory[];
-};
-
-struct ossl_fn_ctx_frame_st {
- /*
- * Pointer back to the whole arena where the frame is located, to access
- * |msize| and |memory| from it.
- */
- struct ossl_fn_ctx_st *arena;
- /*
- * Pointer to the previous frame in the arena, allowing OSSL_FN_CTX_end()
- * to do its job.
- */
- struct ossl_fn_ctx_frame_st *previous_frame;
- /*
- * Pointer to the free area of the frame. Every time OSSL_FN_CTX_get() is
- * called, the current value of this pointer is returned, and it's updated
- * by incrementing it by the number of bytes given by OSSL_FN_CTX_get().
- * The available number of bytes is limited by what's left in the arena.
- */
- unsigned char *free_memory;
- unsigned char memory[];
-};
-```
-
-The arena design requires that the total use of the arena can be predicted
-at the point of allocating the arena. There is an inherent uncertainty how
-large an arena should be to accommodate the needs of a large tree of
-function calls using it. A possible solution is to allocate a very large
-arena (could 32kB be considered enough?), but it may require some
-investigation to find out what's reasonable.
-
-Looking at the current use of `BN_CTX_new`, it can be noted that they are
-allocated all over current OpenSSL code, so it's easy to assume that each is
-used in a fairly limited fashion. Furthermore, the `BN_CTX` internals allow
-for a maximum of 16 `BIGNUM`s. A corresponding arena could the reasonably
-have the size 16 \* *size of largest fixed number* plus a little extra for
-bookkeeping purposes.
-
-### The `OSSL_FN_CTX` type, without frames
-
-[The `OSSL_FN_CTX` type, without frames]: #the-ossl_fn_ctx-type-without-frames
-
-Compared to the variant with frames, this `OSSL_FN_CTX` variant is much
-simpler, but also more heap allocation intense.
-
-The idea with this one is that each function that needs to obtain temporary
-`OSSL_FN`s would also create their own `OSSL_FN_CTX`, independently from any
-other function.
-
-```c
-typedef struct ossl_fn_ctx_st OSSL_FN_CTX;
-
-struct ossl_fn_ctx_st {
- /*
- * Pointer to the free area of the arena. Every time OSSL_FN_CTX_get() is
- * called, the current value of this pointer is returned, and it's updated
- * by incrementing it by the number of bytes given by OSSL_FN_CTX_get().
- * The available number of bytes is limited by what's left in the arena.
- */
- unsigned char *free_memory;
- /*
- * The arena itself.
- */
- size_t msize; /* bytes */
- unsigned char memory[];
-};
-```
-
-Other associated types
-----------------------
-
-[Other associated types]: #other-associated-types
-
-There are a few types that, like `BN_CTX` / `OSSL_FN_CTX`, are used to hold
-a context around some more complicated calculations. Just like `OSSL_FN_CTX`,
-The `OSSL_FN` variants of these types are made into strictly separate types,
-not compatible with their `BIGNUM` counterparts.
-
-| `BIGNUM` types | `OSSL_FN` types |
-|----------------|--------------------|
-| `BN_BLINDING` | `OSSL_FN_BLINDING` |
-| `BN_MONT_CTX` | `OSSL_FN_MONT_CTX` |
-| `BN_RECP_CTX` | `OSSL_FN_RECP_CTX` |
-
-Their `OSSL_FN` APIs for these types should be possible to create by
-repurposing the corresponding `BIGNUM` APIs, with adjustments for the
-constant-size requirements of all `OSSL_FN` functions.
-
-The `BIGNUM` type
------------------
-
-[The `BIGNUM` type]: #the-bignum-type
-
-The `BIGNUM` type is changed to include a `OSSL_FN` for its data, while
-retaining the fields that support the dynamic `BIGNUM` semantics:
-
-```c
-struct bignum_st {
- OSSL_FN *data;
- /* Some of these flags are replicated in OSSL_FN, some are not */
- int flags;
-
- BN_ULONG *d; /* Pointer to |data->d| */
- int top; /* Index of last used d +1. */
- int dmax; /* Copy of |data->dsize| */
- int neg; /* One if the number is negative */
-};
-```
-
-In normal public use, `data` is non-NULL and `d` points at `data->d`.
-Certain internal or otherwise special `BIGNUM`s may still have `data` set to
-NULL, in which case `d` points directly at a `BN_ULONG` array. Such cases
-must not be forced to grow an `OSSL_FN` backing object solely to fit this
-structure. How `OSSL_FN` code should use the `BN_ULONG` data from such
-`BIGNUM`s remains an implementation detail.
-
-When structured this way, it's easy to get an `OSSL_FN` out of a `BIGNUM`:
-
-```c
-/*
- * BN_acquire_fn() and BN_release_fn() function together. It is done this
- * way as a safety measure, to make sure that a BIGNUM doesn't expand an OSSL_FN
- * that the caller currently has a handle on. However, it's possible to
- * adjust the size of the OSSL_FN while acquiring it.
- */
-OSSL_FN *BN_acquire_fn(BIGNUM *a, size_t bits)
-{
- if ((bn_expand(a, bits)) <= 0)
- return NULL;
- /* Implementation may do further acquisition bookkeeping here. */
- return a->data;
-}
-void BN_release_fn(BIGNUM *a)
-{
- /* Implementation may do further release bookkeeping here. */
-}
-```
-
-Note that these functions are not designed to be thread-safe. By design,
-holding pointers to a `BIGNUM` and its wrapped `OSSL_FN` at the same time
-should only happen in a very short term.
-
-Mutability
-----------
-
-[Mutability]: #mutability
-
-The understanding is that within a `OSSL_FN` API, `dsize` is immutable as
-soon as a `OSSL_FN` has been allocated to its target size, except for when
-the `OSSL_FN` instance is freed.
-
-When accessed through the `BIGNUM` type (i.e. by the `BIGNUM` API), the
-`OSSL_FN` size may be reallocated to allow a larger size than initially
-allocated, and `dsize` may be modified accordingly. The exception is an
-acquired `OSSL_FN` view. Once a caller has acquired the backing `OSSL_FN`
-from a `BIGNUM`, that backing size must be treated as immutable until
-release. The owning `BIGNUM` must not simultaneously be used through `BN_`
-operations that could resize or otherwise reinterpret the same storage.
-
-The `OSSL_FN_CTX` API is much more strict. The size of an `OSSL_FN_CTX`
-instance is immutable after it has been allocated, except when it is freed.
-
-Memory functionality for `OSSL_FN`
-----------------------------------
-
-[Memory functionality for `OSSL_FN`]: #memory-functionality-for-ossl_fn
-
-We anticipate that we will need the following functions to allocate and
-deallocate `OSSL_FN`s:
-
-```c
-OSSL_FN *OSSL_FN_new(size_t size);
-void OSSL_FN_free(OSSL_FN *f);
-```
-
-Memory functionality for `OSSL_FN_CTX`
---------------------------------------
-
-[Memory functionality for `OSSL_FN_CTX`]: #memory-functionality-for-ossl_fn_ctx
-
-We anticipate that the `OSSL_FN_CTX` API will look very much like the
-`BN_CTX` API, except for the allocation functionality:
-
-```c
-OSSL_FN_CTX *OSSL_FN_CTX_new(OSSL_LIB_CTX *libctx, size_t arena_size);
-OSSL_FN_CTX *OSSL_FN_CTX_secure_new(OSSL_LIB_CTX *libctx, size_t arena_size);
-void OSSL_FN_CTX_free(OSSL_FN_CTX *ctx);
-
-OSSL_FN *OSSL_FN_CTX_get(OSSL_FN_CTX *ctx, size_t size);
-```
-
-*Something to be noted is that `OSSL_FN_CTX_secure_new()` allocates the
-whole arena in secure memory. The impact compared to allocating individual
-`OSSL_FN` instances in secure memory is considered minimal.*
-
-If the variant of `OSSL_FN_CTX` *with frames* is chosen, the following
-functions will also have to be defined:
-
-```c
-int OSSL_FN_CTX_start(OSSL_FN_CTX *ctx);
-int OSSL_FN_CTX_end(OSSL_FN_CTX *ctx);
-```
-
-Failures
---------
-
-[Failures]: #failures
-
-A fixed size large number introduces new problems, which introduces new ways
-that the `OSSL_FN` API can fail:
-
-* Overflow: this will happen when the caller has allocated an improperly
- sized `OSSL_FN` to store future calculation results in. *This is akin to
- memory allocation failures in so far that there isn't enough memory space*
-
-Repurposing existing code
-=========================
-
-[Repurposing existing code]: #repurposing-existing-code
-
-A majority of existing internal `BIGNUM` code operates directly on the `d`
-array of the existing `BIGNUM` structure, with the size of that array given
-separately, and are already essentially operating on fixed size numbers.
-This design assumes that such functions can be repurposed for `OSSL_FN`
-functionality with zero change, apart from function name changes.
-
-Furthermore, the remaining functions, which do manipulate the size of the
-`BIGNUM`, or are public facing `BIGNUM` functions, retain their current
-`BIGNUM` functionality, including size manipulation within the `BIGNUM`
-"bubble". They are not wrapped around `OSSL_FN` functions; conversion
-between `BIGNUM` and `OSSL_FN` happens at top-level crypto call sites,
-where the embedded `OSSL_FN` is acquired and passed to `OSSL_FN`
-functions, during whose execution the `OSSL_FN` size is immutable (see
-[Mutability][]).
-
-How to apply `OSSL_FN`
-======================
-
-[How to apply `OSSL_FN`]: #how-to-apply-ossl_fn
-
-The purpose of `OSSL_FN` is to make the number constant size (implying
-enhanced constant time) for a crypto system. To guarantee this with high
-confidence, any function that performs some sort of numeric operation on a
-set of input `OSSL_FN`s must only use other functions that only affect the
-contents of their `d` array, but not its size. Those are typically other
-`OSSL_FN` functions, or reused bignum functions that receive the `d` array
-and its size directly.
-
-Where to apply `OSSL_FN`
-========================
-
-[Where to apply `OSSL_FN`]: #where-to-apply-ossl_fn
-
-`OSSL_FN` should primarily be used instead of `BIGNUM` in internal
-calculations throughout OpenSSLs libraries. Exceptions can be made where
-calculations aren't security critical.
-
-In this, "calculations" is meant in a mathematical sense, i.e. whatever what
-would be expressed as a mathematical formula is considered a "calculation".
-
-However, `BIGNUM` has other uses than mere calculations. For example,
-`BIGNUM` is used as storage of numbers that were originally ASN.1 INTEGERs,
-and while individual ASN.1 INTEGERs always have a known size, they are
-usually just one number in a set, and it's often only known at a later time
-what are the size requirements of the cryptosystem that use them.
-For example, the size of an RSA key can only be determined when a known
-number in that key - usually *n* - has been seen by code, and this affects
-what size all numbers in an RSA key should be adjusted to before doing
-calculations on them.
-
-How to apply `OSSL_FN_CTX`
-==========================
-
-[How to apply `OSSL_FN_CTX`]: #how-to-apply-ossl_fn_ctx
-
-The variant with frames
------------------------
-
-[The variant with frames]: #the-variant-with-frames
-
-All internal uses of `BN_CTX_new()` and `BN_CTX_new_ex()` are to be replaced
-with calls of `OSSL_FN_CTX_new()`.
-
-All internal uses of `BN_CTX_secure_new()` and `BN_CTX_secure_new_ex()` are to
-be replaced with calls of `OSSL_FN_CTX_secure_new()`.
-
-All internal uses of `BN_CTX_free()` are to be replaced with calls of
-`OSSL_FN_CTX_free()`.
-
-All internal uses of `BN_CTX_start()` are to be replaced with calls of
-`OSSL_FN_CTX_start()`.
-
-All internal uses of `BN_CTX_get()` are to be replaced with calls of
-`OSSL_FN_CTX_get()`.
-
-All internal uses of `BN_CTX_end()` are to be replaced with calls of
-`OSSL_FN_CTX_end()`.
-
-The variant without frames
---------------------------
-
-[The variant without frames]: #the-variant-without-frames
-
-All internal uses of `BN_CTX_new()`, `BN_CTX_new_ex()`, `BN_CTX_secure_new()`,
-`BN_CTX_secure_new_ex()`, and `BN_CTX_free()` are to be dropped.
-
-All internal uses of `BN_CTX_start()` are to be replaced with calls of
-`OSSL_FN_CTX_new()`.
-
-All internal uses of `BN_CTX_get()` are to be replaced with calls of
-`OSSL_FN_CTX_get()`.
-
-All internal uses of `BN_CTX_end()` are to be replaced with calls of
-`OSSL_FN_CTX_free()`.
-
-Testing
-=======
-
-[Testing]: #testing
-
-Functional tests similar to `test/recipes/10-test_bn.t` must be added.
-
-Timing tests to compare operations on a variety of inputs of different sizes
-must also be added. These tests should perform operations based on a given
-fixed number size.
-
-It should also prove interesting to collect timing statistics for a set of
-operations using `BIGNUM` in previous OpenSSL versions and compare them with
-similar timing statistics using `BIGNUM` when reimplemented according to this
-design.
-
-Appendix
-========
-
-[Appendix]: #appendix
-
-Using the C99 flexible array member feature
--------------------------------------------
-
-[Using the C99 flexible array member feature]: #using-the-c99-flexible-array-member-feature
-
-In this design, the C99 feature that's dubbed "flexible array member" is used
-extensively. This a `struct` member that's an array, that must come last in
-the struct, and that is incomplete in so far that no array size is given. It
-can look like this:
-
-``` C
-struct t {
- size_t a;
- char b;
- char c[]; /**< flexible array member */
-};
-```
-
-Some attention must be paid to how it's arranged in memory. It's debated
-whether the offset of a flexible array member's offset from the start of the
-`struct` is set to be before or after the `struct`'s end padding, i.e. whether
-`sizeof(struct t) == offsetof(struct t, c)` is true or not in all circumstances.
-
-Here's how that would differ on a 64-bit system:
-
-| location of `c` | `offsetof(struct t, a)` | `offsetof(struct t, b)` | `offsetof(struct t, c)` | `sizeof(struct t)` |
-|-----------------|:-----------------------:|:-----------------------:|:-----------------------:|:------------------:|
-| before padding | 0 | 8 | 9 | 16 |
-| after padding | 0 | 8 | 16 | 16 |
-
-To be noted, `gcc` and `clang` favor "before padding".
-
-For consistent placement of the flexible array member, one therefore needs to
-pay attention to possible `struct` padding. Among other methods, one chosen
-here is to precede the flexible array member with a member whose type is
-assumed to be large enough that no padding is needed after it, such as
-`size_t` or a pointer.
diff --git a/doc/designs/passing-algorithmidentifier-parameters.md b/doc/designs/passing-algorithmidentifier-parameters.md
index 9c5669e86b..0e6126b056 100644
--- a/doc/designs/passing-algorithmidentifier-parameters.md
+++ b/doc/designs/passing-algorithmidentifier-parameters.md
@@ -129,10 +129,10 @@ at all when such parameter data needs to be passed.
Background / tl;dr
------------------
-### AlgorithmIdenfier parameter and how it's used
+### AlgorithmIdentifier parameter and how it's used
OpenSSL has historically done a few tricks to not have to pass
-AlgorithmIdenfier parameter data to the backend implementations of
+AlgorithmIdentifier parameter data to the backend implementations of
cryptographic operations:
- In some cases, they were passed as part of the lower level key structure
diff --git a/doc/designs/quic-design/quic-ackm.md b/doc/designs/quic-design/quic-ackm.md
index 488fded5e1..38d72aac3c 100644
--- a/doc/designs/quic-design/quic-ackm.md
+++ b/doc/designs/quic-design/quic-ackm.md
@@ -424,7 +424,7 @@ This should be called for a packet before attempting to process its contents.
Failure to do so may may result in processing a duplicated packet in violation
of the RFC.
-The returrn value of this function transitions from 1 to 0 for a given PN once
+The return value of this function transitions from 1 to 0 for a given PN once
that PN is passed to ossl_ackm_on_rx_packet, thus this function must be used
before calling `ossl_ackm_on_rx_packet`.
diff --git a/doc/designs/quic-design/quic-api-ssl-funcs.md b/doc/designs/quic-design/quic-api-ssl-funcs.md
index 6333bafab8..37229c26e6 100644
--- a/doc/designs/quic-design/quic-api-ssl-funcs.md
+++ b/doc/designs/quic-design/quic-api-ssl-funcs.md
@@ -108,9 +108,6 @@ Notes:
| `SSL_test_functions` | Global | 🟩U | 🟦U | 🟩NC | 🟢Done |
| `SSL_select_next_proto` | Global | 🟩U | 🟦U | 🟩NC | 🟢Done |
| **⇒ Methods** | | | | | |
-| `SSLv3_method` | Global | 🟩U | 🟦U | 🟩NC | 🟢Done |
-| `SSLv3_client_method` | Global | 🟩U | 🟦U | 🟩NC | 🟢Done |
-| `SSLv3_server_method` | Global | 🟩U | 🟦U | 🟩NC | 🟢Done |
| `TLS_method` | Global | 🟩U | 🟦U | 🟩NC | 🟢Done |
| `TLS_client_method` | Global | 🟩U | 🟦U | 🟩NC | 🟢Done |
| `TLS_server_method` | Global | 🟩U | 🟦U | 🟩NC | 🟢Done |
diff --git a/doc/designs/quic-design/quic-requirements.md b/doc/designs/quic-design/quic-requirements.md
index c8aeedc7b7..daeb50db66 100644
--- a/doc/designs/quic-design/quic-requirements.md
+++ b/doc/designs/quic-design/quic-requirements.md
@@ -60,7 +60,7 @@ and that were specific to QUIC
* For the MVP a single interop target (i.e. the server implementation list):
- 1. [Cloudfare](https://cloudflare-quic.com/)
+ 1. [Cloudflare](https://cloudflare-quic.com/)
* Testing against other implementations is not a release requirement for the MVP.
diff --git a/doc/internal/man3/bn_mul_words.pod b/doc/internal/man3/bn_mul_words.pod
index 7dc4267fd6..d2d8e3397a 100644
--- a/doc/internal/man3/bn_mul_words.pod
+++ b/doc/internal/man3/bn_mul_words.pod
@@ -4,7 +4,7 @@
bn_mul_words, bn_mul_add_words, bn_sqr_words, bn_div_words,
bn_add_words, bn_sub_words, bn_mul_comba4, bn_mul_comba8,
-bn_sqr_comba4, bn_sqr_comba8, bn_cmp_words, bn_mul_truncated, bn_mul_normal,
+bn_sqr_comba4, bn_sqr_comba8, bn_cmp_words, bn_mul_normal,
bn_mul_low_normal, bn_mul_recursive, bn_mul_part_recursive,
bn_mul_low_recursive, bn_sqr_normal, bn_sqr_recursive,
bn_expand, bn_wexpand, bn_expand2, bn_fix_top, bn_check_top,
@@ -32,8 +32,6 @@ library internal functions
int bn_cmp_words(BN_ULONG *a, BN_ULONG *b, int n);
- void bn_mul_truncated(BN_ULONG *r, int rn, BN_ULONG *a, int na,
- BN_ULONG *b, int nb);
void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b,
int nb);
void bn_mul_low_normal(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n);
@@ -153,11 +151,6 @@ bn_cmp_words(B, B, B) operates on the B word arrays B
and B. It returns 1, 0 and -1 if B is greater than, equal and
less than B.
-bn_mul_truncated(B, B, B, B, B, B) operates on the
-B word array B, the B word array B and the B word array
-B. It computes B*B and places the result in B, truncated to
-B words.
-
bn_mul_normal(B, B, B, B, B) operates on the B
word array B, the B word array B and the B+B word
array B. It computes B*B and places the result in B.
diff --git a/doc/internal/man3/evp_generic_fetch.pod b/doc/internal/man3/evp_generic_fetch.pod
index 016494239e..53f29c1e98 100644
--- a/doc/internal/man3/evp_generic_fetch.pod
+++ b/doc/internal/man3/evp_generic_fetch.pod
@@ -187,8 +187,7 @@ And here's the implementation of the FOO method fetcher:
EVP_FOO *foo = vfoo;
int ref = 0;
- CRYPTO_UP_REF(&foo->refcnt, &ref);
- return 1;
+ return CRYPTO_UP_REF(&foo->refcnt, &ref);
}
static void foo_free(void *vfoo)
diff --git a/doc/internal/man7/VERSION.pod b/doc/internal/man7/VERSION.pod
index 4bc8ba6b93..8ffd836c13 100644
--- a/doc/internal/man7/VERSION.pod
+++ b/doc/internal/man7/VERSION.pod
@@ -26,7 +26,7 @@ The keys that are recognised are:
The three parts of OpenSSL's 3 numbered version number, MAJOR.MINOR.PATCH.
These are used to compose the values for the C macros B,
-B, B.
+B, B.
=item B
diff --git a/doc/man1/openssl-ciphers.pod.in b/doc/man1/openssl-ciphers.pod.in
index c7e1291c83..db8b6e55e1 100644
--- a/doc/man1/openssl-ciphers.pod.in
+++ b/doc/man1/openssl-ciphers.pod.in
@@ -269,12 +269,12 @@ Cipher suites using DSS authentication, i.e. the certificates carry DSS keys.
Cipher suites using ECDSA authentication, i.e. the certificates carry ECDSA
keys.
-=item B, B, B
+=item B, B
-Lists cipher suites introduced in TLS v1.2, TLS v1.0 or SSL v3.0 respectively.
+Lists cipher suites introduced in TLS v1.2 or TLS v1.0 respectively.
Note: there are no cipher suites specific to TLS v1.1.
-Since this is only the minimum version, if, for example, TLSv1.0 is negotiated
-then both TLSv1.0 and SSLv3.0 cipher suites are available.
+Since this is only the minimum version, if, for example, TLSv1.2 is negotiated
+then both TLSv1.2 and TLSv1.0 cipher suites are available.
Note: these cipher strings B change the negotiated version of SSL or
TLS, they only affect the list of available cipher suites.
diff --git a/doc/man1/openssl-ec.pod.in b/doc/man1/openssl-ec.pod.in
index a60b796c00..2fd397da00 100644
--- a/doc/man1/openssl-ec.pod.in
+++ b/doc/man1/openssl-ec.pod.in
@@ -122,9 +122,6 @@ This specifies how the points on the elliptic curve are converted
into octet strings. Possible values are: B, B (the
default value) and B. For more information regarding
the point conversion forms please read the X9.62 standard.
-B Due to patent issues the B option is disabled
-by default for binary curves and can be enabled by defining
-the preprocessor macro B at compile time.
=item B<-param_enc> I
diff --git a/doc/man1/openssl-ecparam.pod.in b/doc/man1/openssl-ecparam.pod.in
index ca4e002762..d48f19d789 100644
--- a/doc/man1/openssl-ecparam.pod.in
+++ b/doc/man1/openssl-ecparam.pod.in
@@ -98,9 +98,6 @@ This specifies how the points on the elliptic curve are converted
into octet strings. Possible values are: B, B (the
default value) and B. For more information regarding
the point conversion forms please read the X9.62 standard.
-B Due to patent issues the B option is disabled
-by default for binary curves and can be enabled by defining
-the preprocessor macro B at compile time.
=item B<-param_enc> I
diff --git a/doc/man1/openssl-pkey.pod.in b/doc/man1/openssl-pkey.pod.in
index 52cc5712b2..bb6fcde863 100644
--- a/doc/man1/openssl-pkey.pod.in
+++ b/doc/man1/openssl-pkey.pod.in
@@ -179,12 +179,9 @@ This cannot be combined with encoded output in DER format.
This option only applies to elliptic-curve based keys.
This specifies how the points on the elliptic curve are converted
-into octet strings. Possible values are: B (the default
-value), B and B. For more information regarding
+into octet strings. Possible values are: B (the default
+value), B and B. For more information regarding
the point conversion forms please read the X9.62 standard.
-B Due to patent issues the B option is disabled
-by default for binary curves and can be enabled by defining
-the preprocessor macro B at compile time.
=item B<-ec_param_enc> I
diff --git a/doc/man1/openssl-pkeyutl.pod.in b/doc/man1/openssl-pkeyutl.pod.in
index 053385ca0b..590bfe3a6d 100644
--- a/doc/man1/openssl-pkeyutl.pod.in
+++ b/doc/man1/openssl-pkeyutl.pod.in
@@ -677,8 +677,10 @@ L,
=head1 HISTORY
Since OpenSSL 3.5,
-the B<-digest> option implies B<-rawin>, and these two options are
-no longer required when signing or verifying with an Ed25519 or Ed448 key.
+the B<-digest> option implies B<-rawin>. The B<-rawin> option is no longer
+required when signing or verifying with a key type that does not support a
+prehash digest, such as Ed25519, Ed448, ML-DSA, or SLH-DSA. For these key
+types, B<-digest> is not supported.
Also since OpenSSL 3.5, the B<-kemop> option is no longer required for any of
the supported algorithms, the only supported B is now the default.
diff --git a/doc/man1/openssl-rand.pod.in b/doc/man1/openssl-rand.pod.in
index d38961acc3..4d4cda2b4d 100644
--- a/doc/man1/openssl-rand.pod.in
+++ b/doc/man1/openssl-rand.pod.in
@@ -12,6 +12,7 @@ B
[B<-out> I]
[B<-base64>]
[B<-hex>]
+[B<-n>]
{- $OpenSSL::safe::opt_r_synopsis -}
{- $OpenSSL::safe::opt_provider_synopsis -}
I[K|M|G|T]
@@ -55,6 +56,10 @@ Perform base64 encoding on the output.
Show the output as a hex string.
+=item B<-n>
+
+Do not output the trailing newline.
+
{- $OpenSSL::safe::opt_r_item -}
{- $OpenSSL::safe::opt_provider_item -}
diff --git a/doc/man3/ASN1_INTEGER_get_int64.pod b/doc/man3/ASN1_INTEGER_get_int64.pod
index 4ba6c4c0d7..d25c87a5e2 100644
--- a/doc/man3/ASN1_INTEGER_get_int64.pod
+++ b/doc/man3/ASN1_INTEGER_get_int64.pod
@@ -108,7 +108,7 @@ B structure respectively or NULL if an error occurs. They will
only fail due to a memory allocation error.
ASN1_INTEGER_to_BN() and ASN1_ENUMERATED_to_BN() return a B structure
-of NULL if an error occurs. They can fail if the passed type is incorrect
+or NULL if an error occurs. They can fail if the passed type is incorrect
(due to programming error) or due to a memory allocation failure.
=head1 SEE ALSO
diff --git a/doc/man3/ASN1_STRING_length.pod b/doc/man3/ASN1_STRING_length.pod
index 47cacb253a..5b047f084a 100644
--- a/doc/man3/ASN1_STRING_length.pod
+++ b/doc/man3/ASN1_STRING_length.pod
@@ -2,6 +2,7 @@
=head1 NAME
+ASN1_STRING_set_data, ASN1_STRING_set_string, ASN1_STRING_length_ex,
ASN1_STRING_dup, ASN1_STRING_cmp, ASN1_STRING_set, ASN1_STRING_length,
ASN1_STRING_type, ASN1_STRING_get0_data,
ASN1_STRING_to_UTF8 - ASN1_STRING utility functions
@@ -10,19 +11,30 @@ ASN1_STRING_to_UTF8 - ASN1_STRING utility functions
#include
- int ASN1_STRING_length(ASN1_STRING *x);
const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x);
ASN1_STRING *ASN1_STRING_dup(const ASN1_STRING *a);
int ASN1_STRING_cmp(ASN1_STRING *a, ASN1_STRING *b);
- int ASN1_STRING_set(ASN1_STRING *str, const void *data, int len);
-
int ASN1_STRING_type(const ASN1_STRING *x);
int ASN1_STRING_to_UTF8(unsigned char **out, const ASN1_STRING *in);
+ int ASN1_STRING_set_data(ASN1_STRING *str, const uint8_t *data, size_t len);
+
+ int ASN1_STRING_set_string(ASN1_STRING *str, const char *data);
+
+ size_t ASN1_STRING_length_ex(const ASN1_STRING *x);
+
+The following functions have been deprecated since OpenSSL 4.1, and can be
+hidden entirely by defining B with a suitable version value,
+see L:
+
+ int ASN1_STRING_set(ASN1_STRING *str, const void *data, int len);
+
+ int ASN1_STRING_length(ASN1_STRING *x);
+
=head1 DESCRIPTION
These functions allow an B structure to be manipulated.
@@ -38,9 +50,25 @@ ASN1_STRING_dup() returns a copy of the structure I.
ASN1_STRING_cmp() compares I and I returning 0 if the two
are identical. The string types and content are compared.
-ASN1_STRING_set() sets the data of string I to the buffer
-I or length I. The supplied data is copied. If I
-is -1 then the length is determined by strlen(data).
+ASN1_STRING_set() allocates memory for string I to hold I
+bytes of data. Any previously allocated memory owned by I will be
+freed or re-used. If I is not NULL, I bytes are copied
+from the memory pointed to by I to I. If I is -1 then
+the length is determined by strlen(data).
+
+ASN1_STRING_set_data() allocates memory for string I to hold
+I bytes of data. Any previously allocated memory owned by I
+will be freed or re-used. If I is not NULL, I bytes are
+copied from the memory pointed to by I to I. It is an error
+to use this function on a string of type B.
+
+ASN1_STRING_set_string() allocates memory for the string I and makes
+a copy of the characters from I. Any previously
+allocated memory owned by I will be freed or re-used. I
+must point to a valid NUL-terminated C string, and must not be
+NULL. The terminating NUL byte is not included in the data copied into
+I. It is an error to use this function on a string of type
+B.
ASN1_STRING_type() returns the type of I, using standard constants
such as B.
@@ -70,8 +98,9 @@ actual string type itself: for example for an IA5String the data will
be ASCII, for a BMPString two bytes per character in big endian
format, and for a UTF8String it will be in UTF8 format.
-Similar care should be take to ensure the data is in the correct format
-when calling ASN1_STRING_set().
+Similar care should be taken to ensure the data is in the correct
+format when calling ASN1_STRING_set(), ASN1_STRING_set_data(), or
+ASN1_STRING_set_string().
=head1 RETURN VALUES
@@ -86,7 +115,8 @@ error occurred.
ASN1_STRING_cmp() returns an integer greater than, equal to, or less than 0,
according to whether I is greater than, equal to, or less than I.
-ASN1_STRING_set() returns 1 on success or 0 on error.
+ASN1_STRING_set(), ASN1_STRING_set_data(), and
+ASN1_STRING_set_string() return 1 on success or 0 on error or failure.
ASN1_STRING_type() returns the type of I.
@@ -97,6 +127,11 @@ negative value if an error occurred.
L
+=head1 HISTORY
+
+ASN1_STRING_set_data(), ASN1_STRING_set_string(), and ASN1_STRING_length_ex()
+were added in OpenSSL 4.1.
+
=head1 COPYRIGHT
Copyright 2002-2020 The OpenSSL Project Authors. All Rights Reserved.
diff --git a/doc/man3/ASN1_aux_cb.pod b/doc/man3/ASN1_aux_cb.pod
index 9963ea1350..9a38ab168f 100644
--- a/doc/man3/ASN1_aux_cb.pod
+++ b/doc/man3/ASN1_aux_cb.pod
@@ -59,7 +59,7 @@ Arbitrary application data
=item I
-Flags which indicate the auxiliarly functionality supported.
+Flags which indicate the auxiliary functionality supported.
The B flag indicates that objects support reference counting.
@@ -106,9 +106,11 @@ During the processing of an B object the callbacks set via
I or I will be invoked as a result of various events
indicated via the I parameter. The value of I<*in> will be the
B object being processed based on the template in I. An
-additional operation specific parameter may be passed in I. The currently
-supported operations are as follows. The callbacks should return a positive
-value on success or zero on error, unless otherwise noted below.
+additional operation specific parameter may be passed in I. The
+currently supported operations are as follows. Unless noted otherwise below,
+the callbacks should return a positive value on success and zero on error;
+some operations recognise additional return values, and a few do not consult
+the return value at all.
=over 4
@@ -130,13 +132,15 @@ I<*pval>.
Invoked when processing a B, B or B structure
immediately before an B is freed. If the callback originally
constructed the B via B then it should free it at
-this point and return 2 from the callback. Otherwise it should return 1 for
-success or 0 on error.
+this point and return 2; the caller will then skip its normal freeing. Any
+other return value (including zero) causes the caller to proceed with normal
+freeing; the hook cannot signal an error.
=item B
Invoked when processing a B, B or B structure
-immediately after B sub-structures are freed.
+immediately after B sub-structures are freed. The caller does not
+consult the return value from this hook.
=item B
@@ -162,7 +166,10 @@ immediately after a "i2d" operation for the B.
Invoked when processing a B or B structure immediately
before printing the B. The I argument will be a pointer to an
-B structure (see below).
+B structure (see below). If the callback has fully printed the
+value itself it should return 2; the caller will then skip the per-field
+printing loop and the matching B callback. Return zero on
+error or any other positive value to continue with normal printing.
=item B
@@ -260,8 +267,41 @@ The streaming I/O boundary.
=head1 RETURN VALUES
-The callbacks return 0 on error and a positive value on success. Some operations
-require specific positive success values as noted above.
+In general the callbacks return zero on error and a positive value on
+success. Several operations have additional or different return-value
+semantics, summarised here:
+
+=over 4
+
+=item *
+
+B recognises a return of 2, meaning that the callback has
+allocated the B itself and normal allocation should be skipped.
+
+=item *
+
+B recognises a return of 2, meaning that the callback has
+freed the B itself and normal freeing should be skipped. Other
+return values (including zero) cause normal freeing to proceed; the hook
+cannot signal an error.
+
+=item *
+
+B's return value is not consulted by the caller.
+
+=item *
+
+B recognises a return of 2, meaning that the callback
+has printed the value itself; the caller will skip the per-field printing
+loop and the matching B invocation.
+
+=item *
+
+B, B, B, and
+B treat any non-positive return value (zero or
+negative) as an error.
+
+=back
=head1 SEE ALSO
diff --git a/doc/man3/ASN1_item_d2i_bio.pod b/doc/man3/ASN1_item_d2i_bio.pod
index f8e4678367..9b3f389a23 100644
--- a/doc/man3/ASN1_item_d2i_bio.pod
+++ b/doc/man3/ASN1_item_d2i_bio.pod
@@ -59,6 +59,16 @@ B provided in the I parameter and the property query
string in I. See L for more information
about algorithm fetching.
+When reading from I, decoding consumes one complete DER-encoded structure
+and leaves any following bytes in the BIO, so concatenated structures can be
+read with successive calls. Reaching the end of the input cleanly, at a
+structure boundary, is not treated as an error: the function returns NULL
+without adding to the error queue. If the end of the input is reached in the
+middle of a structure, or an indefinite-length value is missing its
+end-of-contents octets (that is, the input is truncated), an error is queued
+with reason code B. The same applies to
+ASN1_item_d2i_fp_ex().
+
ASN1_item_d2i_bio() is the same as ASN1_item_d2i_bio_ex() except that the
default B is used (i.e. NULL) and with a NULL property query
string.
@@ -92,6 +102,12 @@ that the I and I can be used when doing algorithm fetching.
ASN1_item_d2i_bio(), ASN1_item_unpack_ex() and ASN1_item_unpack() return a pointer to
an B or NULL on error.
+The ASN1_item_d2i_bio() and ASN1_item_d2i_fp() functions, including their
+B<_ex> variants, also return NULL at a clean end of input. In that case the
+error queue is left unchanged, so a caller reading concatenated structures in
+a loop can distinguish a clean end of input from a decoding error by
+inspecting the error queue, for example with L.
+
ASN1_item_i2d_mem_bio() returns a pointer to a memory BIO or NULL on error.
ASN1_item_pack() returns a pointer to an B or NULL on error.
@@ -105,7 +121,7 @@ The function ASN1_item_unpack_ex() was added in OpenSSL 3.2.
=head1 COPYRIGHT
-Copyright 2021-2023 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2021-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
diff --git a/doc/man3/BIO_s_datagram.pod b/doc/man3/BIO_s_datagram.pod
index 634c3a9af4..b28dcf088c 100644
--- a/doc/man3/BIO_s_datagram.pod
+++ b/doc/man3/BIO_s_datagram.pod
@@ -65,7 +65,7 @@ the underlying socket is configured and how it is to be used; see below.
=item
-Use of BIO_s_datagram() with an unconnected network socket is hazardous hecause
+Use of BIO_s_datagram() with an unconnected network socket is hazardous because
any successful call to BIO_read() results in the peer address used for any
subsequent call to BIO_write() being set to the source address of the datagram
received by that call to BIO_read(). Thus, unless the caller calls
diff --git a/doc/man3/BIO_s_file.pod b/doc/man3/BIO_s_file.pod
index 5dcd4bbbca..6cd1da02a3 100644
--- a/doc/man3/BIO_s_file.pod
+++ b/doc/man3/BIO_s_file.pod
@@ -14,8 +14,8 @@ BIO_rw_filename - FILE bio
BIO *BIO_new_file(const char *filename, const char *mode);
BIO *BIO_new_fp(FILE *stream, int flags);
- BIO_set_fp(BIO *b, FILE *fp, int flags);
- BIO_get_fp(BIO *b, FILE **fpp);
+ long BIO_set_fp(BIO *b, FILE *fp, int flags);
+ long BIO_get_fp(BIO *b, FILE **fpp);
int BIO_read_filename(BIO *b, char *name);
int BIO_write_filename(BIO *b, char *name);
@@ -87,8 +87,7 @@ BIO_s_file() returns the file BIO method.
BIO_new_file() and BIO_new_fp() return a file BIO or NULL if an error
occurred.
-BIO_set_fp() and BIO_get_fp() return 1 for success or <=0 for failure
-(although the current implementation never return 0).
+BIO_set_fp() and BIO_get_fp() return 1 for success or <=0 for failure.
BIO_seek() returns 0 for success or negative values for failure.
diff --git a/doc/man3/CMS_EncryptedData_decrypt.pod b/doc/man3/CMS_EncryptedData_decrypt.pod
index 80bbdcc95f..f7375f2c58 100644
--- a/doc/man3/CMS_EncryptedData_decrypt.pod
+++ b/doc/man3/CMS_EncryptedData_decrypt.pod
@@ -46,7 +46,7 @@ are used when retrieving algorithms from providers.
CMS_EncryptedData_decrypt() returns 0 if an error occurred otherwise returns 1.
CMS_EnvelopedData_decrypt() returns NULL if an error occurred,
-otherwise a BIO containing the decypted content.
+otherwise a BIO containing the decrypted content.
=head1 SEE ALSO
diff --git a/doc/man3/EVP_KDF.pod b/doc/man3/EVP_KDF.pod
index b9cc14eb79..6df44e8643 100644
--- a/doc/man3/EVP_KDF.pod
+++ b/doc/man3/EVP_KDF.pod
@@ -6,7 +6,7 @@ EVP_KDF, EVP_KDF_fetch, EVP_KDF_free, EVP_KDF_up_ref,
EVP_KDF_CTX, EVP_KDF_CTX_new, EVP_KDF_CTX_free, EVP_KDF_CTX_dup,
EVP_KDF_CTX_reset, EVP_KDF_derive,
EVP_KDF_CTX_set_SKEY, EVP_KDF_derive_SKEY,
-EVP_KDF_CTX_get_kdf_size,
+EVP_KDF_CTX_get_kdf_size, EVP_KDF_CTX_get0_kdf, EVP_KDF_CTX_get1_kdf,
EVP_KDF_get0_provider, EVP_KDF_CTX_kdf, EVP_KDF_is_a,
EVP_KDF_get0_name, EVP_KDF_names_do_all, EVP_KDF_get0_description,
EVP_KDF_CTX_get_params, EVP_KDF_CTX_set_params, EVP_KDF_do_all_provided,
@@ -22,7 +22,8 @@ EVP_KDF_CTX_gettable_params, EVP_KDF_CTX_settable_params - EVP KDF routines
typedef struct evp_kdf_ctx_st EVP_KDF_CTX;
EVP_KDF_CTX *EVP_KDF_CTX_new(EVP_KDF *kdf);
- const EVP_KDF *EVP_KDF_CTX_kdf(EVP_KDF_CTX *ctx);
+ const EVP_KDF *EVP_KDF_CTX_get0_kdf(const EVP_KDF_CTX *ctx);
+ EVP_KDF *EVP_KDF_CTX_get1_kdf(EVP_KDF_CTX *ctx);
void EVP_KDF_CTX_free(EVP_KDF_CTX *ctx);
EVP_KDF_CTX *EVP_KDF_CTX_dup(const EVP_KDF_CTX *src);
void EVP_KDF_CTX_reset(EVP_KDF_CTX *ctx);
@@ -57,6 +58,12 @@ EVP_KDF_CTX_gettable_params, EVP_KDF_CTX_settable_params - EVP KDF routines
const OSSL_PARAM *EVP_KDF_CTX_settable_params(const EVP_KDF *kdf);
const OSSL_PROVIDER *EVP_KDF_get0_provider(const EVP_KDF *kdf);
+The following functions have been deprecated since OpenSSL 4.1,
+and can be hidden entirely by defining B with a suitable
+version value, see L:
+
+ const EVP_KDF *EVP_KDF_CTX_kdf(const EVP_KDF_CTX *ctx);
+
=head1 DESCRIPTION
The EVP KDF routines are a high-level interface to Key Derivation Function
@@ -99,8 +106,10 @@ EVP_KDF_CTX_new() creates a new context for the KDF implementation I.
EVP_KDF_CTX_free() frees up the context I. If I is NULL, nothing
is done.
-EVP_KDF_CTX_kdf() returns the B associated with the context
-I.
+EVP_KDF_CTX_get0_kdf() returns the B associated with the context
+I. EVP_KDF_CTX_get1_kdf() is the same, except ownership is passed
+to the caller.
+EVP_KDF_CTX_kdf() is an alias for EVP_KDF_CTX_get0_kdf().
=head2 Computing functions
@@ -324,6 +333,12 @@ This functionality was added in OpenSSL 3.0.
EVP_KDF_derive_SKEY() and EVP_KDF_CTX_set_SKEY() functions were introduced in
OpenSSL 3.6.
+EVP_KDF_CTX_get0_kdf() and EVP_KDF_CTX_get1_kdf() functions were introduced
+in OpenSSL 4.1.
+
+EVP_KDF_CTX_kdf() function was deprecated in favour of EVP_KDF_CTX_get0_kdf()
+in OpenSSL 4.1.
+
=head1 COPYRIGHT
Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved.
diff --git a/doc/man3/EVP_MAC.pod b/doc/man3/EVP_MAC.pod
index e5b05701f7..1ca411e5d7 100644
--- a/doc/man3/EVP_MAC.pod
+++ b/doc/man3/EVP_MAC.pod
@@ -147,7 +147,7 @@ as part of this call or separately using EVP_MAC_CTX_set_params().
Providing non-NULL I to this function is equivalent to calling
EVP_MAC_CTX_set_params() with those I for the same I beforehand.
Note: There are additional requirements for some MAC algorithms during
-re-initalization (i.e. calling EVP_MAC_init() on an EVP_MAC after EVP_MAC_final()
+re-initialization (i.e. calling EVP_MAC_init() on an EVP_MAC after EVP_MAC_final()
has been called on the same object). See the NOTES section below.
EVP_MAC_init() should be called before EVP_MAC_update() and EVP_MAC_final().
@@ -352,7 +352,7 @@ The usage of the parameter names "custom", "iv" and "salt" correspond to
the names used in the standard where the algorithm was defined.
Some MAC algorithms store internal state that cannot be extracted during
-re-initalization. For example GMAC cannot extract an B from the
+re-initialization. For example GMAC cannot extract an B from the
underlying CIPHER context, and so calling EVP_MAC_init() on an EVP_MAC object
after EVP_MAC_final() has been called cannot reset its cipher state to what it
was when the B was initially generated. For such instances, an
diff --git a/doc/man3/EVP_PKEY_CTX_new.pod b/doc/man3/EVP_PKEY_CTX_new.pod
index fff102a769..9ded13de5d 100644
--- a/doc/man3/EVP_PKEY_CTX_new.pod
+++ b/doc/man3/EVP_PKEY_CTX_new.pod
@@ -48,6 +48,9 @@ EVP_PKEY_CTX_new_id() and EVP_PKEY_CTX_new_from_name() are normally
used when no B structure is associated with the operations,
for example during parameter generation or key generation for some
algorithms.
+The key returned by L is not associated with the
+generation context. To perform operations using that key, create a new context
+with L.
EVP_PKEY_CTX_dup() duplicates the context I.
It is not supported for a keygen operation.
@@ -125,7 +128,7 @@ added in OpenSSL 3.0.
=head1 COPYRIGHT
-Copyright 2006-2025 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
diff --git a/doc/man3/EVP_PKEY_decrypt.pod b/doc/man3/EVP_PKEY_decrypt.pod
index 5e624e8c61..6b46329793 100644
--- a/doc/man3/EVP_PKEY_decrypt.pod
+++ b/doc/man3/EVP_PKEY_decrypt.pod
@@ -17,12 +17,13 @@ EVP_PKEY_decrypt - decrypt using a public key algorithm
=head1 DESCRIPTION
-The EVP_PKEY_decrypt_init() function initializes a public key algorithm
-context using key I for a decryption operation.
+The EVP_PKEY_decrypt_init() function initializes the public key algorithm
+context I for a decryption operation. A key must already be associated
+with I; this is normally done by creating it with
+L or L.
-The EVP_PKEY_decrypt_init_ex() function initializes a public key algorithm
-context using key I for a decryption operation and sets the
-algorithm specific I.
+The EVP_PKEY_decrypt_init_ex() function is the same as
+EVP_PKEY_decrypt_init() but additionally sets the algorithm-specific I.
The EVP_PKEY_decrypt() function performs a public key decryption operation
using I. The data to be decrypted is specified using the I and
@@ -88,7 +89,7 @@ Decrypt data using OAEP (for RSA keys):
* NB: assumes key, in, inlen are already set up
* and that key is an RSA private key
*/
- ctx = EVP_PKEY_CTX_new(key, NULL);
+ ctx = EVP_PKEY_CTX_new_from_pkey(NULL, key, NULL);
if (!ctx)
/* Error occurred */
if (EVP_PKEY_decrypt_init(ctx) <= 0)
@@ -125,7 +126,7 @@ These functions were added in OpenSSL 1.0.0.
=head1 COPYRIGHT
-Copyright 2006-2025 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
diff --git a/doc/man3/EVP_PKEY_encrypt.pod b/doc/man3/EVP_PKEY_encrypt.pod
index 1fb41f99f4..fda95c218e 100644
--- a/doc/man3/EVP_PKEY_encrypt.pod
+++ b/doc/man3/EVP_PKEY_encrypt.pod
@@ -17,12 +17,13 @@ EVP_PKEY_encrypt_init, EVP_PKEY_encrypt - encrypt using a public key algorithm
=head1 DESCRIPTION
-The EVP_PKEY_encrypt_init() function initializes a public key algorithm
-context using key B for an encryption operation.
+The EVP_PKEY_encrypt_init() function initializes the public key algorithm
+context I for an encryption operation. A key must already be associated
+with I; this is normally done by creating it with
+L or L.
-The EVP_PKEY_encrypt_init_ex() function initializes a public key algorithm
-context using key B for an encryption operation and sets the
-algorithm specific B.
+The EVP_PKEY_encrypt_init_ex() function is the same as
+EVP_PKEY_encrypt_init() but additionally sets the algorithm-specific I.
The EVP_PKEY_encrypt() function performs a public key encryption operation
using B. The data to be encrypted is specified using the B and
@@ -66,7 +67,7 @@ L for means to load a public key.
* NB: assumes key, in, inlen are already set up,
* and that key is an RSA public key
*/
- ctx = EVP_PKEY_CTX_new(key, NULL);
+ ctx = EVP_PKEY_CTX_new_from_pkey(NULL, key, NULL);
if (!ctx)
/* Error occurred */
if (EVP_PKEY_encrypt_init(ctx) <= 0)
@@ -104,7 +105,7 @@ These functions were added in OpenSSL 1.0.0.
=head1 COPYRIGHT
-Copyright 2006-2021 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
diff --git a/doc/man3/EVP_PKEY_keygen.pod b/doc/man3/EVP_PKEY_keygen.pod
index 1d5180ef6f..71daed31c0 100644
--- a/doc/man3/EVP_PKEY_keygen.pod
+++ b/doc/man3/EVP_PKEY_keygen.pod
@@ -66,6 +66,12 @@ parameters or key are written to I<*ppkey>. If I<*ppkey> is NULL when this
function is called, it will be allocated, and should be freed by the caller
when no longer useful, using L.
+When a key is generated, EVP_PKEY_generate() does not associate it with I
+or change I into a context for operations using that key. To use the
+generated key, create a new context with L,
+passing I<*ppkey>. The generation context can be reused for further generation
+operations or freed.
+
EVP_PKEY_paramgen() and EVP_PKEY_keygen() do exactly the same thing as
EVP_PKEY_generate(), after checking that the corresponding EVP_PKEY_paramgen_init()
or EVP_PKEY_keygen_init() was used to initialize I.
@@ -153,7 +159,7 @@ in functions which require the use of a public key or parameters.
=head1 EXAMPLES
-Generate a 2048 bit RSA key:
+Generate a 2048 bit RSA key, then initialize a context for encryption:
#include
#include
@@ -161,7 +167,7 @@ Generate a 2048 bit RSA key:
EVP_PKEY_CTX *ctx;
EVP_PKEY *pkey = NULL;
- ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
+ ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
if (!ctx)
/* Error occurred */
if (EVP_PKEY_keygen_init(ctx) <= 0)
@@ -170,7 +176,15 @@ Generate a 2048 bit RSA key:
/* Error */
/* Generate key */
- if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
+ if (EVP_PKEY_generate(ctx, &pkey) <= 0)
+ /* Error */
+
+ /* ctx is still a generation context; pkey contains the generated key */
+ EVP_PKEY_CTX_free(ctx);
+ ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL);
+ if (!ctx)
+ /* Error occurred */
+ if (EVP_PKEY_encrypt_init(ctx) <= 0)
/* Error */
Generate a key from a set of parameters:
diff --git a/doc/man3/EVP_PKEY_verify_recover.pod b/doc/man3/EVP_PKEY_verify_recover.pod
index 10084d61c1..52682f2aa5 100644
--- a/doc/man3/EVP_PKEY_verify_recover.pod
+++ b/doc/man3/EVP_PKEY_verify_recover.pod
@@ -22,10 +22,10 @@ EVP_PKEY_verify_recover_init_ex2, EVP_PKEY_verify_recover
=head1 DESCRIPTION
EVP_PKEY_verify_recover_init() initializes a public key algorithm context
-I for signing using the algorithm given when the context was created
-using L or variants thereof. The algorithm is used to
-fetch a B method implicitly, see L
-for more information about implicit fetches.
+I for a verify-recover operation using the algorithm given when the
+context was created using L or variants thereof. The
+algorithm is used to fetch a B method implicitly, see
+L for more information about implicit fetches.
EVP_PKEY_verify_recover_init_ex() is the same as
EVP_PKEY_verify_recover_init() but additionally sets the passed parameters
@@ -35,8 +35,8 @@ EVP_PKEY_verify_recover_init_ex2() is the same as EVP_PKEY_verify_recover_init_e
but works with an explicitly fetched B I.
A context I without a pre-loaded key cannot be used with this function.
Depending on what algorithm was fetched, certain details revolving around the
-treatment of the input to EVP_PKEY_verify() may be pre-determined, and in that
-case, those details may normally not be changed.
+treatment of the input to EVP_PKEY_verify_recover() may be pre-determined, and
+in that case, those details may normally not be changed.
See L below for a deeper explanation.
The EVP_PKEY_verify_recover() function recovers signed data
@@ -132,7 +132,7 @@ The EVP_PKEY_verify_recover_init_ex() function was added in OpenSSL 3.0.
=head1 COPYRIGHT
-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
diff --git a/doc/man3/HMAC.pod b/doc/man3/HMAC.pod
index 53a3853eb2..d6cd404ab6 100644
--- a/doc/man3/HMAC.pod
+++ b/doc/man3/HMAC.pod
@@ -112,6 +112,9 @@ be authenticated (I bytes at I).
HMAC_Final() places the message authentication code in I, which
must have space for the hash function output.
+After calling HMAC_Final() no calls to HMAC_Update() or HMAC_Final() can be
+made, but HMAC_Init_ex() can be called to initialize a new HMAC
+operation.
HMAC_CTX_copy() copies all of the internal state from I into I.
diff --git a/doc/man3/NAME_CONSTRAINTS_check.pod b/doc/man3/NAME_CONSTRAINTS_check.pod
new file mode 100644
index 0000000000..3dfe39ea29
--- /dev/null
+++ b/doc/man3/NAME_CONSTRAINTS_check.pod
@@ -0,0 +1,211 @@
+=pod
+
+=head1 NAME
+
+NAME_CONSTRAINTS_check,
+NAME_CONSTRAINTS_check_CN - check a certificate's names against a name
+constraints extension
+
+=head1 SYNOPSIS
+
+ #include
+
+ int NAME_CONSTRAINTS_check(const X509 *x, NAME_CONSTRAINTS *nc);
+ int NAME_CONSTRAINTS_check_CN(const X509 *x, NAME_CONSTRAINTS *nc);
+
+=head1 DESCRIPTION
+
+NAME_CONSTRAINTS_check() tests whether the names asserted by certificate
+I satisfy the name constraints I. It implements the matching
+primitive of RFC 5280 section 4.2.1.10: given a constraint set (a
+B structure containing zero or more B
+and B) and a candidate certificate, decide whether the
+certificate's names fall within the permitted subtrees and outside the
+excluded subtrees.
+
+The names considered by NAME_CONSTRAINTS_check() are:
+
+=over 4
+
+=item *
+
+The certificate's subject distinguished name, matched as a B
+general-name type. The subject is considered only when it is nonempty.
+
+=item *
+
+Each B attribute appearing within the subject distinguished
+name, matched as an B general-name type. These attributes are
+the historical, pre-SAN way of expressing an email address in a
+certificate's subject, and RFC 5280 requires that they be subjected to
+name-constraint checking.
+
+=item *
+
+Each entry in the certificate's subject alternative name extension, matched
+according to its declared general-name type.
+
+=back
+
+NAME_CONSTRAINTS_check() implements matching for the following
+general-name types: B, B, B,
+B, and B. The B form
+B