diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml new file mode 100644 index 0000000000000..86a53a2abaebb --- /dev/null +++ b/.github/workflows/backport.yml @@ -0,0 +1,64 @@ +# 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: Backports CI + +on: [pull_request] + +permissions: + contents: read + +jobs: + check_backports: + strategy: + fail-fast: false + matrix: + release: [ + { + branch: '4.0', + cppflags: '' + }, { + branch: '3.6', + cppflags: '' + }, { + branch: '3.5', + cppflags: 'CPPFLAGS=-ansi' + }, { + branch: '3.4', + cppflags: 'CPPFLAGS=-ansi' + }, { + branch: '3.0', + cppflags: 'CPPFLAGS=-ansi' + } + ] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + if: ${{ contains(join(github.event.pull_request.labels.*.name,','),matrix.release.branch) }} + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + persist-credentials: false + - name: cherry-pick + if: ${{ contains(join(github.event.pull_request.labels.*.name,','),matrix.release.branch) }} + run: | + REFEND=$(git rev-parse HEAD) + REFSTART=$(git rev-parse $REFEND~${{ github.event.pull_request.commits }}) + git checkout ${{ format('openssl-{0}', matrix.release.branch) }} + git config user.name "OpenSSL Machine" + git config user.email "openssl-machine@openssl.org" + echo Cherry-picking $REFSTART..$REFEND + git cherry-pick $REFSTART..$REFEND || { git diff | head -n1000; exit 1; } + - name: config + if: ${{ contains(join(github.event.pull_request.labels.*.name,','),matrix.release.branch) }} + run: ${{ matrix.release.cppflags }} ./config --strict-warnings --banner=Configured no-asm enable-fips --strict-warnings -D_DEFAULT_SOURCE && perl configdata.pm --dump + - name: make + if: ${{ contains(join(github.event.pull_request.labels.*.name,','),matrix.release.branch) }} + run: make -s -j4 + - name: make test + if: ${{ contains(join(github.event.pull_request.labels.*.name,','),matrix.release.branch) }} + run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed42020800d28..482235a1d974d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -714,9 +714,37 @@ jobs: ./util/opensslwrap.sh version -c - name: test external oqs-provider run: make test TESTS="test_external_oqsprovider" - # Disabled temporarily: https://github.com/latchset/pkcs11-provider/pull/525#discussion_r1982805969 - # - name: test external pkcs11-provider - # run: make test TESTS="test_external_pkcs11_provider" VERBOSE=1 + + external-tests-pkcs11-provider: + runs-on: ubuntu-latest + container: fedora:latest + steps: + - name: package installs + run: | + dnf install -y perl-FindBin perl-IPC-Cmd perl-File-Compare perl-File-Copy perl-Test-Simple perl-Test-Harness python3 make g++ perl git meson opensc expect kryoptic xxd + - uses: actions/checkout@v6 + with: + persist-credentials: false + - name: checkout fuzz/corpora and pkcs11-provider submodule + run: | + git config --global --add safe.directory "$GITHUB_WORKSPACE" + git submodule update --init --depth 1 fuzz/corpora + git submodule update --init --depth 1 pkcs11-provider + - name: config + run: ./config --strict-warnings --banner=Configured --debug enable-external-tests no-fips && perl configdata.pm --dump + - name: make + run: make -s -j4 + # Run all tests except external tests to make sure they work fine on Fedora because + # this is the only job running on Fedora, only then execute pkcs11-provider external + # test. + - name: test (except external tests) + run: make test TESTS="-test_external_*" + - name: test external pkcs11-provider + run: make test TESTS="test_external_pkcs11_provider" VERBOSE=1 + - name: get cpu info + run: | + cat /proc/cpuinfo + ./util/opensslwrap.sh version -c external-tests-pyca: runs-on: ubuntu-latest diff --git a/.github/workflows/coveralls.yml b/.github/workflows/coveralls.yml index f997726145795..b270841fa72ab 100644 --- a/.github/workflows/coveralls.yml +++ b/.github/workflows/coveralls.yml @@ -51,15 +51,6 @@ jobs: },{ "branch": "openssl-3.4", "extra_config": "no-afalgeng enable-fips enable-tfo" - }, { - "branch": "openssl-3.3", - "extra_config": "no-afalgeng enable-fips enable-tfo" - }, { - "branch": "openssl-3.2", - "extra_config": "no-afalgeng enable-fips enable-tfo" - }, { - "branch": "openssl-3.1", - "extra_config": "no-afalgeng enable-fips" }, { "branch": "openssl-3.0", "extra_config": "no-afalgeng enable-fips" diff --git a/.github/workflows/cross-compiles.yml b/.github/workflows/cross-compiles.yml index 6b061aefa5233..08b25335befb2 100644 --- a/.github/workflows/cross-compiles.yml +++ b/.github/workflows/cross-compiles.yml @@ -107,6 +107,10 @@ jobs: fips: no }, { arch: riscv64-linux-gnu, + # Pin the vector spec version, otherwise qemu-user emits a + # "vector version is not specified" warning on stderr at every + # process start, which upsets tests that parse or check stderr. + qemucpu: "rv64,v=true,vext_spec=v1.0", libs: libc6-dev-riscv64-cross, target: linux64-riscv64, fips: no diff --git a/.github/workflows/os-zoo.yml b/.github/workflows/os-zoo.yml index 74208d01029fd..bd5d641ec8a60 100644 --- a/.github/workflows/os-zoo.yml +++ b/.github/workflows/os-zoo.yml @@ -137,7 +137,7 @@ jobs: - os: windows-2022 vcvars: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat - os: windows-2025 - vcvars: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat + vcvars: C:\Program Files\Microsoft Visual Studio\18\Enterprise\VC\Auxiliary\Build\vcvars64.bat runs-on: ${{ matrix.platform.os }} steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/prov-compat-label.yml b/.github/workflows/prov-compat-label.yml index 46c6eaf3b0bbf..a129338eac6e9 100644 --- a/.github/workflows/prov-compat-label.yml +++ b/.github/workflows/prov-compat-label.yml @@ -16,7 +16,7 @@ permissions: contents: read env: - opts: enable-rc5 enable-md2 enable-ssl3 enable-weak-ssl-ciphers enable-zlib + opts: enable-rc5 enable-md2 enable-weak-ssl-ciphers enable-zlib jobs: fips-releases: @@ -113,10 +113,6 @@ jobs: name: openssl-3.0, dir: branch-3.0, tgz: branch-3.0.tar.gz, - }, { - name: openssl-3.3, - dir: branch-3.3, - tgz: branch-3.3.tar.gz, }, { name: openssl-3.4, dir: branch-3.4, @@ -197,7 +193,7 @@ jobs: # Note that releases are not used as a test environment for # later providers. Problems in these situations ought to be # caught by cross branch testing before the release. - tree_a: [ branch-3.6, branch-3.5, branch-3.4, branch-3.3, branch-3.0, + tree_a: [ branch-3.6, branch-3.5, branch-3.4, branch-3.0, openssl-3.0.0, openssl-3.0.8, openssl-3.0.9, openssl-3.1.2 ] tree_b: [ PR ] include: @@ -209,8 +205,6 @@ jobs: tree_b: branch-3.5 - tree_a: PR tree_b: branch-3.4 - - tree_a: PR - tree_b: branch-3.3 - tree_a: PR tree_b: branch-3.0 steps: diff --git a/.github/workflows/provider-compatibility.yml b/.github/workflows/provider-compatibility.yml index a664b831f8669..c5546784c01af 100644 --- a/.github/workflows/provider-compatibility.yml +++ b/.github/workflows/provider-compatibility.yml @@ -117,11 +117,6 @@ jobs: dir: branch-3.0, tgz: branch-3.0.tar.gz, extra_config: "", - }, { - name: openssl-3.3, - dir: branch-3.3, - tgz: branch-3.3.tar.gz, - extra_config: "", }, { name: openssl-3.4, dir: branch-3.4, @@ -204,11 +199,9 @@ jobs: # Note that releases are not used as a test environment for # later providers. Problems in these situations ought to be # caught by cross branch testing before the release. - tree_a: [ branch-master, branch-3.6, branch-3.5, branch-3.4, branch-3.3, - branch-3.0, + tree_a: [ branch-master, branch-3.6, branch-3.5, branch-3.4, branch-3.0, openssl-3.0.0, openssl-3.0.8, openssl-3.0.9, openssl-3.1.2 ] - tree_b: [ branch-master, branch-3.6, branch-3.5, branch-3.4, branch-3.3, - branch-3.0 ] + tree_b: [ branch-master, branch-3.6, branch-3.5, branch-3.4, branch-3.0 ] steps: - name: early exit checks id: early_exit diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index a3449c74bfe2a..858f80c683474 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -25,7 +25,7 @@ jobs: - arch: amd64 os: windows-2025 config: enable-fips no-thread-pool no-quic - vcvars: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat + vcvars: C:\Program Files\Microsoft Visual Studio\18\Enterprise\VC\Auxiliary\Build\vcvars64.bat - arch: x86 os: windows-2022 config: no-fips diff --git a/.github/workflows/windows_comp.yml b/.github/workflows/windows_comp.yml index bdc9ebbebee20..a35cd06352550 100644 --- a/.github/workflows/windows_comp.yml +++ b/.github/workflows/windows_comp.yml @@ -42,14 +42,14 @@ jobs: working-directory: _build shell: cmd run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" + call "C:\Program Files\Microsoft Visual Studio\18\Enterprise\VC\Auxiliary\Build\vcvars64.bat" perl ..\Configure enable-comp enable-zstd --with-zstd-include=C:\vcpkg\packages\zstd_x64-windows\include --with-zstd-lib=C:\vcpkg\packages\zstd_x64-windows\lib\zstd.lib no-makedepend -DOSSL_WINCTX=openssl VC-WIN64A 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" + call "C:\Program Files\Microsoft Visual Studio\18\Enterprise\VC\Auxiliary\Build\vcvars64.bat" nmake - name: Gather openssl version info working-directory: _build @@ -81,7 +81,7 @@ jobs: working-directory: _build shell: cmd run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" + call "C:\Program Files\Microsoft Visual Studio\18\Enterprise\VC\Auxiliary\Build\vcvars64.bat" nmake test VERBOSE_FAILURE=yes TESTS="-test_fuzz* -test_fipsload" HARNESS_JOBS=4 brotli: @@ -106,14 +106,14 @@ jobs: working-directory: _build shell: cmd run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" + call "C:\Program Files\Microsoft Visual Studio\18\Enterprise\VC\Auxiliary\Build\vcvars64.bat" perl ..\Configure enable-comp enable-brotli --with-brotli-include=C:\vcpkg\packages\brotli_x64-windows\include --with-brotli-lib=C:\vcpkg\packages\brotli_x64-windows\lib no-makedepend -DOSSL_WINCTX=openssl VC-WIN64A 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" + call "C:\Program Files\Microsoft Visual Studio\18\Enterprise\VC\Auxiliary\Build\vcvars64.bat" nmake - name: Gather openssl version info working-directory: _build @@ -145,5 +145,5 @@ jobs: working-directory: _build shell: cmd run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" + call "C:\Program Files\Microsoft Visual Studio\18\Enterprise\VC\Auxiliary\Build\vcvars64.bat" nmake test VERBOSE_FAILURE=yes TESTS="-test_fuzz* -test_fipsload" HARNESS_JOBS=4 diff --git a/.gitmodules b/.gitmodules index b4c756a67b179..e69de29bb2d1d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,37 +0,0 @@ -[submodule "pyca.cryptography"] - path = pyca-cryptography - url = https://github.com/pyca/cryptography.git - -[submodule "krb5"] - path = krb5 - url = https://github.com/krb5/krb5 - -[submodule "gost-engine"] - path = gost-engine - url = https://github.com/gost-engine/engine - update = rebase -[submodule "wycheproof"] - path = wycheproof - url = https://github.com/google/wycheproof -[submodule "tlsfuzzer"] - path = tlsfuzzer - url = https://github.com/tlsfuzzer/tlsfuzzer -[submodule "python-ecdsa"] - path = python-ecdsa - url = https://github.com/tlsfuzzer/python-ecdsa -[submodule "tlslite-ng"] - path = tlslite-ng - url = https://github.com/tlsfuzzer/tlslite-ng -[submodule "oqs-provider"] - path = oqs-provider - url = https://github.com/open-quantum-safe/oqs-provider.git -[submodule "cloudflare-quiche"] - path = cloudflare-quiche - url = https://github.com/cloudflare/quiche -[submodule "fuzz/corpora"] - path = fuzz/corpora - url = https://github.com/openssl/fuzz-corpora - branch = main -[submodule "pkcs11-provider"] - path = pkcs11-provider - url = https://github.com/latchset/pkcs11-provider.git diff --git a/CHANGES.md b/CHANGES.md index c1c29eb55f04c..b440f013313f6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -28,6 +28,237 @@ OpenSSL Releases OpenSSL 3.5 ----------- +### Changes between 3.5.7 and 3.5.8 [25 Aug 2026] + + * Fixed QUIC server being able to trigger double free when processing `INITIAL` + packet. + + Severity: Moderate + + Issue summary: QUIC server may double free QRX (QUIC record layer RX) object + when channel creation fails for initial packet. + + Impact summary: Double free leads to heap corruption, which typically results + in termination of QUIC server process, leading to a Denial of Service. + There is so far no evidence that this double free is exploitable for remote + code execution, thus it is considered highly improbable. + + Reported by: Fuzz0x (ZKSC Institute of Security Research), Emilio Galle, + and Feng Xue (ThreatBoon). + + ([CVE-2026-18798]) + + *Alexandr Nedvědický* + + * Fixed heap buffer overflow in CMS key unwrapping. + + Severity: Moderate + + Issue summary: OpenSSL CMS decryption sizes the key-unwrap output buffer + based on querying the unwrapped key size, but the AES-WRAP-PAD unwrap + primitive can write and cleanse more bytes than that query reports, causing + an 8-byte out-of-bounds heap write. + + Impact summary: An attacker who supplies a crafted CMS message can trigger + a deterministic 8-byte out-of-bounds heap write when the victim decrypts it + with `CMS_decrypt()`, corrupting the heap and typically resulting in a Denial + of Service. + + Reported by: Bhabani Sankar Das and Filipe Casal (Trail of Bits). + + ([CVE-2026-63072]) + + *Daniel Kubec* + + * Fixed invalid pointer dereference in CMP server via crafted `protectionAlg`. + + Severity: Moderate + + Issue Summary: The OpenSSL Certificate Management Protocol (CMP) + password-based protection verification only checks whether + the `protectionAlg` parameter was not NULL and not its ASN.1 type, + before treating it as a `PBMParameter`. A crafted message can contain + a parameter of a different type, which is then dereferenced as an invalid + pointer. + + Impact summary: A remote, unauthenticated attacker can crash an application + acting as a CMP server that accepts PBM-protected messages, or a CMP client + talking to a malicious or intercepted CMP server, resulting in a Denial + of Service. + + Reported by: Ying Dong and Bhabani Sankar Das. + + ([CVE-2026-63076]) + + *Daniel Kubec* + + * Fixed unbounded memory growth in QUIC server incoming channel queue. + + Severity: Low + + Issue summary: When an OpenSSL QUIC server (Listener SSL object) processes + valid QUIC Initial packets for unknown destination connection IDs, it can + allocate and queue new incoming channels without enforcing any limit. + + Impact summary: A remote peer that can make many `INITIAL` packets reach + the server listener faster than the application accepts connections can + cause the memory allocated to store the per-channel state to grow + without any limits, potentially making the QUIC listener unavailable + and causing a Denial of Service. + + Reported by: Filipe Casal (Trail of Bits) in collaboration with OpenAI. + + ([CVE-2026-14456]) + + + *Filipe Casal* + + * Fixed RPK server signature algorithm selection being able to dereference + a missing certificate. + + Severity: Low + + Issue summary: In a server or client configuration with [RFC 7250] Raw Public + Keys (RPKs) enabled, and only the private key (with no associated + certificate) configured locally, a NULL pointer dereference may occur + when the remote peer solicits raw public keys and also sends the typically + omitted `signature_algorithms_cert` TLS extension. + + Impact summary: The impact is limited to a possible Denial of Service + as a result of an application abort, no data disclosure or remote command + execution are possible. + + Reported by: Filipe Casal (Trail of Bits) in collaboration with OpenAI. + + ([CVE-2026-14457]) + + *Viktor Dukhovni* + + * Fixed excessive memory use buffering DTLS records for a future epoch. + + Severity: Low + + Issue summary: Receiving a DTLS record for a future epoch while a handshake + is in progress causes OpenSSL to buffer far more memory than the record + itself requires. + + Impact summary: A peer can use a small amount of network traffic to make + an OpenSSL DTLS endpoint retain a disproportionately large amount of memory, + which may lead to a Denial of Service. + + Reported by: Amazon Web Services. + + ([CVE-2026-54874]) + + *Matt Caswell* + + * Fixed untrusted Sender DN being used as a format string in CMP response + validation. + + Severity: Low + + Issue Summary: The OpenSSL Certificate Management Protocol (CMP) response + validation passed an unexpected response sender distinguished name directly + as the format string to `ERR_raise_data()`. + + Impact summary: A malicious or intercepted CMP endpoint can crash a CMP + client that enforces an expected sender or uses a pinned server certificate + whose subject becomes the default expected sender. + + Reported by: Filipe Casal (Trail of Bits) in collaboration with OpenAI, + Brandon Luo, and TrendAI Zero Day Initiative. + + ([CVE-2026-63073]) + + *Filipe Casal* + + * Fixed CMP indefinite cache growth of `extraCerts`. + + Severity: Low + + Issue Summary: The OpenSSL Certificate Management Protocol (CMP) caches + additional certificates (`extraCerts`) sent in a CMP message, but never + expunges them (for instance, if they are invalid). If a server reuses + an `OSSL_CMP_CTX` object frequently, this cache of `extraCerts` may grow + unboundedly, and a malicious client may flood a CMP server with requests + driving this growth. + + Impact Summary: Users utilizing a CMP server that reuses a single + `OSSL_CMP_CTX` object for the lifetime of a server process may observe + unbounded memory growth in the event a malicious client repeatedly sends + requests containing unique extra certificates, which may lead to OOM + conditions. + + Reported by: Pavol Zacik (Red Hat). + + ([CVE-2026-63074]) + + *Neil Horman* + + * Fixed QUIC ACK-only packet retention being able to cause memory exhaustion. + + Severity: Low + + Issue Summary: When OpenSSL processes QUIC traffic from a peer + that repeatedly sends ACK-eliciting packets while not acknowledging ACK-only + responses, the QUIC stack can retain ACK-only packet metadata + for the lifetime of the connection. + + Impact Summary: A remote peer that can complete a QUIC handshake can cause + connection-scoped memory growth, which may lead to a Denial of Service + through memory exhaustion, especially with sustained traffic or many + concurrent QUIC connections. + + Reported by: Opal Wright (Trail of Bits). + + ([CVE-2026-63075]) + + *Neil Horman* + + * Fixed possibility of AEAD forgeries with empty ciphertext when using + `EVP_Cipher()`. + + Severity: Low + + Issue summary: ChaCha20-Poly1305 and AES-OCB decryption with an empty + ciphertext can report success without verifying the supplied authentication + tag when the operation is finalized by calling the `EVP_Cipher()` function. + + Impact summary: Applications calling `EVP_Cipher()` on an empty ciphertext + and expecting the call to check the AEAD tag may accept forged messages. + + Reported by: Billy Brumley (Rochester Institute of Technology). + + ([CVE-2026-75803]) + + + *Billy Bob Brumley* + + * Added `OPENSSL_armcap(3)` documentation page. + + + *Paul Elliott* + + * Added support for selecting assembly code paths for LLVM-based Intel's `icx` + compiler. + + + *Wolfgang Beck* + + * Updated compliance with TLS 1.3 session ticket lifetime requirements. + TLS 1.3 clients now cap `ticket_lifetime_hint` to 7 days (604800 seconds) + when processing new session ticket messages, in accordance + with [RFC 8446 Section 4.6.1]. + + + *Abel Thomas* + + * Fixed checking of authentication tags for empty ciphertexts for AEAD ciphers + in CCM cipher mode. + + + *Mounir IDRASSI* + ### Changes between 3.5.6 and 3.5.7 [9 Jun 2026] * Fixed heap use-after-free in `PKCS7_verify()`. @@ -306,6 +537,21 @@ OpenSSL 3.5 *Dmitry Belyavskiy (Red Hat)* + * Fixed excessive allocation of the handshake message buffer (aka HollowByte). + + Previously, we would allocate a buffer large enough to hold the full size of + an incoming handshake message as advertised by the peer. This could be quite + large (although it is bounded, e.g. for ClientHello this is approximately + 128 KiB). If the peer then fails to send the full handshake message, then the + endpoint is left waiting for the remainder of the message to arrive and the + memory is still allocated (i.e. a Slowloris attack). To prevent this, we + incrementally grow the buffer as we receive the data. + + This issue was reported by Okta Red Team. + + + *Matt Caswell* + * Fixed TLS 1.3 server not sending `NewSessionTicket` message after ciphersuite mismatch. @@ -22260,6 +22506,9 @@ ndif [CVE-2026-2673]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-2673 [CVE-2026-7383]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-7383 [CVE-2026-9076]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-9076 +[CVE-2026-14456]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-14456 +[CVE-2026-14457]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-14457 +[CVE-2026-18798]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-18798 [CVE-2026-22795]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-22795 [CVE-2026-22796]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-22796 [CVE-2026-28387]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-28387 @@ -22281,9 +22530,18 @@ ndif [CVE-2026-45445]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-45445 [CVE-2026-45446]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-45446 [CVE-2026-45447]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-45447 +[CVE-2026-54874]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-54874 +[CVE-2026-63072]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-63072 +[CVE-2026-63073]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-63073 +[CVE-2026-63074]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-63074 +[CVE-2026-63075]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-63075 +[CVE-2026-63076]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-63076 +[CVE-2026-75803]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-75803 [ESV]: https://csrc.nist.gov/Projects/cryptographic-module-validation-program/entropy-validations [RFC 2578 (STD 58), section 3.5]: https://datatracker.ietf.org/doc/html/rfc2578#section-3.5 [RFC 3211]: https://datatracker.ietf.org/doc/html/rfc3211 [RFC 5297]: https://datatracker.ietf.org/doc/html/rfc5297 +[RFC 7250]: https://datatracker.ietf.org/doc/html/rfc7250 [RFC 8446]: https://datatracker.ietf.org/doc/html/rfc8446 +[RFC 8446 Section 4.6.1]: https://datatracker.ietf.org/doc/html/rfc8446#section-4.6.1 [RFC 8452]: https://datatracker.ietf.org/doc/html/rfc8452 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 06dfbaeff1fec..8a0d40524ddbd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -70,7 +70,37 @@ guidelines: git push -f [ []] ``` - 2. All source files should start with the following text (with + 2. Similarly, if a non-trivial portion of a contribution was created + using an AI tool, you must declare which agent and model were used. + This is done by adding `Assisted-by: {agent}:{model}` below the commit + message: + + ``` + One-line summary of change with AI-generated portions + + Assisted-by: Claude:claude-sonnet-4-6 + ``` + + Multiple Assisted-by trailers can be included if multiple tools were used: + + ``` + Assisted-by: Claude:claude-sonnet-4-6 + Assisted-by: ChatGPT:gpt-4o + Assisted-by: GitHub Copilot:gpt-4.1 + ``` + + You will need to have signed a v1.1 or later CLA in order to + include AI-generated content in your contribution. CLAs signed + after June 2026 will have the requisite clauses. + + Consult the [OpenSSL AI Code and Documentation Contribution + Policy] if an AI model assisted with the creation of your + contribution. + + [OpenSSL AI Code and Documentation Contribution + Policy]: + + 3. All source files should start with the following text (with appropriate comment characters at the start of each line and the year(s) updated): @@ -83,11 +113,11 @@ guidelines: https://www.openssl.org/source/license.html ``` - 3. Patches should be as current as possible; expect to have to rebase + 4. Patches should be as current as possible; expect to have to rebase often. We do not accept merge commits, you will have to remove them (usually by rebasing) before it will be acceptable. - 4. Code provided should follow our [coding style] and [documentation policy] + 5. Code provided should follow our [coding style] and [documentation policy] and compile without warnings. There is a [Perl tool](util/check-format.pl) that helps finding code formatting mistakes and other coding style nits. @@ -100,16 +130,16 @@ guidelines: [coding style]: https://openssl-library.org/policies/technical/coding-style/ [documentation policy]: https://openssl-library.org/policies/technical/documentation-policy/ - 5. When at all possible, code contributions should include tests. These can + 6. When at all possible, code contributions should include tests. These can either be added to an existing test, or completely new. Please see [test/README.md](test/README.md) for information on the test framework. - 6. New features or changed functionality must include + 7. New features or changed functionality must include documentation. Please look at the `.pod` files in `doc/man[1357]` for examples of our style. Run `make doc-nits` to make sure that your documentation changes are clean. - 7. For user visible changes (API changes, behaviour changes, ...), + 8. For user visible changes (API changes, behaviour changes, ...), consider adding a note in [CHANGES.md](CHANGES.md). This could be a summarising description of the change, and could explain the grander details. @@ -120,5 +150,5 @@ guidelines: with a specific release without having to sift through the higher noise ratio in git-log. - 8. Guidelines on how to integrate error output of new crypto library modules + 9. Guidelines on how to integrate error output of new crypto library modules can be found in [crypto/err/README.md](crypto/err/README.md). diff --git a/NEWS.md b/NEWS.md index 04d0bd72c7f53..329b1772c3483 100644 --- a/NEWS.md +++ b/NEWS.md @@ -23,6 +23,50 @@ OpenSSL Releases OpenSSL 3.5 ----------- +### Major changes between OpenSSL 3.5.7 and OpenSSL 3.5.8 [25 Aug 2026] + +OpenSSL 3.5.8 is a security patch release. The most severe CVE fixed +in this release is Moderate. + +This release incorporates the following bug fixes and mitigations: + + * Fixed QUIC server being able to trigger double free when processing + `INITIAL` packet. + ([CVE-2026-18798]) + + * Fixed heap buffer overflow in CMS key unwrapping. + ([CVE-2026-63072]) + + * Fixed invalid pointer dereference in CMP server via crafted `protectionAlg`. + ([CVE-2026-63076]) + + * Fixed unbounded memory growth in QUIC server incoming channel queue. + ([CVE-2026-14456]) + + * Fixed RPK server signature algorithm selection being able to dereference + a missing certificate. + ([CVE-2026-14457]) + + * Fixed excessive memory use buffering DTLS records for a future epoch. + ([CVE-2026-54874]) + + * Fixed untrusted Sender DN being used as a format string in CMP response + validation. + ([CVE-2026-63073]) + + * Fixed CMP indefinite cache growth of `extraCerts`. + ([CVE-2026-63074]) + + * Fixed QUIC ACK-only packet retention being able to cause memory exhaustion. + ([CVE-2026-63075]) + + * Fixed possibility of AEAD forgeries with empty ciphertext when using + `EVP_Cipher()`. + ([CVE-2026-75803]) + + * Fixed checking of authentication tags for empty ciphertexts for AEAD ciphers + in CCM cipher mode. + ### Major changes between OpenSSL 3.5.6 and OpenSSL 3.5.7 [9 Jun 2026] OpenSSL 3.5.7 is a security patch release. The most severe CVE fixed @@ -78,6 +122,8 @@ This release incorporates the following bug fixes and mitigations: and AES-SIV modes. ([CVE-2026-45446]) + * Fixed excessive allocation of the handshake message buffer (aka HollowByte). + ### Major changes between OpenSSL 3.5.5 and OpenSSL 3.5.6 [7 Apr 2026] OpenSSL 3.5.6 is a security patch release. The most severe CVE fixed in this @@ -2267,6 +2313,9 @@ OpenSSL 0.9.x [CVE-2026-2673]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-2673 [CVE-2026-7383]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-7383 [CVE-2026-9076]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-9076 +[CVE-2026-14456]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-14456 +[CVE-2026-14457]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-14457 +[CVE-2026-18798]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-18798 [CVE-2026-22795]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-22795 [CVE-2026-22796]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-22796 [CVE-2026-28387]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-28387 @@ -2288,6 +2337,13 @@ OpenSSL 0.9.x [CVE-2026-45445]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-45445 [CVE-2026-45446]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-45446 [CVE-2026-45447]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-45447 +[CVE-2026-54874]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-54874 +[CVE-2026-63072]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-63072 +[CVE-2026-63073]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-63073 +[CVE-2026-63074]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-63074 +[CVE-2026-63075]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-63075 +[CVE-2026-63076]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-63076 +[CVE-2026-75803]: https://openssl-library.org/news/vulnerabilities/#CVE-2026-75803 [ESV]: https://csrc.nist.gov/Projects/cryptographic-module-validation-program/entropy-validations [OpenSSL Guide]: https://www.openssl.org/docs/manmaster/man7/ossl-guide-introduction.html [README-QUIC.md]: ./README-QUIC.md diff --git a/README-FIPS.md b/README-FIPS.md index b31f8c65304b2..feb6892a2c47c 100644 --- a/README-FIPS.md +++ b/README-FIPS.md @@ -32,11 +32,15 @@ Installing the FIPS provider ============================ In order to be FIPS compliant you must only use FIPS validated source code. -Refer to for information related to +Refer to for information related to which versions are FIPS validated. The instructions given below build OpenSSL -just using the FIPS validated source code. Any FIPS validated version may be -used with any other openssl library. Please see -To determine which FIPS validated library version may be appropriate for you. +just using the FIPS validated source code. A FIPS provider built from any +validated version may be used together with an OpenSSL library built from any +supported release from OpenSSL 3.0 onwards; provider compatibility is +maintained backward and forward across these releases, including future major +release series, for as long as the module remains supported. Please see + +to determine which FIPS validated library version may be appropriate for you. If you want to use a validated FIPS provider, but also want to use the latest OpenSSL release to build everything else, then refer to the next section. diff --git a/VERSION.dat b/VERSION.dat index a297eee91e171..bf654c1a77130 100644 --- a/VERSION.dat +++ b/VERSION.dat @@ -1,7 +1,7 @@ MAJOR=3 MINOR=5 -PATCH=7 +PATCH=8 PRE_RELEASE_TAG= BUILD_METADATA= -RELEASE_DATE="9 Jun 2026" +RELEASE_DATE="25 Aug 2026" SHLIB_VERSION=3 diff --git a/apps/lib/apps.c b/apps/lib/apps.c index e5a2b162b4efa..29dd6514f6d93 100644 --- a/apps/lib/apps.c +++ b/apps/lib/apps.c @@ -1688,11 +1688,18 @@ CA_DB *load_index(const char *dbfile, DB_ATTR *db_attr) goto err; #ifndef OPENSSL_NO_POSIX_IO - BIO_get_fp(in, &dbfp); - if (fstat(fileno(dbfp), &dbst) == -1) { - ERR_raise_data(ERR_LIB_SYS, errno, - "calling fstat(%s)", dbfile); - goto err; + if (BIO_get_fp(in, &dbfp) > 0 && dbfp != NULL) { + if (fstat(fileno(dbfp), &dbst) == -1) { + ERR_raise_data(ERR_LIB_SYS, errno, + "calling fstat(%s)", dbfile); + goto err; + } + } else { + if (stat(dbfile, &dbst) == -1) { + ERR_raise_data(ERR_LIB_SYS, errno, + "calling stat(%s)", dbfile); + goto err; + } } #endif @@ -1722,8 +1729,14 @@ CA_DB *load_index(const char *dbfile, DB_ATTR *db_attr) } retdb->dbfname = OPENSSL_strdup(dbfile); - if (retdb->dbfname == NULL) + if (retdb->dbfname == NULL) { + TXT_DB_free(retdb->db); + retdb->db = NULL; + OPENSSL_free(retdb); + retdb = NULL; + ERR_raise_data(ERR_LIB_SYS, errno, "Out of memory while copying filename: %s", dbfile); goto err; + } #ifndef OPENSSL_NO_POSIX_IO retdb->dbst = dbst; diff --git a/apps/lib/s_cb.c b/apps/lib/s_cb.c index 80b5c65554246..760ad010988b3 100644 --- a/apps/lib/s_cb.c +++ b/apps/lib/s_cb.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -1461,10 +1461,7 @@ static STRINT_PAIR callback_types[] = { { "Signature Algorithm mask", SSL_SECOP_SIGALG_MASK }, { "Certificate chain EE key", SSL_SECOP_EE_KEY }, { "Certificate chain CA key", SSL_SECOP_CA_KEY }, - { "Peer Chain EE key", SSL_SECOP_PEER_EE_KEY }, - { "Peer Chain CA key", SSL_SECOP_PEER_CA_KEY }, { "Certificate chain CA digest", SSL_SECOP_CA_MD }, - { "Peer chain CA digest", SSL_SECOP_PEER_CA_MD }, { "SSL compression", SSL_SECOP_COMPRESSION }, { "Session ticket", SSL_SECOP_TICKET }, { NULL } @@ -1498,7 +1495,6 @@ static int security_callback_debug(const SSL *s, const SSL_CTX *ctx, show_nm = 0; break; case SSL_SECOP_CA_MD: - case SSL_SECOP_PEER_CA_MD: cert_md = 1; break; case SSL_SECOP_SIGALG_SUPPORTED: diff --git a/apps/lib/vms_term_sock.c b/apps/lib/vms_term_sock.c index faceb05d01451..15bc6665694d0 100644 --- a/apps/lib/vms_term_sock.c +++ b/apps/lib/vms_term_sock.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2026 The OpenSSL Project Authors. All Rights Reserved. * Copyright 2016 VMS Software, Inc. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use @@ -230,6 +230,7 @@ int TerminalSocket(int FunctionCode, int *ReturnSocket) LogMessage("TerminalSocket: SYS$QIO () - %08X", status); close(TerminalSocketPair[0]); close(TerminalSocketPair[1]); + sys$dassgn(TerminalDeviceChan); return TERM_SOCK_FAILURE; } @@ -248,6 +249,7 @@ int TerminalSocket(int FunctionCode, int *ReturnSocket) LogMessage("TerminalSocket: SYS$CANCEL () - %08X", status); close(TerminalSocketPair[0]); close(TerminalSocketPair[1]); + sys$dassgn(TerminalDeviceChan); return TERM_SOCK_FAILURE; } diff --git a/apps/s_client.c b/apps/s_client.c index 9b88d6dfbc86e..b3f333a6993c3 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -2846,11 +2846,9 @@ int s_client_main(int argc, char **argv) } /* * According to RFC 5804 § 2.2, response codes are case- - * insensitive, make it uppercase but preserve the response. + * insensitive. */ - strncpy(sbuf, mbuf, 2); - make_uppercase(sbuf); - if (!HAS_PREFIX(sbuf, "OK")) { + if (OPENSSL_strncasecmp(mbuf, "OK", 2) != 0) { BIO_printf(bio_err, "STARTTLS not supported: %s", mbuf); goto shut; } @@ -3349,29 +3347,32 @@ int s_client_main(int argc, char **argv) print_stuff(bio_c_out, con, full_log); do_ssl_shutdown(con); - /* - * If we ended with an alert being sent, but still with data in the - * network buffer to be read, then calling BIO_closesocket() will - * result in a TCP-RST being sent. On some platforms (notably - * Windows) then this will result in the peer immediately abandoning - * the connection including any buffered alert data before it has - * had a chance to be read. Shutting down the sending side first, - * and then closing the socket sends TCP-FIN first followed by - * TCP-RST. This seems to allow the peer to read the alert data. - */ - shutdown(SSL_get_fd(con), 1); /* SHUT_WR */ - /* - * We just said we have nothing else to say, but it doesn't mean that - * the other side has nothing. It's even recommended to consume incoming - * data. [In testing context this ensures that alerts are passed on...] - */ - timeout.tv_sec = 0; - timeout.tv_usec = 500000; /* some extreme round-trip */ - do { - FD_ZERO(&readfds); - openssl_fdset(sock, &readfds); - } while (select(sock + 1, &readfds, NULL, NULL, &timeout) > 0 - && BIO_read(sbio, sbuf, BUFSIZZ) > 0); + /* The following half-close/drain workaround is TCP-specific. */ + if (!isdtls && !isquic) { + /* + * If we ended with an alert being sent, but still with data in the + * network buffer to be read, then calling BIO_closesocket() will + * result in a TCP-RST being sent. On some platforms (notably + * Windows) then this will result in the peer immediately abandoning + * the connection including any buffered alert data before it has + * had a chance to be read. Shutting down the sending side first, + * and then closing the socket sends TCP-FIN first followed by + * TCP-RST. This seems to allow the peer to read the alert data. + */ + shutdown(SSL_get_fd(con), 1); /* SHUT_WR */ + /* + * We just said we have nothing else to say, but it doesn't mean that + * the other side has nothing. It's even recommended to consume incoming + * data. [In testing context this ensures that alerts are passed on...] + */ + timeout.tv_sec = 0; + timeout.tv_usec = 500000; /* some extreme round-trip */ + do { + FD_ZERO(&readfds); + openssl_fdset(sock, &readfds); + } while (select(sock + 1, &readfds, NULL, NULL, &timeout) > 0 + && BIO_read(sbio, sbuf, BUFSIZZ) > 0); + } BIO_closesocket(SSL_get_fd(con)); end: diff --git a/cloudflare-quiche b/cloudflare-quiche deleted file mode 160000 index 7ab6a55cfe471..0000000000000 --- a/cloudflare-quiche +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7ab6a55cfe471267d61e4d28ba43d41defcd87e0 diff --git a/crypto/aes/aes_x86core.c b/crypto/aes/aes_x86core.c deleted file mode 100644 index 0fa994871b279..0000000000000 --- a/crypto/aes/aes_x86core.c +++ /dev/null @@ -1,867 +0,0 @@ -/* - * Copyright 2006-2016 The OpenSSL Project Authors. All Rights Reserved. - * - * Licensed under the Apache License 2.0 (the "License"). You may not use - * this file except in compliance with the License. You can obtain a copy - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -/* - * This is experimental x86[_64] derivative. It assumes little-endian - * byte order and expects CPU to sustain unaligned memory references. - * It is used as playground for cache-time attack mitigations and - * serves as reference C implementation for x86[_64] as well as some - * other assembly modules. - */ - -/** - * rijndael-alg-fst.c - * - * @version 3.0 (December 2000) - * - * Optimised ANSI C code for the Rijndael cipher (now AES) - * - * @author Vincent Rijmen - * @author Antoon Bosselaers - * @author Paulo Barreto - * - * This code is hereby placed in the public domain. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#include -#include -#include "aes_local.h" - -/* - * These two parameters control which table, 256-byte or 2KB, is - * referenced in outer and respectively inner rounds. - */ -#define AES_COMPACT_IN_OUTER_ROUNDS -#ifdef AES_COMPACT_IN_OUTER_ROUNDS -/* AES_COMPACT_IN_OUTER_ROUNDS costs ~30% in performance, while - * adding AES_COMPACT_IN_INNER_ROUNDS reduces benchmark *further* - * by factor of ~2. */ -#undef AES_COMPACT_IN_INNER_ROUNDS -#endif - -#if 1 -static void prefetch256(const void *table) -{ - volatile unsigned long *t = (void *)table, ret; - unsigned long sum; - int i; - - /* 32 is common least cache-line size */ - for (sum = 0, i = 0; i < 256 / sizeof(t[0]); i += 32 / sizeof(t[0])) - sum ^= t[i]; - - ret = sum; -} -#else -#define prefetch256(t) -#endif - -#undef GETU32 -#define GETU32(p) (*((u32 *)(p))) - -#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__) -#define U64(C) C##UI64 -#elif defined(__arch64__) -#define U64(C) C##UL -#else -#define U64(C) C##ULL -#endif - -#undef ROTATE -#if defined(_MSC_VER) -#define ROTATE(a, n) _lrotl(a, n) -#elif defined(__ICC) -#define ROTATE(a, n) _rotl(a, n) -#elif defined(__GNUC__) && __GNUC__ >= 2 -#if defined(__i386) || defined(__i386__) || defined(__x86_64) || defined(__x86_64__) -#define ROTATE(a, n) ({ \ - register unsigned int ret; \ - asm( \ - "roll %1,%0" \ - : "=r"(ret) \ - : "I"(n), "0"(a) \ - : "cc"); \ - ret; \ -}) -#endif -#endif -/*- -Te [x] = S [x].[02, 01, 01, 03, 02, 01, 01, 03]; -Te0[x] = S [x].[02, 01, 01, 03]; -Te1[x] = S [x].[03, 02, 01, 01]; -Te2[x] = S [x].[01, 03, 02, 01]; -Te3[x] = S [x].[01, 01, 03, 02]; -*/ -#define Te0 (u32)((u64 *)((u8 *)Te + 0)) -#define Te1 (u32)((u64 *)((u8 *)Te + 3)) -#define Te2 (u32)((u64 *)((u8 *)Te + 2)) -#define Te3 (u32)((u64 *)((u8 *)Te + 1)) -/*- -Td [x] = Si[x].[0e, 09, 0d, 0b, 0e, 09, 0d, 0b]; -Td0[x] = Si[x].[0e, 09, 0d, 0b]; -Td1[x] = Si[x].[0b, 0e, 09, 0d]; -Td2[x] = Si[x].[0d, 0b, 0e, 09]; -Td3[x] = Si[x].[09, 0d, 0b, 0e]; -Td4[x] = Si[x].[01]; -*/ -#define Td0 (u32)((u64 *)((u8 *)Td + 0)) -#define Td1 (u32)((u64 *)((u8 *)Td + 3)) -#define Td2 (u32)((u64 *)((u8 *)Td + 2)) -#define Td3 (u32)((u64 *)((u8 *)Td + 1)) - -static const u64 Te[256] = { - U64(0xa56363c6a56363c6), U64(0x847c7cf8847c7cf8), - U64(0x997777ee997777ee), U64(0x8d7b7bf68d7b7bf6), - U64(0x0df2f2ff0df2f2ff), U64(0xbd6b6bd6bd6b6bd6), - U64(0xb16f6fdeb16f6fde), U64(0x54c5c59154c5c591), - U64(0x5030306050303060), U64(0x0301010203010102), - U64(0xa96767cea96767ce), U64(0x7d2b2b567d2b2b56), - U64(0x19fefee719fefee7), U64(0x62d7d7b562d7d7b5), - U64(0xe6abab4de6abab4d), U64(0x9a7676ec9a7676ec), - U64(0x45caca8f45caca8f), U64(0x9d82821f9d82821f), - U64(0x40c9c98940c9c989), U64(0x877d7dfa877d7dfa), - U64(0x15fafaef15fafaef), U64(0xeb5959b2eb5959b2), - U64(0xc947478ec947478e), U64(0x0bf0f0fb0bf0f0fb), - U64(0xecadad41ecadad41), U64(0x67d4d4b367d4d4b3), - U64(0xfda2a25ffda2a25f), U64(0xeaafaf45eaafaf45), - U64(0xbf9c9c23bf9c9c23), U64(0xf7a4a453f7a4a453), - U64(0x967272e4967272e4), U64(0x5bc0c09b5bc0c09b), - U64(0xc2b7b775c2b7b775), U64(0x1cfdfde11cfdfde1), - U64(0xae93933dae93933d), U64(0x6a26264c6a26264c), - U64(0x5a36366c5a36366c), U64(0x413f3f7e413f3f7e), - U64(0x02f7f7f502f7f7f5), U64(0x4fcccc834fcccc83), - U64(0x5c3434685c343468), U64(0xf4a5a551f4a5a551), - U64(0x34e5e5d134e5e5d1), U64(0x08f1f1f908f1f1f9), - U64(0x937171e2937171e2), U64(0x73d8d8ab73d8d8ab), - U64(0x5331316253313162), U64(0x3f15152a3f15152a), - U64(0x0c0404080c040408), U64(0x52c7c79552c7c795), - U64(0x6523234665232346), U64(0x5ec3c39d5ec3c39d), - U64(0x2818183028181830), U64(0xa1969637a1969637), - U64(0x0f05050a0f05050a), U64(0xb59a9a2fb59a9a2f), - U64(0x0907070e0907070e), U64(0x3612122436121224), - U64(0x9b80801b9b80801b), U64(0x3de2e2df3de2e2df), - U64(0x26ebebcd26ebebcd), U64(0x6927274e6927274e), - U64(0xcdb2b27fcdb2b27f), U64(0x9f7575ea9f7575ea), - U64(0x1b0909121b090912), U64(0x9e83831d9e83831d), - U64(0x742c2c58742c2c58), U64(0x2e1a1a342e1a1a34), - U64(0x2d1b1b362d1b1b36), U64(0xb26e6edcb26e6edc), - U64(0xee5a5ab4ee5a5ab4), U64(0xfba0a05bfba0a05b), - U64(0xf65252a4f65252a4), U64(0x4d3b3b764d3b3b76), - U64(0x61d6d6b761d6d6b7), U64(0xceb3b37dceb3b37d), - U64(0x7b2929527b292952), U64(0x3ee3e3dd3ee3e3dd), - U64(0x712f2f5e712f2f5e), U64(0x9784841397848413), - U64(0xf55353a6f55353a6), U64(0x68d1d1b968d1d1b9), - U64(0x0000000000000000), U64(0x2cededc12cededc1), - U64(0x6020204060202040), U64(0x1ffcfce31ffcfce3), - U64(0xc8b1b179c8b1b179), U64(0xed5b5bb6ed5b5bb6), - U64(0xbe6a6ad4be6a6ad4), U64(0x46cbcb8d46cbcb8d), - U64(0xd9bebe67d9bebe67), U64(0x4b3939724b393972), - U64(0xde4a4a94de4a4a94), U64(0xd44c4c98d44c4c98), - U64(0xe85858b0e85858b0), U64(0x4acfcf854acfcf85), - U64(0x6bd0d0bb6bd0d0bb), U64(0x2aefefc52aefefc5), - U64(0xe5aaaa4fe5aaaa4f), U64(0x16fbfbed16fbfbed), - U64(0xc5434386c5434386), U64(0xd74d4d9ad74d4d9a), - U64(0x5533336655333366), U64(0x9485851194858511), - U64(0xcf45458acf45458a), U64(0x10f9f9e910f9f9e9), - U64(0x0602020406020204), U64(0x817f7ffe817f7ffe), - U64(0xf05050a0f05050a0), U64(0x443c3c78443c3c78), - U64(0xba9f9f25ba9f9f25), U64(0xe3a8a84be3a8a84b), - U64(0xf35151a2f35151a2), U64(0xfea3a35dfea3a35d), - U64(0xc0404080c0404080), U64(0x8a8f8f058a8f8f05), - U64(0xad92923fad92923f), U64(0xbc9d9d21bc9d9d21), - U64(0x4838387048383870), U64(0x04f5f5f104f5f5f1), - U64(0xdfbcbc63dfbcbc63), U64(0xc1b6b677c1b6b677), - U64(0x75dadaaf75dadaaf), U64(0x6321214263212142), - U64(0x3010102030101020), U64(0x1affffe51affffe5), - U64(0x0ef3f3fd0ef3f3fd), U64(0x6dd2d2bf6dd2d2bf), - U64(0x4ccdcd814ccdcd81), U64(0x140c0c18140c0c18), - U64(0x3513132635131326), U64(0x2fececc32fececc3), - U64(0xe15f5fbee15f5fbe), U64(0xa2979735a2979735), - U64(0xcc444488cc444488), U64(0x3917172e3917172e), - U64(0x57c4c49357c4c493), U64(0xf2a7a755f2a7a755), - U64(0x827e7efc827e7efc), U64(0x473d3d7a473d3d7a), - U64(0xac6464c8ac6464c8), U64(0xe75d5dbae75d5dba), - U64(0x2b1919322b191932), U64(0x957373e6957373e6), - U64(0xa06060c0a06060c0), U64(0x9881811998818119), - U64(0xd14f4f9ed14f4f9e), U64(0x7fdcdca37fdcdca3), - U64(0x6622224466222244), U64(0x7e2a2a547e2a2a54), - U64(0xab90903bab90903b), U64(0x8388880b8388880b), - U64(0xca46468cca46468c), U64(0x29eeeec729eeeec7), - U64(0xd3b8b86bd3b8b86b), U64(0x3c1414283c141428), - U64(0x79dedea779dedea7), U64(0xe25e5ebce25e5ebc), - U64(0x1d0b0b161d0b0b16), U64(0x76dbdbad76dbdbad), - U64(0x3be0e0db3be0e0db), U64(0x5632326456323264), - U64(0x4e3a3a744e3a3a74), U64(0x1e0a0a141e0a0a14), - U64(0xdb494992db494992), U64(0x0a06060c0a06060c), - U64(0x6c2424486c242448), U64(0xe45c5cb8e45c5cb8), - U64(0x5dc2c29f5dc2c29f), U64(0x6ed3d3bd6ed3d3bd), - U64(0xefacac43efacac43), U64(0xa66262c4a66262c4), - U64(0xa8919139a8919139), U64(0xa4959531a4959531), - U64(0x37e4e4d337e4e4d3), U64(0x8b7979f28b7979f2), - U64(0x32e7e7d532e7e7d5), U64(0x43c8c88b43c8c88b), - U64(0x5937376e5937376e), U64(0xb76d6ddab76d6dda), - U64(0x8c8d8d018c8d8d01), U64(0x64d5d5b164d5d5b1), - U64(0xd24e4e9cd24e4e9c), U64(0xe0a9a949e0a9a949), - U64(0xb46c6cd8b46c6cd8), U64(0xfa5656acfa5656ac), - U64(0x07f4f4f307f4f4f3), U64(0x25eaeacf25eaeacf), - U64(0xaf6565caaf6565ca), U64(0x8e7a7af48e7a7af4), - U64(0xe9aeae47e9aeae47), U64(0x1808081018080810), - U64(0xd5baba6fd5baba6f), U64(0x887878f0887878f0), - U64(0x6f25254a6f25254a), U64(0x722e2e5c722e2e5c), - U64(0x241c1c38241c1c38), U64(0xf1a6a657f1a6a657), - U64(0xc7b4b473c7b4b473), U64(0x51c6c69751c6c697), - U64(0x23e8e8cb23e8e8cb), U64(0x7cdddda17cdddda1), - U64(0x9c7474e89c7474e8), U64(0x211f1f3e211f1f3e), - U64(0xdd4b4b96dd4b4b96), U64(0xdcbdbd61dcbdbd61), - U64(0x868b8b0d868b8b0d), U64(0x858a8a0f858a8a0f), - U64(0x907070e0907070e0), U64(0x423e3e7c423e3e7c), - U64(0xc4b5b571c4b5b571), U64(0xaa6666ccaa6666cc), - U64(0xd8484890d8484890), U64(0x0503030605030306), - U64(0x01f6f6f701f6f6f7), U64(0x120e0e1c120e0e1c), - U64(0xa36161c2a36161c2), U64(0x5f35356a5f35356a), - U64(0xf95757aef95757ae), U64(0xd0b9b969d0b9b969), - U64(0x9186861791868617), U64(0x58c1c19958c1c199), - U64(0x271d1d3a271d1d3a), U64(0xb99e9e27b99e9e27), - U64(0x38e1e1d938e1e1d9), U64(0x13f8f8eb13f8f8eb), - U64(0xb398982bb398982b), U64(0x3311112233111122), - U64(0xbb6969d2bb6969d2), U64(0x70d9d9a970d9d9a9), - U64(0x898e8e07898e8e07), U64(0xa7949433a7949433), - U64(0xb69b9b2db69b9b2d), U64(0x221e1e3c221e1e3c), - U64(0x9287871592878715), U64(0x20e9e9c920e9e9c9), - U64(0x49cece8749cece87), U64(0xff5555aaff5555aa), - U64(0x7828285078282850), U64(0x7adfdfa57adfdfa5), - U64(0x8f8c8c038f8c8c03), U64(0xf8a1a159f8a1a159), - U64(0x8089890980898909), U64(0x170d0d1a170d0d1a), - U64(0xdabfbf65dabfbf65), U64(0x31e6e6d731e6e6d7), - U64(0xc6424284c6424284), U64(0xb86868d0b86868d0), - U64(0xc3414182c3414182), U64(0xb0999929b0999929), - U64(0x772d2d5a772d2d5a), U64(0x110f0f1e110f0f1e), - U64(0xcbb0b07bcbb0b07b), U64(0xfc5454a8fc5454a8), - U64(0xd6bbbb6dd6bbbb6d), U64(0x3a16162c3a16162c) -}; - -static const u8 Te4[256] = { - 0x63U, 0x7cU, 0x77U, 0x7bU, 0xf2U, 0x6bU, 0x6fU, 0xc5U, - 0x30U, 0x01U, 0x67U, 0x2bU, 0xfeU, 0xd7U, 0xabU, 0x76U, - 0xcaU, 0x82U, 0xc9U, 0x7dU, 0xfaU, 0x59U, 0x47U, 0xf0U, - 0xadU, 0xd4U, 0xa2U, 0xafU, 0x9cU, 0xa4U, 0x72U, 0xc0U, - 0xb7U, 0xfdU, 0x93U, 0x26U, 0x36U, 0x3fU, 0xf7U, 0xccU, - 0x34U, 0xa5U, 0xe5U, 0xf1U, 0x71U, 0xd8U, 0x31U, 0x15U, - 0x04U, 0xc7U, 0x23U, 0xc3U, 0x18U, 0x96U, 0x05U, 0x9aU, - 0x07U, 0x12U, 0x80U, 0xe2U, 0xebU, 0x27U, 0xb2U, 0x75U, - 0x09U, 0x83U, 0x2cU, 0x1aU, 0x1bU, 0x6eU, 0x5aU, 0xa0U, - 0x52U, 0x3bU, 0xd6U, 0xb3U, 0x29U, 0xe3U, 0x2fU, 0x84U, - 0x53U, 0xd1U, 0x00U, 0xedU, 0x20U, 0xfcU, 0xb1U, 0x5bU, - 0x6aU, 0xcbU, 0xbeU, 0x39U, 0x4aU, 0x4cU, 0x58U, 0xcfU, - 0xd0U, 0xefU, 0xaaU, 0xfbU, 0x43U, 0x4dU, 0x33U, 0x85U, - 0x45U, 0xf9U, 0x02U, 0x7fU, 0x50U, 0x3cU, 0x9fU, 0xa8U, - 0x51U, 0xa3U, 0x40U, 0x8fU, 0x92U, 0x9dU, 0x38U, 0xf5U, - 0xbcU, 0xb6U, 0xdaU, 0x21U, 0x10U, 0xffU, 0xf3U, 0xd2U, - 0xcdU, 0x0cU, 0x13U, 0xecU, 0x5fU, 0x97U, 0x44U, 0x17U, - 0xc4U, 0xa7U, 0x7eU, 0x3dU, 0x64U, 0x5dU, 0x19U, 0x73U, - 0x60U, 0x81U, 0x4fU, 0xdcU, 0x22U, 0x2aU, 0x90U, 0x88U, - 0x46U, 0xeeU, 0xb8U, 0x14U, 0xdeU, 0x5eU, 0x0bU, 0xdbU, - 0xe0U, 0x32U, 0x3aU, 0x0aU, 0x49U, 0x06U, 0x24U, 0x5cU, - 0xc2U, 0xd3U, 0xacU, 0x62U, 0x91U, 0x95U, 0xe4U, 0x79U, - 0xe7U, 0xc8U, 0x37U, 0x6dU, 0x8dU, 0xd5U, 0x4eU, 0xa9U, - 0x6cU, 0x56U, 0xf4U, 0xeaU, 0x65U, 0x7aU, 0xaeU, 0x08U, - 0xbaU, 0x78U, 0x25U, 0x2eU, 0x1cU, 0xa6U, 0xb4U, 0xc6U, - 0xe8U, 0xddU, 0x74U, 0x1fU, 0x4bU, 0xbdU, 0x8bU, 0x8aU, - 0x70U, 0x3eU, 0xb5U, 0x66U, 0x48U, 0x03U, 0xf6U, 0x0eU, - 0x61U, 0x35U, 0x57U, 0xb9U, 0x86U, 0xc1U, 0x1dU, 0x9eU, - 0xe1U, 0xf8U, 0x98U, 0x11U, 0x69U, 0xd9U, 0x8eU, 0x94U, - 0x9bU, 0x1eU, 0x87U, 0xe9U, 0xceU, 0x55U, 0x28U, 0xdfU, - 0x8cU, 0xa1U, 0x89U, 0x0dU, 0xbfU, 0xe6U, 0x42U, 0x68U, - 0x41U, 0x99U, 0x2dU, 0x0fU, 0xb0U, 0x54U, 0xbbU, 0x16U -}; - -static const u64 Td[256] = { - U64(0x50a7f45150a7f451), U64(0x5365417e5365417e), - U64(0xc3a4171ac3a4171a), U64(0x965e273a965e273a), - U64(0xcb6bab3bcb6bab3b), U64(0xf1459d1ff1459d1f), - U64(0xab58faacab58faac), U64(0x9303e34b9303e34b), - U64(0x55fa302055fa3020), U64(0xf66d76adf66d76ad), - U64(0x9176cc889176cc88), U64(0x254c02f5254c02f5), - U64(0xfcd7e54ffcd7e54f), U64(0xd7cb2ac5d7cb2ac5), - U64(0x8044352680443526), U64(0x8fa362b58fa362b5), - U64(0x495ab1de495ab1de), U64(0x671bba25671bba25), - U64(0x980eea45980eea45), U64(0xe1c0fe5de1c0fe5d), - U64(0x02752fc302752fc3), U64(0x12f04c8112f04c81), - U64(0xa397468da397468d), U64(0xc6f9d36bc6f9d36b), - U64(0xe75f8f03e75f8f03), U64(0x959c9215959c9215), - U64(0xeb7a6dbfeb7a6dbf), U64(0xda595295da595295), - U64(0x2d83bed42d83bed4), U64(0xd3217458d3217458), - U64(0x2969e0492969e049), U64(0x44c8c98e44c8c98e), - U64(0x6a89c2756a89c275), U64(0x78798ef478798ef4), - U64(0x6b3e58996b3e5899), U64(0xdd71b927dd71b927), - U64(0xb64fe1beb64fe1be), U64(0x17ad88f017ad88f0), - U64(0x66ac20c966ac20c9), U64(0xb43ace7db43ace7d), - U64(0x184adf63184adf63), U64(0x82311ae582311ae5), - U64(0x6033519760335197), U64(0x457f5362457f5362), - U64(0xe07764b1e07764b1), U64(0x84ae6bbb84ae6bbb), - U64(0x1ca081fe1ca081fe), U64(0x942b08f9942b08f9), - U64(0x5868487058684870), U64(0x19fd458f19fd458f), - U64(0x876cde94876cde94), U64(0xb7f87b52b7f87b52), - U64(0x23d373ab23d373ab), U64(0xe2024b72e2024b72), - U64(0x578f1fe3578f1fe3), U64(0x2aab55662aab5566), - U64(0x0728ebb20728ebb2), U64(0x03c2b52f03c2b52f), - U64(0x9a7bc5869a7bc586), U64(0xa50837d3a50837d3), - U64(0xf2872830f2872830), U64(0xb2a5bf23b2a5bf23), - U64(0xba6a0302ba6a0302), U64(0x5c8216ed5c8216ed), - U64(0x2b1ccf8a2b1ccf8a), U64(0x92b479a792b479a7), - U64(0xf0f207f3f0f207f3), U64(0xa1e2694ea1e2694e), - U64(0xcdf4da65cdf4da65), U64(0xd5be0506d5be0506), - U64(0x1f6234d11f6234d1), U64(0x8afea6c48afea6c4), - U64(0x9d532e349d532e34), U64(0xa055f3a2a055f3a2), - U64(0x32e18a0532e18a05), U64(0x75ebf6a475ebf6a4), - U64(0x39ec830b39ec830b), U64(0xaaef6040aaef6040), - U64(0x069f715e069f715e), U64(0x51106ebd51106ebd), - U64(0xf98a213ef98a213e), U64(0x3d06dd963d06dd96), - U64(0xae053eddae053edd), U64(0x46bde64d46bde64d), - U64(0xb58d5491b58d5491), U64(0x055dc471055dc471), - U64(0x6fd406046fd40604), U64(0xff155060ff155060), - U64(0x24fb981924fb9819), U64(0x97e9bdd697e9bdd6), - U64(0xcc434089cc434089), U64(0x779ed967779ed967), - U64(0xbd42e8b0bd42e8b0), U64(0x888b8907888b8907), - U64(0x385b19e7385b19e7), U64(0xdbeec879dbeec879), - U64(0x470a7ca1470a7ca1), U64(0xe90f427ce90f427c), - U64(0xc91e84f8c91e84f8), U64(0x0000000000000000), - U64(0x8386800983868009), U64(0x48ed2b3248ed2b32), - U64(0xac70111eac70111e), U64(0x4e725a6c4e725a6c), - U64(0xfbff0efdfbff0efd), U64(0x5638850f5638850f), - U64(0x1ed5ae3d1ed5ae3d), U64(0x27392d3627392d36), - U64(0x64d90f0a64d90f0a), U64(0x21a65c6821a65c68), - U64(0xd1545b9bd1545b9b), U64(0x3a2e36243a2e3624), - U64(0xb1670a0cb1670a0c), U64(0x0fe757930fe75793), - U64(0xd296eeb4d296eeb4), U64(0x9e919b1b9e919b1b), - U64(0x4fc5c0804fc5c080), U64(0xa220dc61a220dc61), - U64(0x694b775a694b775a), U64(0x161a121c161a121c), - U64(0x0aba93e20aba93e2), U64(0xe52aa0c0e52aa0c0), - U64(0x43e0223c43e0223c), U64(0x1d171b121d171b12), - U64(0x0b0d090e0b0d090e), U64(0xadc78bf2adc78bf2), - U64(0xb9a8b62db9a8b62d), U64(0xc8a91e14c8a91e14), - U64(0x8519f1578519f157), U64(0x4c0775af4c0775af), - U64(0xbbdd99eebbdd99ee), U64(0xfd607fa3fd607fa3), - U64(0x9f2601f79f2601f7), U64(0xbcf5725cbcf5725c), - U64(0xc53b6644c53b6644), U64(0x347efb5b347efb5b), - U64(0x7629438b7629438b), U64(0xdcc623cbdcc623cb), - U64(0x68fcedb668fcedb6), U64(0x63f1e4b863f1e4b8), - U64(0xcadc31d7cadc31d7), U64(0x1085634210856342), - U64(0x4022971340229713), U64(0x2011c6842011c684), - U64(0x7d244a857d244a85), U64(0xf83dbbd2f83dbbd2), - U64(0x1132f9ae1132f9ae), U64(0x6da129c76da129c7), - U64(0x4b2f9e1d4b2f9e1d), U64(0xf330b2dcf330b2dc), - U64(0xec52860dec52860d), U64(0xd0e3c177d0e3c177), - U64(0x6c16b32b6c16b32b), U64(0x99b970a999b970a9), - U64(0xfa489411fa489411), U64(0x2264e9472264e947), - U64(0xc48cfca8c48cfca8), U64(0x1a3ff0a01a3ff0a0), - U64(0xd82c7d56d82c7d56), U64(0xef903322ef903322), - U64(0xc74e4987c74e4987), U64(0xc1d138d9c1d138d9), - U64(0xfea2ca8cfea2ca8c), U64(0x360bd498360bd498), - U64(0xcf81f5a6cf81f5a6), U64(0x28de7aa528de7aa5), - U64(0x268eb7da268eb7da), U64(0xa4bfad3fa4bfad3f), - U64(0xe49d3a2ce49d3a2c), U64(0x0d9278500d927850), - U64(0x9bcc5f6a9bcc5f6a), U64(0x62467e5462467e54), - U64(0xc2138df6c2138df6), U64(0xe8b8d890e8b8d890), - U64(0x5ef7392e5ef7392e), U64(0xf5afc382f5afc382), - U64(0xbe805d9fbe805d9f), U64(0x7c93d0697c93d069), - U64(0xa92dd56fa92dd56f), U64(0xb31225cfb31225cf), - U64(0x3b99acc83b99acc8), U64(0xa77d1810a77d1810), - U64(0x6e639ce86e639ce8), U64(0x7bbb3bdb7bbb3bdb), - U64(0x097826cd097826cd), U64(0xf418596ef418596e), - U64(0x01b79aec01b79aec), U64(0xa89a4f83a89a4f83), - U64(0x656e95e6656e95e6), U64(0x7ee6ffaa7ee6ffaa), - U64(0x08cfbc2108cfbc21), U64(0xe6e815efe6e815ef), - U64(0xd99be7bad99be7ba), U64(0xce366f4ace366f4a), - U64(0xd4099fead4099fea), U64(0xd67cb029d67cb029), - U64(0xafb2a431afb2a431), U64(0x31233f2a31233f2a), - U64(0x3094a5c63094a5c6), U64(0xc066a235c066a235), - U64(0x37bc4e7437bc4e74), U64(0xa6ca82fca6ca82fc), - U64(0xb0d090e0b0d090e0), U64(0x15d8a73315d8a733), - U64(0x4a9804f14a9804f1), U64(0xf7daec41f7daec41), - U64(0x0e50cd7f0e50cd7f), U64(0x2ff691172ff69117), - U64(0x8dd64d768dd64d76), U64(0x4db0ef434db0ef43), - U64(0x544daacc544daacc), U64(0xdf0496e4df0496e4), - U64(0xe3b5d19ee3b5d19e), U64(0x1b886a4c1b886a4c), - U64(0xb81f2cc1b81f2cc1), U64(0x7f5165467f516546), - U64(0x04ea5e9d04ea5e9d), U64(0x5d358c015d358c01), - U64(0x737487fa737487fa), U64(0x2e410bfb2e410bfb), - U64(0x5a1d67b35a1d67b3), U64(0x52d2db9252d2db92), - U64(0x335610e9335610e9), U64(0x1347d66d1347d66d), - U64(0x8c61d79a8c61d79a), U64(0x7a0ca1377a0ca137), - U64(0x8e14f8598e14f859), U64(0x893c13eb893c13eb), - U64(0xee27a9ceee27a9ce), U64(0x35c961b735c961b7), - U64(0xede51ce1ede51ce1), U64(0x3cb1477a3cb1477a), - U64(0x59dfd29c59dfd29c), U64(0x3f73f2553f73f255), - U64(0x79ce141879ce1418), U64(0xbf37c773bf37c773), - U64(0xeacdf753eacdf753), U64(0x5baafd5f5baafd5f), - U64(0x146f3ddf146f3ddf), U64(0x86db447886db4478), - U64(0x81f3afca81f3afca), U64(0x3ec468b93ec468b9), - U64(0x2c3424382c342438), U64(0x5f40a3c25f40a3c2), - U64(0x72c31d1672c31d16), U64(0x0c25e2bc0c25e2bc), - U64(0x8b493c288b493c28), U64(0x41950dff41950dff), - U64(0x7101a8397101a839), U64(0xdeb30c08deb30c08), - U64(0x9ce4b4d89ce4b4d8), U64(0x90c1566490c15664), - U64(0x6184cb7b6184cb7b), U64(0x70b632d570b632d5), - U64(0x745c6c48745c6c48), U64(0x4257b8d04257b8d0) -}; -static const u8 Td4[256] = { - 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, - 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, - 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, - 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, - 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, - 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU, - 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U, - 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, - 0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, - 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U, - 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, - 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, - 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, - 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U, - 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, - 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, - 0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU, - 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U, - 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, - 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU, - 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U, - 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, - 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, - 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, - 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U, - 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, - 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, - 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU, - 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U, - 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, - 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, - 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU -}; - -static const u32 rcon[] = { - 0x00000001U, - 0x00000002U, - 0x00000004U, - 0x00000008U, - 0x00000010U, - 0x00000020U, - 0x00000040U, - 0x00000080U, - 0x0000001bU, - 0x00000036U, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ -}; - -/** - * Expand the cipher key into the encryption key schedule. - */ -int AES_set_encrypt_key(const unsigned char *userKey, const int bits, - AES_KEY *key) -{ - - u32 *rk; - int i = 0; - u32 temp; - - if (!userKey || !key) - return -1; - if (bits != 128 && bits != 192 && bits != 256) - return -2; - - rk = key->rd_key; - - if (bits == 128) - key->rounds = 10; - else if (bits == 192) - key->rounds = 12; - else - key->rounds = 14; - - rk[0] = GETU32(userKey); - rk[1] = GETU32(userKey + 4); - rk[2] = GETU32(userKey + 8); - rk[3] = GETU32(userKey + 12); - if (bits == 128) { - while (1) { - temp = rk[3]; - rk[4] = rk[0] ^ ((u32)Te4[(temp >> 8) & 0xff]) ^ ((u32)Te4[(temp >> 16) & 0xff] << 8) ^ ((u32)Te4[(temp >> 24)] << 16) ^ ((u32)Te4[(temp) & 0xff] << 24) ^ rcon[i]; - rk[5] = rk[1] ^ rk[4]; - rk[6] = rk[2] ^ rk[5]; - rk[7] = rk[3] ^ rk[6]; - if (++i == 10) { - return 0; - } - rk += 4; - } - } - rk[4] = GETU32(userKey + 16); - rk[5] = GETU32(userKey + 20); - if (bits == 192) { - while (1) { - temp = rk[5]; - rk[6] = rk[0] ^ ((u32)Te4[(temp >> 8) & 0xff]) ^ ((u32)Te4[(temp >> 16) & 0xff] << 8) ^ ((u32)Te4[(temp >> 24)] << 16) ^ ((u32)Te4[(temp) & 0xff] << 24) ^ rcon[i]; - rk[7] = rk[1] ^ rk[6]; - rk[8] = rk[2] ^ rk[7]; - rk[9] = rk[3] ^ rk[8]; - if (++i == 8) { - return 0; - } - rk[10] = rk[4] ^ rk[9]; - rk[11] = rk[5] ^ rk[10]; - rk += 6; - } - } - rk[6] = GETU32(userKey + 24); - rk[7] = GETU32(userKey + 28); - if (bits == 256) { - while (1) { - temp = rk[7]; - rk[8] = rk[0] ^ ((u32)Te4[(temp >> 8) & 0xff]) ^ ((u32)Te4[(temp >> 16) & 0xff] << 8) ^ ((u32)Te4[(temp >> 24)] << 16) ^ ((u32)Te4[(temp) & 0xff] << 24) ^ rcon[i]; - rk[9] = rk[1] ^ rk[8]; - rk[10] = rk[2] ^ rk[9]; - rk[11] = rk[3] ^ rk[10]; - if (++i == 7) { - return 0; - } - temp = rk[11]; - rk[12] = rk[4] ^ ((u32)Te4[(temp) & 0xff]) ^ ((u32)Te4[(temp >> 8) & 0xff] << 8) ^ ((u32)Te4[(temp >> 16) & 0xff] << 16) ^ ((u32)Te4[(temp >> 24)] << 24); - rk[13] = rk[5] ^ rk[12]; - rk[14] = rk[6] ^ rk[13]; - rk[15] = rk[7] ^ rk[14]; - - rk += 8; - } - } - return 0; -} - -/** - * Expand the cipher key into the decryption key schedule. - */ -int AES_set_decrypt_key(const unsigned char *userKey, const int bits, - AES_KEY *key) -{ - - u32 *rk; - int i, j, status; - u32 temp; - - /* first, start with an encryption schedule */ - status = AES_set_encrypt_key(userKey, bits, key); - if (status < 0) - return status; - - rk = key->rd_key; - - /* invert the order of the round keys: */ - for (i = 0, j = 4 * (key->rounds); i < j; i += 4, j -= 4) { - temp = rk[i]; - rk[i] = rk[j]; - rk[j] = temp; - temp = rk[i + 1]; - rk[i + 1] = rk[j + 1]; - rk[j + 1] = temp; - temp = rk[i + 2]; - rk[i + 2] = rk[j + 2]; - rk[j + 2] = temp; - temp = rk[i + 3]; - rk[i + 3] = rk[j + 3]; - rk[j + 3] = temp; - } - /* apply the inverse MixColumn transform to all round keys but the first and the last: */ - for (i = 1; i < (key->rounds); i++) { - rk += 4; -#if 1 - for (j = 0; j < 4; j++) { - u32 tp1, tp2, tp4, tp8, tp9, tpb, tpd, tpe, m; - - tp1 = rk[j]; - m = tp1 & 0x80808080; - tp2 = ((tp1 & 0x7f7f7f7f) << 1) ^ ((m - (m >> 7)) & 0x1b1b1b1b); - m = tp2 & 0x80808080; - tp4 = ((tp2 & 0x7f7f7f7f) << 1) ^ ((m - (m >> 7)) & 0x1b1b1b1b); - m = tp4 & 0x80808080; - tp8 = ((tp4 & 0x7f7f7f7f) << 1) ^ ((m - (m >> 7)) & 0x1b1b1b1b); - tp9 = tp8 ^ tp1; - tpb = tp9 ^ tp2; - tpd = tp9 ^ tp4; - tpe = tp8 ^ tp4 ^ tp2; -#if defined(ROTATE) - rk[j] = tpe ^ ROTATE(tpd, 16) ^ ROTATE(tp9, 8) ^ ROTATE(tpb, 24); -#else - rk[j] = tpe ^ (tpd >> 16) ^ (tpd << 16) ^ (tp9 >> 24) ^ (tp9 << 8) ^ (tpb >> 8) ^ (tpb << 24); -#endif - } -#else - rk[0] = Td0[Te2[(rk[0]) & 0xff] & 0xff] ^ Td1[Te2[(rk[0] >> 8) & 0xff] & 0xff] ^ Td2[Te2[(rk[0] >> 16) & 0xff] & 0xff] ^ Td3[Te2[(rk[0] >> 24)] & 0xff]; - rk[1] = Td0[Te2[(rk[1]) & 0xff] & 0xff] ^ Td1[Te2[(rk[1] >> 8) & 0xff] & 0xff] ^ Td2[Te2[(rk[1] >> 16) & 0xff] & 0xff] ^ Td3[Te2[(rk[1] >> 24)] & 0xff]; - rk[2] = Td0[Te2[(rk[2]) & 0xff] & 0xff] ^ Td1[Te2[(rk[2] >> 8) & 0xff] & 0xff] ^ Td2[Te2[(rk[2] >> 16) & 0xff] & 0xff] ^ Td3[Te2[(rk[2] >> 24)] & 0xff]; - rk[3] = Td0[Te2[(rk[3]) & 0xff] & 0xff] ^ Td1[Te2[(rk[3] >> 8) & 0xff] & 0xff] ^ Td2[Te2[(rk[3] >> 16) & 0xff] & 0xff] ^ Td3[Te2[(rk[3] >> 24)] & 0xff]; -#endif - } - return 0; -} - -/* - * Encrypt a single block - * in and out can overlap - */ -void AES_encrypt(const unsigned char *in, unsigned char *out, - const AES_KEY *key) -{ - - const u32 *rk; - u32 s0, s1, s2, s3, t[4]; - int r; - - assert(in && out && key); - rk = key->rd_key; - - /* - * map byte array block to cipher state - * and add initial round key: - */ - s0 = GETU32(in) ^ rk[0]; - s1 = GETU32(in + 4) ^ rk[1]; - s2 = GETU32(in + 8) ^ rk[2]; - s3 = GETU32(in + 12) ^ rk[3]; - -#if defined(AES_COMPACT_IN_OUTER_ROUNDS) - prefetch256(Te4); - - t[0] = (u32)Te4[(s0) & 0xff] ^ (u32)Te4[(s1 >> 8) & 0xff] << 8 ^ (u32)Te4[(s2 >> 16) & 0xff] << 16 ^ (u32)Te4[(s3 >> 24)] << 24; - t[1] = (u32)Te4[(s1) & 0xff] ^ (u32)Te4[(s2 >> 8) & 0xff] << 8 ^ (u32)Te4[(s3 >> 16) & 0xff] << 16 ^ (u32)Te4[(s0 >> 24)] << 24; - t[2] = (u32)Te4[(s2) & 0xff] ^ (u32)Te4[(s3 >> 8) & 0xff] << 8 ^ (u32)Te4[(s0 >> 16) & 0xff] << 16 ^ (u32)Te4[(s1 >> 24)] << 24; - t[3] = (u32)Te4[(s3) & 0xff] ^ (u32)Te4[(s0 >> 8) & 0xff] << 8 ^ (u32)Te4[(s1 >> 16) & 0xff] << 16 ^ (u32)Te4[(s2 >> 24)] << 24; - - /* now do the linear transform using words */ - { - int i; - u32 r0, r1, r2; - - for (i = 0; i < 4; i++) { - r0 = t[i]; - r1 = r0 & 0x80808080; - r2 = ((r0 & 0x7f7f7f7f) << 1) ^ ((r1 - (r1 >> 7)) & 0x1b1b1b1b); -#if defined(ROTATE) - t[i] = r2 ^ ROTATE(r2, 24) ^ ROTATE(r0, 24) ^ ROTATE(r0, 16) ^ ROTATE(r0, 8); -#else - t[i] = r2 ^ ((r2 ^ r0) << 24) ^ ((r2 ^ r0) >> 8) ^ (r0 << 16) ^ (r0 >> 16) ^ (r0 << 8) ^ (r0 >> 24); -#endif - t[i] ^= rk[4 + i]; - } - } -#else - t[0] = Te0[(s0) & 0xff] ^ Te1[(s1 >> 8) & 0xff] ^ Te2[(s2 >> 16) & 0xff] ^ Te3[(s3 >> 24)] ^ rk[4]; - t[1] = Te0[(s1) & 0xff] ^ Te1[(s2 >> 8) & 0xff] ^ Te2[(s3 >> 16) & 0xff] ^ Te3[(s0 >> 24)] ^ rk[5]; - t[2] = Te0[(s2) & 0xff] ^ Te1[(s3 >> 8) & 0xff] ^ Te2[(s0 >> 16) & 0xff] ^ Te3[(s1 >> 24)] ^ rk[6]; - t[3] = Te0[(s3) & 0xff] ^ Te1[(s0 >> 8) & 0xff] ^ Te2[(s1 >> 16) & 0xff] ^ Te3[(s2 >> 24)] ^ rk[7]; -#endif - s0 = t[0]; - s1 = t[1]; - s2 = t[2]; - s3 = t[3]; - - /* - * Nr - 2 full rounds: - */ - for (rk += 8, r = key->rounds - 2; r > 0; rk += 4, r--) { -#if defined(AES_COMPACT_IN_INNER_ROUNDS) - t[0] = (u32)Te4[(s0) & 0xff] ^ (u32)Te4[(s1 >> 8) & 0xff] << 8 ^ (u32)Te4[(s2 >> 16) & 0xff] << 16 ^ (u32)Te4[(s3 >> 24)] << 24; - t[1] = (u32)Te4[(s1) & 0xff] ^ (u32)Te4[(s2 >> 8) & 0xff] << 8 ^ (u32)Te4[(s3 >> 16) & 0xff] << 16 ^ (u32)Te4[(s0 >> 24)] << 24; - t[2] = (u32)Te4[(s2) & 0xff] ^ (u32)Te4[(s3 >> 8) & 0xff] << 8 ^ (u32)Te4[(s0 >> 16) & 0xff] << 16 ^ (u32)Te4[(s1 >> 24)] << 24; - t[3] = (u32)Te4[(s3) & 0xff] ^ (u32)Te4[(s0 >> 8) & 0xff] << 8 ^ (u32)Te4[(s1 >> 16) & 0xff] << 16 ^ (u32)Te4[(s2 >> 24)] << 24; - - /* now do the linear transform using words */ - { - int i; - u32 r0, r1, r2; - - for (i = 0; i < 4; i++) { - r0 = t[i]; - r1 = r0 & 0x80808080; - r2 = ((r0 & 0x7f7f7f7f) << 1) ^ ((r1 - (r1 >> 7)) & 0x1b1b1b1b); -#if defined(ROTATE) - t[i] = r2 ^ ROTATE(r2, 24) ^ ROTATE(r0, 24) ^ ROTATE(r0, 16) ^ ROTATE(r0, 8); -#else - t[i] = r2 ^ ((r2 ^ r0) << 24) ^ ((r2 ^ r0) >> 8) ^ (r0 << 16) ^ (r0 >> 16) ^ (r0 << 8) ^ (r0 >> 24); -#endif - t[i] ^= rk[i]; - } - } -#else - t[0] = Te0[(s0) & 0xff] ^ Te1[(s1 >> 8) & 0xff] ^ Te2[(s2 >> 16) & 0xff] ^ Te3[(s3 >> 24)] ^ rk[0]; - t[1] = Te0[(s1) & 0xff] ^ Te1[(s2 >> 8) & 0xff] ^ Te2[(s3 >> 16) & 0xff] ^ Te3[(s0 >> 24)] ^ rk[1]; - t[2] = Te0[(s2) & 0xff] ^ Te1[(s3 >> 8) & 0xff] ^ Te2[(s0 >> 16) & 0xff] ^ Te3[(s1 >> 24)] ^ rk[2]; - t[3] = Te0[(s3) & 0xff] ^ Te1[(s0 >> 8) & 0xff] ^ Te2[(s1 >> 16) & 0xff] ^ Te3[(s2 >> 24)] ^ rk[3]; -#endif - s0 = t[0]; - s1 = t[1]; - s2 = t[2]; - s3 = t[3]; - } - /* - * apply last round and - * map cipher state to byte array block: - */ -#if defined(AES_COMPACT_IN_OUTER_ROUNDS) - prefetch256(Te4); - - *(u32 *)(out + 0) = (u32)Te4[(s0) & 0xff] ^ (u32)Te4[(s1 >> 8) & 0xff] << 8 ^ (u32)Te4[(s2 >> 16) & 0xff] << 16 ^ (u32)Te4[(s3 >> 24)] << 24 ^ rk[0]; - *(u32 *)(out + 4) = (u32)Te4[(s1) & 0xff] ^ (u32)Te4[(s2 >> 8) & 0xff] << 8 ^ (u32)Te4[(s3 >> 16) & 0xff] << 16 ^ (u32)Te4[(s0 >> 24)] << 24 ^ rk[1]; - *(u32 *)(out + 8) = (u32)Te4[(s2) & 0xff] ^ (u32)Te4[(s3 >> 8) & 0xff] << 8 ^ (u32)Te4[(s0 >> 16) & 0xff] << 16 ^ (u32)Te4[(s1 >> 24)] << 24 ^ rk[2]; - *(u32 *)(out + 12) = (u32)Te4[(s3) & 0xff] ^ (u32)Te4[(s0 >> 8) & 0xff] << 8 ^ (u32)Te4[(s1 >> 16) & 0xff] << 16 ^ (u32)Te4[(s2 >> 24)] << 24 ^ rk[3]; -#else - *(u32 *)(out + 0) = (Te2[(s0) & 0xff] & 0x000000ffU) ^ (Te3[(s1 >> 8) & 0xff] & 0x0000ff00U) ^ (Te0[(s2 >> 16) & 0xff] & 0x00ff0000U) ^ (Te1[(s3 >> 24)] & 0xff000000U) ^ rk[0]; - *(u32 *)(out + 4) = (Te2[(s1) & 0xff] & 0x000000ffU) ^ (Te3[(s2 >> 8) & 0xff] & 0x0000ff00U) ^ (Te0[(s3 >> 16) & 0xff] & 0x00ff0000U) ^ (Te1[(s0 >> 24)] & 0xff000000U) ^ rk[1]; - *(u32 *)(out + 8) = (Te2[(s2) & 0xff] & 0x000000ffU) ^ (Te3[(s3 >> 8) & 0xff] & 0x0000ff00U) ^ (Te0[(s0 >> 16) & 0xff] & 0x00ff0000U) ^ (Te1[(s1 >> 24)] & 0xff000000U) ^ rk[2]; - *(u32 *)(out + 12) = (Te2[(s3) & 0xff] & 0x000000ffU) ^ (Te3[(s0 >> 8) & 0xff] & 0x0000ff00U) ^ (Te0[(s1 >> 16) & 0xff] & 0x00ff0000U) ^ (Te1[(s2 >> 24)] & 0xff000000U) ^ rk[3]; -#endif -} - -/* - * Decrypt a single block - * in and out can overlap - */ -void AES_decrypt(const unsigned char *in, unsigned char *out, - const AES_KEY *key) -{ - - const u32 *rk; - u32 s0, s1, s2, s3, t[4]; - int r; - - assert(in && out && key); - rk = key->rd_key; - - /* - * map byte array block to cipher state - * and add initial round key: - */ - s0 = GETU32(in) ^ rk[0]; - s1 = GETU32(in + 4) ^ rk[1]; - s2 = GETU32(in + 8) ^ rk[2]; - s3 = GETU32(in + 12) ^ rk[3]; - -#if defined(AES_COMPACT_IN_OUTER_ROUNDS) - prefetch256(Td4); - - t[0] = (u32)Td4[(s0) & 0xff] ^ (u32)Td4[(s3 >> 8) & 0xff] << 8 ^ (u32)Td4[(s2 >> 16) & 0xff] << 16 ^ (u32)Td4[(s1 >> 24)] << 24; - t[1] = (u32)Td4[(s1) & 0xff] ^ (u32)Td4[(s0 >> 8) & 0xff] << 8 ^ (u32)Td4[(s3 >> 16) & 0xff] << 16 ^ (u32)Td4[(s2 >> 24)] << 24; - t[2] = (u32)Td4[(s2) & 0xff] ^ (u32)Td4[(s1 >> 8) & 0xff] << 8 ^ (u32)Td4[(s0 >> 16) & 0xff] << 16 ^ (u32)Td4[(s3 >> 24)] << 24; - t[3] = (u32)Td4[(s3) & 0xff] ^ (u32)Td4[(s2 >> 8) & 0xff] << 8 ^ (u32)Td4[(s1 >> 16) & 0xff] << 16 ^ (u32)Td4[(s0 >> 24)] << 24; - - /* now do the linear transform using words */ - { - int i; - u32 tp1, tp2, tp4, tp8, tp9, tpb, tpd, tpe, m; - - for (i = 0; i < 4; i++) { - tp1 = t[i]; - m = tp1 & 0x80808080; - tp2 = ((tp1 & 0x7f7f7f7f) << 1) ^ ((m - (m >> 7)) & 0x1b1b1b1b); - m = tp2 & 0x80808080; - tp4 = ((tp2 & 0x7f7f7f7f) << 1) ^ ((m - (m >> 7)) & 0x1b1b1b1b); - m = tp4 & 0x80808080; - tp8 = ((tp4 & 0x7f7f7f7f) << 1) ^ ((m - (m >> 7)) & 0x1b1b1b1b); - tp9 = tp8 ^ tp1; - tpb = tp9 ^ tp2; - tpd = tp9 ^ tp4; - tpe = tp8 ^ tp4 ^ tp2; -#if defined(ROTATE) - t[i] = tpe ^ ROTATE(tpd, 16) ^ ROTATE(tp9, 8) ^ ROTATE(tpb, 24); -#else - t[i] = tpe ^ (tpd >> 16) ^ (tpd << 16) ^ (tp9 >> 24) ^ (tp9 << 8) ^ (tpb >> 8) ^ (tpb << 24); -#endif - t[i] ^= rk[4 + i]; - } - } -#else - t[0] = Td0[(s0) & 0xff] ^ Td1[(s3 >> 8) & 0xff] ^ Td2[(s2 >> 16) & 0xff] ^ Td3[(s1 >> 24)] ^ rk[4]; - t[1] = Td0[(s1) & 0xff] ^ Td1[(s0 >> 8) & 0xff] ^ Td2[(s3 >> 16) & 0xff] ^ Td3[(s2 >> 24)] ^ rk[5]; - t[2] = Td0[(s2) & 0xff] ^ Td1[(s1 >> 8) & 0xff] ^ Td2[(s0 >> 16) & 0xff] ^ Td3[(s3 >> 24)] ^ rk[6]; - t[3] = Td0[(s3) & 0xff] ^ Td1[(s2 >> 8) & 0xff] ^ Td2[(s1 >> 16) & 0xff] ^ Td3[(s0 >> 24)] ^ rk[7]; -#endif - s0 = t[0]; - s1 = t[1]; - s2 = t[2]; - s3 = t[3]; - - /* - * Nr - 2 full rounds: - */ - for (rk += 8, r = key->rounds - 2; r > 0; rk += 4, r--) { -#if defined(AES_COMPACT_IN_INNER_ROUNDS) - t[0] = (u32)Td4[(s0) & 0xff] ^ (u32)Td4[(s3 >> 8) & 0xff] << 8 ^ (u32)Td4[(s2 >> 16) & 0xff] << 16 ^ (u32)Td4[(s1 >> 24)] << 24; - t[1] = (u32)Td4[(s1) & 0xff] ^ (u32)Td4[(s0 >> 8) & 0xff] << 8 ^ (u32)Td4[(s3 >> 16) & 0xff] << 16 ^ (u32)Td4[(s2 >> 24)] << 24; - t[2] = (u32)Td4[(s2) & 0xff] ^ (u32)Td4[(s1 >> 8) & 0xff] << 8 ^ (u32)Td4[(s0 >> 16) & 0xff] << 16 ^ (u32)Td4[(s3 >> 24)] << 24; - t[3] = (u32)Td4[(s3) & 0xff] ^ (u32)Td4[(s2 >> 8) & 0xff] << 8 ^ (u32)Td4[(s1 >> 16) & 0xff] << 16 ^ (u32)Td4[(s0 >> 24)] << 24; - - /* now do the linear transform using words */ - { - int i; - u32 tp1, tp2, tp4, tp8, tp9, tpb, tpd, tpe, m; - - for (i = 0; i < 4; i++) { - tp1 = t[i]; - m = tp1 & 0x80808080; - tp2 = ((tp1 & 0x7f7f7f7f) << 1) ^ ((m - (m >> 7)) & 0x1b1b1b1b); - m = tp2 & 0x80808080; - tp4 = ((tp2 & 0x7f7f7f7f) << 1) ^ ((m - (m >> 7)) & 0x1b1b1b1b); - m = tp4 & 0x80808080; - tp8 = ((tp4 & 0x7f7f7f7f) << 1) ^ ((m - (m >> 7)) & 0x1b1b1b1b); - tp9 = tp8 ^ tp1; - tpb = tp9 ^ tp2; - tpd = tp9 ^ tp4; - tpe = tp8 ^ tp4 ^ tp2; -#if defined(ROTATE) - t[i] = tpe ^ ROTATE(tpd, 16) ^ ROTATE(tp9, 8) ^ ROTATE(tpb, 24); -#else - t[i] = tpe ^ (tpd >> 16) ^ (tpd << 16) ^ (tp9 >> 24) ^ (tp9 << 8) ^ (tpb >> 8) ^ (tpb << 24); -#endif - t[i] ^= rk[i]; - } - } -#else - t[0] = Td0[(s0) & 0xff] ^ Td1[(s3 >> 8) & 0xff] ^ Td2[(s2 >> 16) & 0xff] ^ Td3[(s1 >> 24)] ^ rk[0]; - t[1] = Td0[(s1) & 0xff] ^ Td1[(s0 >> 8) & 0xff] ^ Td2[(s3 >> 16) & 0xff] ^ Td3[(s2 >> 24)] ^ rk[1]; - t[2] = Td0[(s2) & 0xff] ^ Td1[(s1 >> 8) & 0xff] ^ Td2[(s0 >> 16) & 0xff] ^ Td3[(s3 >> 24)] ^ rk[2]; - t[3] = Td0[(s3) & 0xff] ^ Td1[(s2 >> 8) & 0xff] ^ Td2[(s1 >> 16) & 0xff] ^ Td3[(s0 >> 24)] ^ rk[3]; -#endif - s0 = t[0]; - s1 = t[1]; - s2 = t[2]; - s3 = t[3]; - } - /* - * apply last round and - * map cipher state to byte array block: - */ - prefetch256(Td4); - - *(u32 *)(out + 0) = ((u32)Td4[(s0) & 0xff]) ^ ((u32)Td4[(s3 >> 8) & 0xff] << 8) ^ ((u32)Td4[(s2 >> 16) & 0xff] << 16) ^ ((u32)Td4[(s1 >> 24)] << 24) ^ rk[0]; - *(u32 *)(out + 4) = ((u32)Td4[(s1) & 0xff]) ^ ((u32)Td4[(s0 >> 8) & 0xff] << 8) ^ ((u32)Td4[(s3 >> 16) & 0xff] << 16) ^ ((u32)Td4[(s2 >> 24)] << 24) ^ rk[1]; - *(u32 *)(out + 8) = ((u32)Td4[(s2) & 0xff]) ^ ((u32)Td4[(s1 >> 8) & 0xff] << 8) ^ ((u32)Td4[(s0 >> 16) & 0xff] << 16) ^ ((u32)Td4[(s3 >> 24)] << 24) ^ rk[2]; - *(u32 *)(out + 12) = ((u32)Td4[(s3) & 0xff]) ^ ((u32)Td4[(s2 >> 8) & 0xff] << 8) ^ ((u32)Td4[(s1 >> 16) & 0xff] << 16) ^ ((u32)Td4[(s0 >> 24)] << 24) ^ rk[3]; -} diff --git a/crypto/aes/asm/aesni-mb-x86_64.pl b/crypto/aes/asm/aesni-mb-x86_64.pl index dde15b1ef7ee5..87ed95cdf33c1 100644 --- a/crypto/aes/asm/aesni-mb-x86_64.pl +++ b/crypto/aes/asm/aesni-mb-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2013-2020 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2013-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -80,6 +80,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/crypto/aes/asm/aesni-sha1-x86_64.pl b/crypto/aes/asm/aesni-sha1-x86_64.pl index 4e8fa1d753d7a..bc08da9460641 100644 --- a/crypto/aes/asm/aesni-sha1-x86_64.pl +++ b/crypto/aes/asm/aesni-sha1-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2011-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2011-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -111,6 +111,9 @@ $1>=10); $avx=1 if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:clang|LLVM) version|.*based on LLVM) ([0-9]+\.[0-9]+)/ && $2>=3.0); +$avx=1 if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` =~ /#define __clang_major__.([0-9]+)/ && + $1>=11); #icx started with clang 11 + $shaext=1; ### set to zero if compiling for 1.0.1 $stitched_decrypt=0; diff --git a/crypto/aes/asm/aesni-sha256-x86_64.pl b/crypto/aes/asm/aesni-sha256-x86_64.pl index 39d29ddbb0228..6715ba2e11a76 100644 --- a/crypto/aes/asm/aesni-sha256-x86_64.pl +++ b/crypto/aes/asm/aesni-sha256-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2013-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2013-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -75,6 +75,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + $shaext=$avx; ### set to zero if compiling for 1.0.1 $avx=1 if (!$shaext && $avx); diff --git a/crypto/aes/asm/aesni-xts-avx512.pl b/crypto/aes/asm/aesni-xts-avx512.pl index d89564112e313..16f2bbe789649 100644 --- a/crypto/aes/asm/aesni-xts-avx512.pl +++ b/crypto/aes/asm/aesni-xts-avx512.pl @@ -59,6 +59,13 @@ } } +if (!$avx512vaes && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx512vaes = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/crypto/armcap.c b/crypto/armcap.c index 03e47dc5bbfb0..415c55cb46fc9 100644 --- a/crypto/armcap.c +++ b/crypto/armcap.c @@ -1,5 +1,5 @@ /* - * Copyright 2011-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2011-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -77,6 +77,10 @@ void OPENSSL_cpuid_setup(void) __attribute__((constructor)); #include #define OSSL_IMPLEMENT_GETAUXVAL #endif +#elif defined(__MUSL__) +/* musl has always provided getauxval(), unversioned. */ +#include +#define OSSL_IMPLEMENT_GETAUXVAL #endif #if defined(__FreeBSD__) || defined(__OpenBSD__) #include @@ -408,14 +412,38 @@ void OPENSSL_cpuid_setup(void) if (OPENSSL_armcap_P & ARMV8_CPUID) OPENSSL_arm_midr = _armv8_cpuid_probe(); - if ((MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_N1)) && (OPENSSL_armcap_P & ARMV7_NEON)) { + if ((OPENSSL_armcap_P & ARMV7_NEON) + && (MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_N1))) OPENSSL_armv8_rsa_neonized = 1; - } - if ((MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V1) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_N2) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_MICROSOFT, MICROSOFT_CPU_PART_COBALT_100) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V2) || MIDR_IMPLEMENTER(OPENSSL_arm_midr) == ARM_CPU_IMP_AMPERE) && (OPENSSL_armcap_P & ARMV8_SHA3)) + + if ((OPENSSL_armcap_P & ARMV8_SHA3) + && (MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V1) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_N2) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_MICROSOFT, MICROSOFT_CPU_PART_COBALT_100) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V2) + || MIDR_IMPLEMENTER(OPENSSL_arm_midr) == ARM_CPU_IMP_AMPERE)) OPENSSL_armcap_P |= ARMV8_UNROLL8_EOR3; - if ((MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V1) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V2) || MIDR_IMPLEMENTER(OPENSSL_arm_midr) == ARM_CPU_IMP_AMPERE) && (OPENSSL_armcap_P & ARMV8_SHA3)) + + if ((OPENSSL_armcap_P & ARMV8_SHA3) + && (MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V1) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V2) + || MIDR_IMPLEMENTER(OPENSSL_arm_midr) == ARM_CPU_IMP_AMPERE)) OPENSSL_armcap_P |= ARMV8_UNROLL12_EOR3; - if ((MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM_PRO) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM_PRO) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM_MAX) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM_MAX) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE_PRO) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD_PRO) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE_MAX) || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD_MAX)) && (OPENSSL_armcap_P & ARMV8_SHA3)) + + if ((OPENSSL_armcap_P & ARMV8_SHA3) + && (MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM_PRO) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM_PRO) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM_MAX) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM_MAX) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE_PRO) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD_PRO) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE_MAX) + || MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD_MAX))) OPENSSL_armcap_P |= ARMV8_HAVE_SHA3_AND_WORTH_USING; #endif } diff --git a/crypto/asn1/a_d2i_fp.c b/crypto/asn1/a_d2i_fp.c index a23dea8ebda2e..19595683ef982 100644 --- a/crypto/asn1/a_d2i_fp.c +++ b/crypto/asn1/a_d2i_fp.c @@ -139,7 +139,20 @@ int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb) } i = BIO_read(in, &(b->data[len]), want); if (i <= 0) { - ERR_raise(ERR_LIB_ASN1, ASN1_R_NOT_ENOUGH_DATA); + /* + * A read error (i < 0), an EOF in the middle of an object + * (diff != 0, some bytes already buffered), or an EOF while + * still inside an indefinite-length constructed value awaiting + * its end-of-contents octets (eos != 0) all mean the input is + * truncated. Only a clean EOF at a top-level object boundary + * (i == 0, diff == 0, eos == 0) is the normal end of input: + * fail without queuing an error so that callers looping over + * concatenated DER values (e.g. the libcrypto d2i_*_bio() + * consumers in CPython's ssl module) terminate cleanly instead + * of seeing a spurious ASN1_R_NOT_ENOUGH_DATA. + */ + if (i < 0 || diff != 0 || eos != 0) + ERR_raise(ERR_LIB_ASN1, ASN1_R_NOT_ENOUGH_DATA); goto err; } if (i > 0) { diff --git a/crypto/asn1/a_mbstr.c b/crypto/asn1/a_mbstr.c index ce5618dfd48b8..9a61f7f1e051f 100644 --- a/crypto/asn1/a_mbstr.c +++ b/crypto/asn1/a_mbstr.c @@ -51,12 +51,24 @@ int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len, unsigned char *p; int nchar; int (*cpyfunc)(unsigned long, void *) = NULL; - if (len == -1) - len = strlen((const char *)in); + if (len == -1) { + size_t len_s = strlen((const char *)in); + + if (len_s >= INT_MAX) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_STRING_TOO_LONG); + return -1; + } + len = (int)len_s; + } if (!mask) mask = DIRSTRING_TYPE; - if (len < 0) + if (len < 0) { + ERR_raise(ERR_LIB_ASN1, ERR_R_PASSED_INVALID_ARGUMENT); + return -1; + } else if (len >= INT_MAX) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_STRING_TOO_LONG); return -1; + } /* First do a string check and work out the number of characters */ switch (inform) { @@ -294,7 +306,7 @@ static int out_utf8(unsigned long value, void *arg) return len; } outlen = arg; - if (*outlen > INT_MAX - len) { + if (*outlen >= INT_MAX - len) { ERR_raise(ERR_LIB_ASN1, ASN1_R_STRING_TOO_LONG); return -1; } diff --git a/crypto/asn1/asn1_gen.c b/crypto/asn1/asn1_gen.c index 1c8d3d585940a..69fbd6f89e58e 100644 --- a/crypto/asn1/asn1_gen.c +++ b/crypto/asn1/asn1_gen.c @@ -426,8 +426,11 @@ static ASN1_TYPE *asn1_multi(int utype, const char *section, X509V3_CTX *cnf, depth + 1, perr); if (!typ) goto bad; - if (!sk_ASN1_TYPE_push(sk, typ)) + + if (!sk_ASN1_TYPE_push(sk, typ)) { + ASN1_TYPE_free(typ); goto bad; + } } } diff --git a/crypto/bio/bss_dgram.c b/crypto/bio/bss_dgram.c index 968104a062086..8d802bb020a45 100644 --- a/crypto/bio/bss_dgram.c +++ b/crypto/bio/bss_dgram.c @@ -49,7 +49,9 @@ #define M_METHOD_WSARECVMSG 4 #if defined(__GLIBC__) && defined(__GLIBC_PREREQ) -#if !(__GLIBC_PREREQ(2, 14)) +/// ClickHouse-specific patch: Pretend to use a stone age glibc because we use a stone age glibc. +/// Otherwise, system calls sendmmsg and recvmmsg are used which work only with too-new glibc 2.14. +/// #if !(__GLIBC_PREREQ(2, 14)) #undef NO_RECVMMSG /* * Some old glibc versions may have recvmmsg and MSG_WAITFORONE flag, but @@ -57,7 +59,7 @@ * versions */ #define NO_RECVMMSG -#endif +/// #endif #endif #if defined(__GNU__) /* GNU/Hurd does not have IP_PKTINFO yet */ diff --git a/crypto/bio/bss_file.c b/crypto/bio/bss_file.c index 6b8daeb95f905..023bb458ce5f0 100644 --- a/crypto/bio/bss_file.c +++ b/crypto/bio/bss_file.c @@ -312,7 +312,13 @@ static long file_ctrl(BIO *b, int cmd, long num, void *ptr) /* the ptr parameter is actually a FILE ** in this case. */ if (ptr != NULL) { fpp = (FILE **)ptr; - *fpp = (FILE *)b->ptr; + if (BIO_FLAGS_UPLINK_INTERNAL == 0 + || b->flags & BIO_FLAGS_UPLINK_INTERNAL) { + *fpp = (FILE *)b->ptr; + } else { /* avoid returning internal FILE * to the app */ + *fpp = NULL; + ret = 0; + } } break; case BIO_CTRL_GET_CLOSE: diff --git a/crypto/bn/asm/rsaz-2k-avx512.pl b/crypto/bn/asm/rsaz-2k-avx512.pl index 27f2e9b4b9385..6c0cb566f9d7a 100644 --- a/crypto/bn/asm/rsaz-2k-avx512.pl +++ b/crypto/bn/asm/rsaz-2k-avx512.pl @@ -1,4 +1,4 @@ -# Copyright 2020-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2020-2026 The OpenSSL Project Authors. All Rights Reserved. # Copyright (c) 2020, Intel Corporation. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use @@ -64,6 +64,13 @@ } } +if (!$avx512ifma && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx512ifma = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/crypto/bn/asm/rsaz-2k-avxifma.pl b/crypto/bn/asm/rsaz-2k-avxifma.pl index b84a3e4f1954a..52d9781834d68 100644 --- a/crypto/bn/asm/rsaz-2k-avxifma.pl +++ b/crypto/bn/asm/rsaz-2k-avxifma.pl @@ -39,6 +39,13 @@ $avxifma = ($ver>=16.0); } +if (!$avxifma && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avxifma = ($1>=16); + } +} + if ($win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && `nasm -v 2>&1` =~ /NASM version ([0-9]+)\.([0-9]+)(?:\.([0-9]+))?(rc[0-9]+)?/) { my $ver = $1 + $2/100.0 + $3/10000.0; # 3.1.0->3.01, 3.10.1->3.1001 diff --git a/crypto/bn/asm/rsaz-3k-avx512.pl b/crypto/bn/asm/rsaz-3k-avx512.pl index b2ed3e8ca7cfd..fe5b1ebefab6e 100644 --- a/crypto/bn/asm/rsaz-3k-avx512.pl +++ b/crypto/bn/asm/rsaz-3k-avx512.pl @@ -1,4 +1,4 @@ -# Copyright 2021-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2021-2026 The OpenSSL Project Authors. All Rights Reserved. # Copyright (c) 2021, Intel Corporation. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use @@ -63,6 +63,13 @@ } } +if (!$avx512ifma && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx512ifma = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/crypto/bn/asm/rsaz-3k-avxifma.pl b/crypto/bn/asm/rsaz-3k-avxifma.pl index 1948d726b38b4..aa11c546af6db 100644 --- a/crypto/bn/asm/rsaz-3k-avxifma.pl +++ b/crypto/bn/asm/rsaz-3k-avxifma.pl @@ -38,6 +38,13 @@ $avxifma = ($ver>=16.0); } +if (!$avxifma && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avxifma = ($1>=16); + } +} + if ($win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)(?:\.([0-9]+))?(rc[0-9]+)?/) { $avxifma = ($1>2.16) + ($1==2.16 && ((!defined($2) && !defined($3)) || (defined($2)))); diff --git a/crypto/bn/asm/rsaz-4k-avx512.pl b/crypto/bn/asm/rsaz-4k-avx512.pl index b76ab5904c887..b07180f6feca7 100644 --- a/crypto/bn/asm/rsaz-4k-avx512.pl +++ b/crypto/bn/asm/rsaz-4k-avx512.pl @@ -1,4 +1,4 @@ -# Copyright 2021-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2021-2026 The OpenSSL Project Authors. All Rights Reserved. # Copyright (c) 2021, Intel Corporation. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use @@ -63,6 +63,13 @@ } } +if (!$avx512ifma && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx512ifma = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/crypto/bn/asm/rsaz-4k-avxifma.pl b/crypto/bn/asm/rsaz-4k-avxifma.pl index 9f299430cefcd..28a447800d0d7 100644 --- a/crypto/bn/asm/rsaz-4k-avxifma.pl +++ b/crypto/bn/asm/rsaz-4k-avxifma.pl @@ -38,6 +38,13 @@ $avxifma = ($ver>=16.0); } +if (!$avxifma && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avxifma = ($1>=16); + } +} + if ($win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)(?:\.([0-9]+))?(rc[0-9]+)?/) { $avxifma = ($1>2.16) + ($1==2.16 && ((!defined($2) && !defined($3)) || (defined($2)))); diff --git a/crypto/bn/asm/rsaz-avx2.pl b/crypto/bn/asm/rsaz-avx2.pl index 59b9c89b5be2d..29243a7c0b76e 100755 --- a/crypto/bn/asm/rsaz-avx2.pl +++ b/crypto/bn/asm/rsaz-avx2.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2013-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2013-2026 The OpenSSL Project Authors. All Rights Reserved. # Copyright (c) 2012, Intel Corporation. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use @@ -73,6 +73,14 @@ $addx = ($ver>=3.03); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $addx = ($1>=11); #icx started with clang 11 + $avx = ($1>=11); + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT = *OUT; diff --git a/crypto/bn/asm/rsaz-x86_64.pl b/crypto/bn/asm/rsaz-x86_64.pl index 64acf8f0d84d5..3ceacea1d338d 100755 --- a/crypto/bn/asm/rsaz-x86_64.pl +++ b/crypto/bn/asm/rsaz-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2013-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2013-2026 The OpenSSL Project Authors. All Rights Reserved. # Copyright (c) 2012, Intel Corporation. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use @@ -90,6 +90,13 @@ $addx = ($ver>=3.03); } +if (!$addx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $addx = ($1>=11); #icx started with clang 11 + } +} + ($out, $inp, $mod) = ("%rdi", "%rsi", "%rbp"); # common internal API { my ($out,$inp,$mod,$n0,$times) = ("%rdi","%rsi","%rdx","%rcx","%r8d"); diff --git a/crypto/bn/asm/x86_64-mont.pl b/crypto/bn/asm/x86_64-mont.pl index 140072b899dcb..9c7b3091f4349 100755 --- a/crypto/bn/asm/x86_64-mont.pl +++ b/crypto/bn/asm/x86_64-mont.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2005-2020 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2005-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -82,6 +82,13 @@ $addx = ($ver>=3.03); } +if (!$addx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $addx = ($1>=11); #icx started with clang 11 + } +} + # int bn_mul_mont( $rp="%rdi"; # BN_ULONG *rp, $ap="%rsi"; # const BN_ULONG *ap, diff --git a/crypto/bn/asm/x86_64-mont5.pl b/crypto/bn/asm/x86_64-mont5.pl index e06d13d74aeae..52f95a485317a 100755 --- a/crypto/bn/asm/x86_64-mont5.pl +++ b/crypto/bn/asm/x86_64-mont5.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2011-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2011-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -69,6 +69,13 @@ $addx = ($ver>=3.03); } +if (!$addx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $addx = ($1>=11); #icx started with clang 11 + } +} + # int bn_mul_mont_gather5( $rp="%rdi"; # BN_ULONG *rp, $ap="%rsi"; # const BN_ULONG *ap, diff --git a/crypto/bn/bn_add.c b/crypto/bn/bn_add.c index 38de39d1b8aca..9c028269840cc 100644 --- a/crypto/bn/bn_add.c +++ b/crypto/bn/bn_add.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -97,6 +97,8 @@ int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) return 0; r->top = max; + if (max == 0) + goto end; ap = a->d; bp = b->d; @@ -116,6 +118,7 @@ int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) *rp = carry; r->top += carry; +end: r->neg = 0; bn_check_top(r); return 1; @@ -143,6 +146,9 @@ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) if (bn_wexpand(r, max) == NULL) return 0; + if (max == 0) + goto end; + ap = a->d; bp = b->d; rp = r->d; @@ -162,6 +168,7 @@ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) while (max && *--rp == 0) max--; +end: r->top = max; r->neg = 0; bn_pollute(r); diff --git a/crypto/bn/bn_exp.c b/crypto/bn/bn_exp.c index 44931f803802c..ddcd89e2d4bc5 100644 --- a/crypto/bn/bn_exp.c +++ b/crypto/bn/bn_exp.c @@ -552,7 +552,7 @@ static int MOD_EXP_CTIME_COPY_FROM_PREBUF(BIGNUM *b, int top, BN_ULONG acc = 0; for (j = 0; j < width; j++) { - acc |= table[j] & ((BN_ULONG)0 - (constant_time_eq_int(j, idx) & 1)); + acc |= table[j] & value_barrier_bn((BN_ULONG)0 - (constant_time_eq_int(j, idx) & 1)); } b->d[i] = acc; @@ -573,8 +573,9 @@ static int MOD_EXP_CTIME_COPY_FROM_PREBUF(BIGNUM *b, int top, BN_ULONG acc = 0; for (j = 0; j < xstride; j++) { - acc |= ((table[j + 0 * xstride] & y0) | (table[j + 1 * xstride] & y1) | (table[j + 2 * xstride] & y2) | (table[j + 3 * xstride] & y3)) - & ((BN_ULONG)0 - (constant_time_eq_int(j, idx) & 1)); + acc |= ((table[j + 0 * xstride] & value_barrier_bn(y0)) | (table[j + 1 * xstride] & value_barrier_bn(y1)) + | (table[j + 2 * xstride] & value_barrier_bn(y2)) | (table[j + 3 * xstride] & value_barrier_bn(y3))) + & value_barrier_bn((BN_ULONG)0 - (constant_time_eq_int(j, idx) & 1)); } b->d[i] = acc; diff --git a/crypto/bn/bn_intern.c b/crypto/bn/bn_intern.c index bd299cd1442d7..6fa404afce2cd 100644 --- a/crypto/bn/bn_intern.c +++ b/crypto/bn/bn_intern.c @@ -10,6 +10,11 @@ #include "internal/cryptlib.h" #include "bn_local.h" +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) +# include +# endif +#endif /* * Determine the modified width-(w+1) Non-Adjacent Form (wNAF) of 'scalar'. * This is an array r[] of values that are either zero or odd with an @@ -188,6 +193,11 @@ int bn_set_words(BIGNUM *a, const BN_ULONG *words, int num_words) return 0; } +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) + __msan_unpoison(words, sizeof(BN_ULONG) * num_words); +# endif +#endif memcpy(a->d, words, sizeof(BN_ULONG) * num_words); a->top = num_words; bn_correct_top(a); diff --git a/crypto/bn/bn_lib.c b/crypto/bn/bn_lib.c index 93d54fd0a6ed3..7961906f9ae73 100644 --- a/crypto/bn/bn_lib.c +++ b/crypto/bn/bn_lib.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -707,19 +707,37 @@ int BN_ucmp(const BIGNUM *a, const BIGNUM *b) int i; BN_ULONG t1, t2, *ap, *bp; + /* + * As it is a public API function, we should handle NULL parameters in + * some way. The function can’t return an error, so let’s define that NULL + * is less than any BIGNUM. + */ + if (!ossl_assert(a != NULL && b != NULL)) + return (b == NULL) - (a == NULL); + ap = a->d; bp = b->d; if (BN_get_flags(a, BN_FLG_CONSTTIME) - && a->top == b->top) { + || BN_get_flags(b, BN_FLG_CONSTTIME)) { int res = 0; + int min_top = a->top < b->top ? a->top : b->top; - for (i = 0; i < b->top; i++) { + for (i = 0; i < min_top; i++) { res = constant_time_select_int(constant_time_lt_bn(ap[i], bp[i]), -1, res); res = constant_time_select_int(constant_time_lt_bn(bp[i], ap[i]), 1, res); } + + for (i = min_top; i < a->top; ++i) + res = constant_time_select_int((int)constant_time_is_zero_bn(ap[i]), + res, 1); + + for (i = min_top; i < b->top; ++i) + res = constant_time_select_int((int)constant_time_is_zero_bn(bp[i]), + res, -1); + return res; } @@ -948,11 +966,11 @@ void BN_consttime_swap(BN_ULONG condition, BIGNUM *a, BIGNUM *b, int nwords) condition = ((~condition & ((condition - 1))) >> (BN_BITS2 - 1)) - 1; - t = (a->top ^ b->top) & condition; + t = (a->top ^ b->top) & value_barrier_bn(condition); a->top ^= t; b->top ^= t; - t = (a->neg ^ b->neg) & condition; + t = (a->neg ^ b->neg) & value_barrier_bn(condition); a->neg ^= t; b->neg ^= t; @@ -980,13 +998,13 @@ void BN_consttime_swap(BN_ULONG condition, BIGNUM *a, BIGNUM *b, int nwords) #define BN_CONSTTIME_SWAP_FLAGS (BN_FLG_CONSTTIME | BN_FLG_FIXED_TOP) - t = ((a->flags ^ b->flags) & BN_CONSTTIME_SWAP_FLAGS) & condition; + t = ((a->flags ^ b->flags) & BN_CONSTTIME_SWAP_FLAGS) & value_barrier_bn(condition); a->flags ^= t; b->flags ^= t; /* conditionally swap the data */ for (i = 0; i < nwords; i++) { - t = (a->d[i] ^ b->d[i]) & condition; + t = (a->d[i] ^ b->d[i]) & value_barrier_bn(condition); a->d[i] ^= t; b->d[i] ^= t; } diff --git a/crypto/chacha/asm/chacha-x86.pl b/crypto/chacha/asm/chacha-x86.pl index a1ea4ea461b06..b95d4df379792 100755 --- a/crypto/chacha/asm/chacha-x86.pl +++ b/crypto/chacha/asm/chacha-x86.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2016-2020 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2016-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -64,6 +64,10 @@ `$ENV{CC} -v 2>&1` =~ /((?:clang|LLVM) version|based on LLVM) ([0-9]+\.[0-9]+)/ && $2>=3.0); # first version supporting AVX +$ymm=1 if ($xmm && !$ymm && + `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` =~ /#define __clang_major__.([0-9]+)/ && + $1>=11); #icx started with clang 11 + $a="eax"; ($b,$b_)=("ebx","ebp"); ($c,$c_)=("ecx","esi"); diff --git a/crypto/chacha/asm/chacha-x86_64.pl b/crypto/chacha/asm/chacha-x86_64.pl index d46bc03b3eec2..69e5319ad43ef 100755 --- a/crypto/chacha/asm/chacha-x86_64.pl +++ b/crypto/chacha/asm/chacha-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2016-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2016-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -91,6 +91,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/crypto/cmp/cmp_protect.c b/crypto/cmp/cmp_protect.c index 1c8d2135fdab6..110693b84038e 100644 --- a/crypto/cmp/cmp_protect.c +++ b/crypto/cmp/cmp_protect.c @@ -1,5 +1,5 @@ /* - * Copyright 2007-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2007-2026 The OpenSSL Project Authors. All Rights Reserved. * Copyright Nokia 2007-2019 * Copyright Siemens AG 2015-2019 * @@ -66,7 +66,7 @@ ASN1_BIT_STRING *ossl_cmp_calc_protection(const OSSL_CMP_CTX *ctx, ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_PBM_SECRET); return NULL; } - if (ppval == NULL) { + if (pptype != V_ASN1_SEQUENCE || ppval == NULL) { ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_CALCULATING_PROTECTION); return NULL; } diff --git a/crypto/cmp/cmp_vfy.c b/crypto/cmp/cmp_vfy.c index eaa700d139d13..e79adb09d3879 100644 --- a/crypto/cmp/cmp_vfy.c +++ b/crypto/cmp/cmp_vfy.c @@ -64,8 +64,10 @@ static int verify_signature(const OSSL_CMP_CTX *cmp_ctx, sig_err: res = ossl_x509_print_ex_brief(bio, cert, X509_FLAG_NO_EXTENSIONS); ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_VALIDATING_SIGNATURE); - if (res) - ERR_add_error_mem_bio("\n", bio); + if (res) { + ERR_add_error_txt(NULL, "\n"); + ERR_add_error_mem_bio(NULL, bio); + } res = 0; end: @@ -387,7 +389,7 @@ static int check_msg_with_certs(OSSL_CMP_CTX *ctx, const STACK_OF(X509) *certs, int i; if (sk_X509_num(certs) <= 0) { - ossl_cmp_log1(WARN, ctx, "no %s", desc); + ossl_cmp_log1(INFO, ctx, "no %s", desc); return 0; } @@ -407,7 +409,7 @@ static int check_msg_with_certs(OSSL_CMP_CTX *ctx, const STACK_OF(X509) *certs, } } if (in_extraCerts && n_acceptable_certs == 0) - ossl_cmp_warn(ctx, "no acceptable cert in extraCerts"); + ossl_cmp_log1(WARN, ctx, "no acceptable %s", desc); return 0; } @@ -502,14 +504,14 @@ static int check_msg_find_cert(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg) res = check_msg_all_certs(ctx, msg, 0 /* using ctx->trusted */) || check_msg_all_certs(ctx, msg, 1 /* 3gpp */); - ctx->log_cb = backup_log_cb; - if (res) { - /* discard any diagnostic information on trying to use certs */ - (void)ERR_pop_to_mark(); + + ctx->log_cb = backup_log_cb; /* re-enable logging */ + /* discard any previous diagnostic information on trying to use certs */ + (void)ERR_pop_to_mark(); + + if (res) goto end; - } /* failed finding a sender cert that verifies the message signature */ - (void)ERR_clear_last_mark(); sname = X509_NAME_oneline(sender->d.directoryName, NULL, 0); skid_str = skid == NULL ? NULL : i2s_ASN1_OCTET_STRING(NULL, skid); @@ -732,7 +734,7 @@ int ossl_cmp_msg_check_update(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg, "expected sender", expected_sender)) { str = X509_NAME_oneline(actual_sender, NULL, 0); ERR_raise_data(ERR_LIB_CMP, CMP_R_UNEXPECTED_SENDER, - str != NULL ? str : ""); + "%s", str != NULL ? str : ""); OPENSSL_free(str); return 0; } @@ -776,8 +778,13 @@ int ossl_cmp_msg_check_update(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg, res = 1; /* support more aggressive fuzzing by letting invalid msg pass */ #endif - /* remove extraCerts again if not caching */ - if (ctx->noCacheExtraCerts) + /* + * remove extraCerts again if not caching + * or if we failed validation above, lest a remote user + * starts sending us lots of certificates in invalid messages + * leading to a DOS from unbounded certificate stack growth + */ + if (ctx->noCacheExtraCerts || res != 1) while (num_added-- > 0) X509_free(sk_X509_shift(ctx->untrusted)); diff --git a/crypto/cms/cms_asn1.c b/crypto/cms/cms_asn1.c index fb87f6c6ad273..b3c103699031b 100644 --- a/crypto/cms/cms_asn1.c +++ b/crypto/cms/cms_asn1.c @@ -245,9 +245,9 @@ ASN1_NDEF_SEQUENCE(CMS_AuthEnvelopedData) = { ASN1_IMP_OPT(CMS_AuthEnvelopedData, originatorInfo, CMS_OriginatorInfo, 0), ASN1_SET_OF(CMS_AuthEnvelopedData, recipientInfos, CMS_RecipientInfo), ASN1_SIMPLE(CMS_AuthEnvelopedData, authEncryptedContentInfo, CMS_EncryptedContentInfo), - ASN1_IMP_SET_OF_OPT(CMS_AuthEnvelopedData, authAttrs, X509_ALGOR, 2), + ASN1_IMP_SET_OF_OPT(CMS_AuthEnvelopedData, authAttrs, X509_ATTRIBUTE, 1), ASN1_SIMPLE(CMS_AuthEnvelopedData, mac, ASN1_OCTET_STRING), - ASN1_IMP_SET_OF_OPT(CMS_AuthEnvelopedData, unauthAttrs, X509_ALGOR, 3) + ASN1_IMP_SET_OF_OPT(CMS_AuthEnvelopedData, unauthAttrs, X509_ATTRIBUTE, 2) } ASN1_NDEF_SEQUENCE_END(CMS_AuthEnvelopedData) ASN1_NDEF_SEQUENCE(CMS_AuthenticatedData) = { @@ -257,9 +257,9 @@ ASN1_NDEF_SEQUENCE(CMS_AuthenticatedData) = { ASN1_SIMPLE(CMS_AuthenticatedData, macAlgorithm, X509_ALGOR), ASN1_IMP(CMS_AuthenticatedData, digestAlgorithm, X509_ALGOR, 1), ASN1_SIMPLE(CMS_AuthenticatedData, encapContentInfo, CMS_EncapsulatedContentInfo), - ASN1_IMP_SET_OF_OPT(CMS_AuthenticatedData, authAttrs, X509_ALGOR, 2), + ASN1_IMP_SET_OF_OPT(CMS_AuthenticatedData, authAttrs, X509_ATTRIBUTE, 2), ASN1_SIMPLE(CMS_AuthenticatedData, mac, ASN1_OCTET_STRING), - ASN1_IMP_SET_OF_OPT(CMS_AuthenticatedData, unauthAttrs, X509_ALGOR, 3) + ASN1_IMP_SET_OF_OPT(CMS_AuthenticatedData, unauthAttrs, X509_ATTRIBUTE, 3) } static_ASN1_NDEF_SEQUENCE_END(CMS_AuthenticatedData) ASN1_NDEF_SEQUENCE(CMS_CompressedData) diff --git a/crypto/cms/cms_env.c b/crypto/cms/cms_env.c index a8ecabb64ed76..ee86ae71d3ed6 100644 --- a/crypto/cms/cms_env.c +++ b/crypto/cms/cms_env.c @@ -928,6 +928,7 @@ static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms, CMS_EncryptedContentInfo *ec; CMS_KEKRecipientInfo *kekri; unsigned char *ukey = NULL; + size_t ukey_alloc_len = 0; int ukeylen; int r = 0, wrap_nid; EVP_CIPHER *cipher = NULL; @@ -965,7 +966,8 @@ static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms, goto err; } - ukey = OPENSSL_malloc(kekri->encryptedKey->length - 8); + ukey_alloc_len = (size_t)kekri->encryptedKey->length - 8; + ukey = OPENSSL_malloc(ukey_alloc_len); if (ukey == NULL) goto err; @@ -994,7 +996,7 @@ static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms, err: EVP_CIPHER_free(cipher); if (!r) - OPENSSL_free(ukey); + OPENSSL_clear_free(ukey, ukey_alloc_len); EVP_CIPHER_CTX_free(ctx); return r; @@ -1204,6 +1206,35 @@ BIO *ossl_cms_EnvelopedData_init_bio(CMS_ContentInfo *cms) return cms_EnvelopedData_Decryption_init_bio(cms); } +/* The DER encoding of authAttrs, with the universal SET OF tag, is the AAD */ +static int cms_AuthEnvelopedData_set_aad(BIO *b, + STACK_OF(X509_ATTRIBUTE) *authAttrs) +{ + EVP_CIPHER_CTX *ctx; + unsigned char *aad = NULL; + int aadlen, outl, ok = 0; + const ASN1_ITEM *item; + + if (!BIO_get_cipher_ctx(b, &ctx)) + return 0; + item = EVP_CIPHER_CTX_is_encrypting(ctx) + ? ASN1_ITEM_rptr(CMS_Attributes_AadEncrypt) + : ASN1_ITEM_rptr(CMS_Attributes_AadDecrypt); + aadlen = ASN1_item_i2d((ASN1_VALUE *)authAttrs, &aad, item); + if (aadlen <= 0 || aad == NULL) { + ERR_raise(ERR_LIB_CMS, ERR_R_ASN1_LIB); + goto err; + } + if (EVP_CipherUpdate(ctx, NULL, &outl, aad, aadlen) <= 0) { + ERR_raise(ERR_LIB_CMS, CMS_R_CTRL_FAILURE); + goto err; + } + ok = 1; +err: + OPENSSL_free(aad); + return ok; +} + BIO *ossl_cms_AuthEnvelopedData_init_bio(CMS_ContentInfo *cms) { CMS_EncryptedContentInfo *ec; @@ -1220,9 +1251,16 @@ BIO *ossl_cms_AuthEnvelopedData_init_bio(CMS_ContentInfo *cms) ec->taglen = aenv->mac->length; } ret = ossl_cms_EncryptedContent_init_bio(ec, ossl_cms_get0_cmsctx(cms), 1); + if (ret == NULL) + return NULL; + + /* authAttrs, if present, are the AEAD associated data */ + if (aenv->authAttrs != NULL + && !cms_AuthEnvelopedData_set_aad(ret, aenv->authAttrs)) + goto err; - /* If error or no cipher end of processing */ - if (ret == NULL || ec->cipher == NULL) + /* If no cipher end of processing */ + if (ec->cipher == NULL) return ret; /* Now encrypt content key according to each RecipientInfo type */ diff --git a/crypto/cms/cms_kari.c b/crypto/cms/cms_kari.c index eb5b5d7862857..459991525f09b 100644 --- a/crypto/cms/cms_kari.c +++ b/crypto/cms/cms_kari.c @@ -1,5 +1,5 @@ /* - * Copyright 2013-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2013-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -216,7 +216,9 @@ static int cms_kek_cipher(unsigned char **pout, size_t *poutlen, size_t keklen; int rv = 0; unsigned char *out = NULL; + size_t out_alloc_len = 0; int outlen; + size_t outsize; keklen = EVP_CIPHER_CTX_get_key_length(kari->ctx); if (keklen > EVP_MAX_KEY_LENGTH) @@ -230,10 +232,17 @@ static int cms_kek_cipher(unsigned char **pout, size_t *poutlen, /* obtain output length of ciphered key */ if (!EVP_CipherUpdate(kari->ctx, NULL, &outlen, in, inlen)) goto err; - out = OPENSSL_malloc(outlen); + /* + * On its integrity-failure paths that primitive writes and cleanses up to + * inlen bytes of the output buffer. Size the buffer for that worst case so + * a failed unwrap cannot write past the allocation. + */ + outsize = (size_t)outlen < inlen ? inlen : (size_t)outlen; + out = OPENSSL_malloc(outsize); if (out == NULL) goto err; - if (!EVP_CipherUpdate(kari->ctx, out, &outlen, in, inlen)) + out_alloc_len = (size_t)outlen; + if (!EVP_CipherUpdate(kari->ctx, out, &outlen, in, (int)inlen)) goto err; *pout = out; *poutlen = (size_t)outlen; @@ -242,7 +251,7 @@ static int cms_kek_cipher(unsigned char **pout, size_t *poutlen, err: OPENSSL_cleanse(kek, keklen); if (!rv) - OPENSSL_free(out); + OPENSSL_clear_free(out, out_alloc_len); EVP_CIPHER_CTX_reset(kari->ctx); /* FIXME: WHY IS kari->pctx freed here? /RL */ EVP_PKEY_CTX_free(kari->pctx); diff --git a/crypto/cms/cms_local.h b/crypto/cms/cms_local.h index 94496b3823ef0..55f41af054bed 100644 --- a/crypto/cms/cms_local.h +++ b/crypto/cms/cms_local.h @@ -371,6 +371,9 @@ DECLARE_ASN1_ITEM(CMS_EncryptedContentInfo) DECLARE_ASN1_ITEM(CMS_IssuerAndSerialNumber) DECLARE_ASN1_ITEM(CMS_Attributes_Sign) DECLARE_ASN1_ITEM(CMS_Attributes_Verify) +/* The authAttrs AAD encoding matches the signed-attributes one */ +#define CMS_Attributes_AadEncrypt_it CMS_Attributes_Sign_it +#define CMS_Attributes_AadDecrypt_it CMS_Attributes_Verify_it DECLARE_ASN1_ITEM(CMS_RecipientInfo) DECLARE_ASN1_ITEM(CMS_PasswordRecipientInfo) DECLARE_ASN1_ALLOC_FUNCTIONS(CMS_IssuerAndSerialNumber) diff --git a/crypto/cms/cms_pwri.c b/crypto/cms/cms_pwri.c index 54f0eda2a2d81..de59c74fdd6e9 100644 --- a/crypto/cms/cms_pwri.c +++ b/crypto/cms/cms_pwri.c @@ -315,6 +315,7 @@ int ossl_cms_RecipientInfo_pwri_crypt(const CMS_ContentInfo *cms, EVP_CIPHER *kekcipher; unsigned char *key = NULL; size_t keylen; + size_t key_alloc_len = 0; const CMS_CTX *cms_ctx = ossl_cms_get0_cmsctx(cms); ec = ossl_cms_get0_env_enc_content(cms); @@ -391,6 +392,7 @@ int ossl_cms_RecipientInfo_pwri_crypt(const CMS_ContentInfo *cms, if (key == NULL) goto err; + key_alloc_len = keylen; if (!kek_wrap_key(key, &keylen, ec->key, ec->keylen, kekctx, cms_ctx)) goto err; @@ -400,6 +402,7 @@ int ossl_cms_RecipientInfo_pwri_crypt(const CMS_ContentInfo *cms, key = OPENSSL_malloc(pwri->encryptedKey->length); if (key == NULL) goto err; + key_alloc_len = (size_t)pwri->encryptedKey->length; if (!kek_unwrap_key(key, &keylen, pwri->encryptedKey->data, pwri->encryptedKey->length, kekctx)) { @@ -419,7 +422,7 @@ int ossl_cms_RecipientInfo_pwri_crypt(const CMS_ContentInfo *cms, EVP_CIPHER_CTX_free(kekctx); if (!r) - OPENSSL_free(key); + OPENSSL_clear_free(key, key_alloc_len); X509_ALGOR_free(kekalg); return r; diff --git a/crypto/cms/cms_smime.c b/crypto/cms/cms_smime.c index 4b5009b9d5bf8..dea1df084764c 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/cpuid.c b/crypto/cpuid.c index d659135919d1f..18c648148a30c 100644 --- a/crypto/cpuid.c +++ b/crypto/cpuid.c @@ -102,7 +102,16 @@ void OPENSSL_cpuid_setup(void) if (trigger) return; + /// This function is called from .init section before memory sanitizer mmaps shadow memory. + /// Program will crash with segmentation fault when trying access `trigger`, + /// because its address was replaced with some not mapped address. + /// Also see https://github.com/ClickHouse/openssl/pull/5 + /// Unfortunately, __msan_init() is no longer part of msan's public header and there seems to be no replacement. +#if defined(__has_feature) +# if !__has_feature(memory_sanitizer) trigger = 1; +# endif +#endif if ((env = ossl_getenv("OPENSSL_ia32cap")) != NULL) { int off = (env[0] == '~') ? 1 : 0; diff --git a/crypto/ct/ct_b64.c b/crypto/ct/ct_b64.c index e7eb9740ee08b..01bd8fc508d6d 100644 --- a/crypto/ct/ct_b64.c +++ b/crypto/ct/ct_b64.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -84,7 +84,7 @@ SCT *SCT_new_from_base64(unsigned char version, const char *logid_base64, declen = ct_base64_decode(logid_base64, &dec); if (declen < 0) { - ERR_raise(ERR_LIB_CT, X509_R_BASE64_DECODE_ERROR); + ERR_raise(ERR_LIB_CT, CT_R_BASE64_DECODE_ERROR); goto err; } if (!SCT_set0_log_id(sct, dec, declen)) @@ -93,7 +93,7 @@ SCT *SCT_new_from_base64(unsigned char version, const char *logid_base64, declen = ct_base64_decode(extensions_base64, &dec); if (declen < 0) { - ERR_raise(ERR_LIB_CT, X509_R_BASE64_DECODE_ERROR); + ERR_raise(ERR_LIB_CT, CT_R_BASE64_DECODE_ERROR); goto err; } SCT_set0_extensions(sct, dec, declen); @@ -101,7 +101,7 @@ SCT *SCT_new_from_base64(unsigned char version, const char *logid_base64, declen = ct_base64_decode(signature_base64, &dec); if (declen < 0) { - ERR_raise(ERR_LIB_CT, X509_R_BASE64_DECODE_ERROR); + ERR_raise(ERR_LIB_CT, CT_R_BASE64_DECODE_ERROR); goto err; } diff --git a/crypto/ctype.c b/crypto/ctype.c index 686fe64165fcb..4f19d6002c5e7 100644 --- a/crypto/ctype.c +++ b/crypto/ctype.c @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2017-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -226,7 +226,7 @@ static const unsigned short ctype_char_map[128] = { #ifdef CHARSET_EBCDIC int ossl_toascii(int c) { - if (c < -128 || c > 256 || c == EOF) + if (c < -128 || c >= 256 || c == EOF) return c; /* * Adjust negatively signed characters. @@ -241,7 +241,7 @@ int ossl_toascii(int c) int ossl_fromascii(int c) { - if (c < -128 || c > 256 || c == EOF) + if (c < -128 || c >= 256 || c == EOF) return c; if (c < 0) c += 256; diff --git a/crypto/dh/dh_backend.c b/crypto/dh/dh_backend.c index f68429862cd56..77b0b3257fb7e 100644 --- a/crypto/dh/dh_backend.c +++ b/crypto/dh/dh_backend.c @@ -1,5 +1,5 @@ /* - * Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2020-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -232,7 +232,7 @@ DH *ossl_dh_key_from_pkcs8(const PKCS8_PRIV_KEY_INFO *p8inf, goto done; decerr: - ERR_raise(ERR_LIB_DH, EVP_R_DECODE_ERROR); + ERR_raise(ERR_LIB_DH, DH_R_DECODE_ERROR); dherr: DH_free(dh); dh = NULL; diff --git a/crypto/dh/dh_check.c b/crypto/dh/dh_check.c index 3002609b68f5e..8787945f8a1cd 100644 --- a/crypto/dh/dh_check.c +++ b/crypto/dh/dh_check.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -74,6 +74,14 @@ int DH_check_params(const DH *dh, int *ret) BN_CTX *ctx = NULL; *ret = 0; + /* + * A DH with no modulus or generator cannot be checked. Report + * the failure via |*ret| rather than dereferencing NULL below. + */ + if (dh->params.p == NULL || dh->params.g == NULL) { + *ret = DH_NOT_SUITABLE_GENERATOR | DH_CHECK_P_NOT_PRIME; + return 1; + } ctx = BN_CTX_new_ex(dh->libctx); if (ctx == NULL) goto err; @@ -150,6 +158,11 @@ int DH_check(const DH *dh, int *ret) int nid = DH_get_nid((DH *)dh); *ret = 0; + /* A DH with no modulus or generator cannot be checked. */ + if (dh->params.p == NULL || dh->params.g == NULL) { + *ret = DH_NOT_SUITABLE_GENERATOR | DH_CHECK_P_NOT_PRIME; + return 1; + } if (nid != NID_undef) return 1; @@ -250,6 +263,15 @@ int DH_check_pub_key_ex(const DH *dh, const BIGNUM *pub_key) */ int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret) { + *ret = 0; + /* + * Without a modulus we cannot check anything; signal failure via + * |*ret| rather than crashing in BN_num_bits below. + */ + if (dh->params.p == NULL) { + *ret = DH_CHECK_PUBKEY_INVALID; + return 1; + } /* Don't do any checks at all with an excessively large modulus */ if (BN_num_bits(dh->params.p) > OPENSSL_DH_CHECK_MAX_MODULUS_BITS) { ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE); diff --git a/crypto/dsa/dsa_key.c b/crypto/dsa/dsa_key.c index aa69c3eea8fb8..738915cc4f3d5 100644 --- a/crypto/dsa/dsa_key.c +++ b/crypto/dsa/dsa_key.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -198,7 +198,6 @@ static int dsa_keygen(DSA *dsa) ok = dsa_keygen_pairwise_test(dsa, cb, cbarg) && dsa_keygen_knownanswer_test(dsa, ctx, cb, cbarg); if (!ok) { - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); BN_free(dsa->pub_key); BN_clear_free(dsa->priv_key); dsa->pub_key = NULL; diff --git a/crypto/ec/asm/ecp_nistz256-x86_64.pl b/crypto/ec/asm/ecp_nistz256-x86_64.pl index 4da9a149a99a9..12a104b5ec0fb 100755 --- a/crypto/ec/asm/ecp_nistz256-x86_64.pl +++ b/crypto/ec/asm/ecp_nistz256-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2014-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2014-2026 The OpenSSL Project Authors. All Rights Reserved. # Copyright (c) 2014, Intel Corporation. All Rights Reserved. # Copyright (c) 2015 CloudFlare, Inc. # @@ -80,6 +80,14 @@ $addx = ($ver>=3.03); } +if (!$addx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + $addx = ($1>=11); + } +} + $code.=<<___; .text .extern OPENSSL_ia32cap_P diff --git a/crypto/ec/asm/x25519-x86_64.pl b/crypto/ec/asm/x25519-x86_64.pl index d2285269a308c..204c518548139 100755 --- a/crypto/ec/asm/x25519-x86_64.pl +++ b/crypto/ec/asm/x25519-x86_64.pl @@ -1,5 +1,5 @@ #!/usr/bin/env perl -# Copyright 2018-2020 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2018-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -97,6 +97,13 @@ $addx = ($ver>=3.03); } +if (!$addx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $addx = ($1>=11); #icx started with clang 11 + } +} + $code.=<<___; .text diff --git a/crypto/ec/curve25519.c b/crypto/ec/curve25519.c index c6886763aba7e..5661d33485832 100644 --- a/crypto/ec/curve25519.c +++ b/crypto/ec/curve25519.c @@ -21,6 +21,12 @@ #include "internal/numbers.h" +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) +# include +# endif +#endif + #if defined(X25519_ASM) && (defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)) #define BASE_2_64_IMPLEMENTED @@ -5846,6 +5852,12 @@ int ossl_x25519(uint8_t out_shared_key[32], const uint8_t private_key[32], { static const uint8_t kZeros[32] = { 0 }; x25519_scalar_mult(out_shared_key, private_key, peer_public_value); +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) + /* x25519_scalar_mult may use assembly that MSan cannot instrument. */ + __msan_unpoison(out_shared_key, 32); +# endif +#endif /* The all-zero output results when the input is a point of small order. */ return CRYPTO_memcmp(kZeros, out_shared_key, 32) != 0; } @@ -5875,5 +5887,11 @@ void ossl_x25519_public_from_private(uint8_t out_public_value[32], fe_mul(zplusy, zplusy, zminusy_inv); fe_tobytes(out_public_value, zplusy); +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) + __msan_unpoison(out_public_value, 32); +# endif +#endif + OPENSSL_cleanse(e, sizeof(e)); } diff --git a/crypto/ec/ec_key.c b/crypto/ec/ec_key.c index 8723ead41e0e7..71f1c63e2ab62 100644 --- a/crypto/ec/ec_key.c +++ b/crypto/ec/ec_key.c @@ -1,5 +1,5 @@ /* - * Copyright 2002-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2002-2026 The OpenSSL Project Authors. All Rights Reserved. * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved * * Licensed under the Apache License 2.0 (the "License"). You may not use @@ -236,56 +236,6 @@ int ossl_ec_key_gen(EC_KEY *eckey) return ret; } -/* - * Refer: FIPS 140-3 IG 10.3.A Additional Comment 1 - * Perform a KAT by duplicating the public key generation. - * - * NOTE: This issue requires a background understanding, provided in a separate - * document; the current IG 10.3.A AC1 is insufficient regarding the PCT for - * the key agreement scenario. - * - * Currently IG 10.3.A requires PCT in the mode of use prior to use of the - * key pair, citing the PCT defined in the associated standard. For key - * agreement, the only PCT defined in SP 800-56A is that of Section 5.6.2.4: - * the comparison of the original public key to a newly calculated public key. - */ -static int ecdsa_keygen_knownanswer_test(EC_KEY *eckey, BN_CTX *ctx, - OSSL_CALLBACK *cb, void *cbarg) -{ - int len, ret = 0; - OSSL_SELF_TEST *st = NULL; - unsigned char bytes[512] = { 0 }; - EC_POINT *pub_key2 = NULL; - - st = OSSL_SELF_TEST_new(cb, cbarg); - if (st == NULL) - return 0; - - OSSL_SELF_TEST_onbegin(st, OSSL_SELF_TEST_TYPE_PCT_KAT, - OSSL_SELF_TEST_DESC_PCT_ECDSA); - - if ((pub_key2 = EC_POINT_new(eckey->group)) == NULL) - goto err; - - /* pub_key = priv_key * G (where G is a point on the curve) */ - if (!EC_POINT_mul(eckey->group, pub_key2, eckey->priv_key, NULL, NULL, ctx)) - goto err; - - if (BN_num_bytes(pub_key2->X) > (int)sizeof(bytes)) - goto err; - len = BN_bn2bin(pub_key2->X, bytes); - if (OSSL_SELF_TEST_oncorrupt_byte(st, bytes) - && BN_bin2bn(bytes, len, pub_key2->X) == NULL) - goto err; - ret = !EC_POINT_cmp(eckey->group, eckey->pub_key, pub_key2, ctx); - -err: - OSSL_SELF_TEST_onend(st, ret); - OSSL_SELF_TEST_free(st); - EC_POINT_free(pub_key2); - return ret; -} - /* * ECC Key generation. * See SP800-56AR3 5.6.1.2.2 "Key Pair Generation by Testing Candidates" @@ -382,13 +332,11 @@ static int ec_generate_key(EC_KEY *eckey, int pairwise_test) void *cbarg = NULL; OSSL_SELF_TEST_get_callback(eckey->libctx, &cb, &cbarg); - ok = ecdsa_keygen_pairwise_test(eckey, cb, cbarg) - && ecdsa_keygen_knownanswer_test(eckey, ctx, cb, cbarg); + ok = ecdsa_keygen_pairwise_test(eckey, cb, cbarg); } err: /* Step (9): If there is an error return an invalid keypair. */ if (!ok) { - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); BN_clear(eckey->priv_key); if (eckey->pub_key != NULL) EC_POINT_set_to_infinity(group, eckey->pub_key); diff --git a/crypto/engine/eng_lib.c b/crypto/engine/eng_lib.c index 04a2602ed2d8c..bc643a1b4e67f 100644 --- a/crypto/engine/eng_lib.c +++ b/crypto/engine/eng_lib.c @@ -12,6 +12,12 @@ #include #include "internal/refcount.h" +#if defined(__has_feature) +# if __has_feature(address_sanitizer) +#include +# endif +#endif + CRYPTO_RWLOCK *global_engine_lock; CRYPTO_ONCE engine_lock_init = CRYPTO_ONCE_STATIC_INIT; @@ -33,8 +39,18 @@ ENGINE *ENGINE_new(void) ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB); return 0; } +#if defined(__has_feature) +# if __has_feature(address_sanitizer) + __lsan_disable(); +# endif +#endif if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) return NULL; +#if defined(__has_feature) +# if __has_feature(address_sanitizer) + __lsan_enable(); +# endif +#endif if (!CRYPTO_NEW_REF(&ret->struct_ref, 1)) { OPENSSL_free(ret); return NULL; diff --git a/crypto/err/err.c b/crypto/err/err.c index a995c4e2422de..2a0af875b44d2 100644 --- a/crypto/err/err.c +++ b/crypto/err/err.c @@ -26,6 +26,12 @@ #include "internal/e_os.h" #include "err_local.h" +#if defined(__has_feature) +# if __has_feature(address_sanitizer) +#include +# endif +#endif + /* Forward declaration in case it's not published because of configuration */ ERR_STATE *ERR_get_state(void); @@ -689,7 +695,17 @@ ERR_STATE *ossl_err_get_state_int(void) if (!CRYPTO_THREAD_set_local(&err_thread_local, (ERR_STATE *)-1)) return NULL; +#if defined(__has_feature) +# if __has_feature(address_sanitizer) + __lsan_disable(); +# endif +#endif state = OSSL_ERR_STATE_new(); +#if defined(__has_feature) +# if __has_feature(address_sanitizer) + __lsan_enable(); +# endif +#endif if (state == NULL) { CRYPTO_THREAD_set_local(&err_thread_local, NULL); return NULL; diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 5b2ea1c4a4e67..be65c1767ec6a 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1861,6 +1861,7 @@ X509_R_CANT_CHECK_DH_KEY:114:can't check dh key X509_R_CERTIFICATE_VERIFICATION_FAILED:139:certificate verification failed X509_R_CERT_ALREADY_IN_HASH_TABLE:101:cert already in hash table X509_R_CRL_ALREADY_DELTA:127:crl already delta +X509_R_CRL_SIGNATURE_ALGORITHM_MISMATCH:147:crl signature algorithm mismatch X509_R_CRL_VERIFY_FAILURE:131:crl verify failure X509_R_DUPLICATE_ATTRIBUTE:140:duplicate attribute X509_R_ERROR_GETTING_MD_BY_NID:141:error getting md by nid diff --git a/crypto/evp/exchange.c b/crypto/evp/exchange.c index 088d2fdc6e731..30299d67defd0 100644 --- a/crypto/evp/exchange.c +++ b/crypto/evp/exchange.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -287,7 +287,9 @@ int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[]) * iteration we're on. */ EVP_KEYEXCH_free(exchange); + exchange = NULL; EVP_KEYMGMT_free(tmp_keymgmt); + tmp_keymgmt = NULL; switch (iter) { case 1: diff --git a/crypto/ffc/ffc_params_generate.c b/crypto/ffc/ffc_params_generate.c index 969cca76f999b..94b1602dd28e8 100644 --- a/crypto/ffc/ffc_params_generate.c +++ b/crypto/ffc/ffc_params_generate.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -77,6 +77,13 @@ static int ffc_validate_LN(size_t L, size_t N, int type, int verify) ERR_raise(ERR_LIB_DH, DH_R_BAD_FFC_PARAMETERS); #endif } else if (type == FFC_PARAM_TYPE_DSA) { + if (N > 512) { +#ifndef OPENSSL_NO_DSA + ERR_raise_data(ERR_LIB_DSA, DSA_R_BAD_FFC_PARAMETERS, + "N is %zu, but the maximum supported N is 512", N); +#endif + return 0; + } if (L >= 3072 && N >= 256) return 128; if (L >= 2048 && N >= 224) diff --git a/crypto/hmac/hmac.c b/crypto/hmac/hmac.c index c5d42db820200..77b97b6bef6ad 100644 --- a/crypto/hmac/hmac.c +++ b/crypto/hmac/hmac.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -50,9 +50,11 @@ int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len, return 0; #ifdef OPENSSL_HMAC_S390X - rv = s390x_HMAC_init(ctx, key, len, impl); - if (rv >= 1) - return rv; + { + int ret = s390x_HMAC_init(ctx, key, len, impl); + if (ret != -1) /* -1 means SW fallback */ + return ret; + } #endif if (key != NULL) { diff --git a/crypto/http/http_lib.c b/crypto/http/http_lib.c index 05bf4be78856a..d7227f5df2480 100644 --- a/crypto/http/http_lib.c +++ b/crypto/http/http_lib.c @@ -21,6 +21,7 @@ #define NI_MAXHOST 255 #endif #include "crypto/ctype.h" /* for ossl_isspace() */ +#define OSSL_URL_SCHEME_SUFFIX "://" static void init_pstring(char **pstr) { @@ -79,16 +80,20 @@ int OSSL_parse_url(const char *url, char **pscheme, char **puser, char **phost, return 0; } - /* check for optional prefix "://" */ - scheme = scheme_end = url; - p = strstr(url, "://"); - if (p == NULL) { - p = url; - } else { - scheme_end = p; - if (scheme_end == scheme) - goto parse_err; - p += strlen("://"); + /* check for optional prefix "://" as per RFC 3986: */ + scheme = scheme_end = p = url; + if (ossl_isalpha(*p)) { + while (*p != '\0' + && (ossl_isalpha(*p) + || ossl_isdigit(*p) + || strchr("+-.", *p) != NULL)) + p++; + if (HAS_PREFIX(p, OSSL_URL_SCHEME_SUFFIX)) { + scheme_end = p; + p += sizeof(OSSL_URL_SCHEME_SUFFIX) - 1; + } else { + p = url; + } } /* parse optional "userinfo@" */ @@ -105,7 +110,7 @@ int OSSL_parse_url(const char *url, char **pscheme, char **puser, char **phost, /* parse hostname/address as far as needed here */ if (host[0] == '[') { /* IPv6 literal, which may include ':' */ - host_end = strchr(host + 1, ']'); + host_end = memchr(host + 1, ']', authority_end - host - 1); if (host_end == NULL) goto parse_err; p = ++host_end; diff --git a/crypto/ml_dsa/ml_dsa_encoders.c b/crypto/ml_dsa/ml_dsa_encoders.c index 00e2b1772cf94..9ebe5ae02d9b7 100644 --- a/crypto/ml_dsa/ml_dsa_encoders.c +++ b/crypto/ml_dsa/ml_dsa_encoders.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -932,6 +932,9 @@ int ossl_ml_dsa_sig_encode(const ML_DSA_SIG *sig, const ML_DSA_PARAMS *params, ret = 1; err: WPACKET_finish(&pkt); + /* Erase any partial signature output on failure */ + if (ret == 0) + OPENSSL_cleanse(out, params->sig_len); return ret; } diff --git a/crypto/ml_dsa/ml_dsa_key.c b/crypto/ml_dsa/ml_dsa_key.c index e999b6c08d092..66e2ff2b61a02 100644 --- a/crypto/ml_dsa/ml_dsa_key.c +++ b/crypto/ml_dsa/ml_dsa_key.c @@ -346,10 +346,15 @@ static int public_from_private(const ML_DSA_KEY *key, EVP_MD_CTX *md_ctx, /* Compress t */ vector_power2_round(&t, t1, t0); - /* Zeroize secret */ - vector_zero(&s1_ntt); ret = 1; err: + /* + * The low bits of |t| are private and |s1_ntt| is secret, wipe both. + * The trailing |a_ntt| matrix is not wiped: per FIPS 204 section 3.6.3 + * the matrix A is easily computed from the public key and does not + * require any special protections. + */ + OPENSSL_cleanse(polys, (k + l) * sizeof(*polys)); OPENSSL_free(polys); return ret; } @@ -370,6 +375,7 @@ int ossl_ml_dsa_key_public_from_private(ML_DSA_KEY *key) && shake_xof(md_ctx, key->shake256_md, key->pub_encoding, key->params->pk_len, key->tr, sizeof(key->tr)); + vector_zero(&t0); vector_free(&t0); EVP_MD_CTX_free(md_ctx); return ret; @@ -401,7 +407,7 @@ int ossl_ml_dsa_key_pairwise_check(const ML_DSA_KEY *key) ret = vector_equal(&t1, &key->t1) && vector_equal(&t0, &key->t0); err: EVP_MD_CTX_free(md_ctx); - OPENSSL_free(polys); + OPENSSL_clear_free(polys, 2 * k * sizeof(*polys)); return ret; } @@ -489,7 +495,7 @@ int ossl_ml_dsa_generate_key(ML_DSA_KEY *out) "explicit %s private key does not match seed", out->params->alg); } - OPENSSL_free(sk); + OPENSSL_clear_free(sk, out->params->sk_len); } return ret; } diff --git a/crypto/ml_dsa/ml_dsa_matrix.c b/crypto/ml_dsa/ml_dsa_matrix.c index c7ff59845217f..94fd16936c8b5 100644 --- a/crypto/ml_dsa/ml_dsa_matrix.c +++ b/crypto/ml_dsa/ml_dsa_matrix.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -7,6 +7,7 @@ * https://www.openssl.org/source/license.html */ +#include #include "ml_dsa_local.h" #include "ml_dsa_vector.h" #include "ml_dsa_matrix.h" @@ -25,15 +26,16 @@ void ossl_ml_dsa_matrix_mult_vector(const MATRIX *a, const VECTOR *s, { size_t i, j; POLY *poly = a->m_poly; + POLY product; vector_zero(t); for (i = 0; i < a->k; i++) { for (j = 0; j < a->l; j++) { - POLY product; - ossl_ml_dsa_poly_ntt_mult(poly++, &s->poly[j], &product); poly_add(&product, &t->poly[i], &t->poly[i]); } } + + OPENSSL_cleanse(&product, sizeof(product)); } diff --git a/crypto/ml_dsa/ml_dsa_sample.c b/crypto/ml_dsa/ml_dsa_sample.c index 6fae4c4a0de5c..f8ce638dc2295 100644 --- a/crypto/ml_dsa/ml_dsa_sample.c +++ b/crypto/ml_dsa/ml_dsa_sample.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -8,6 +8,7 @@ */ #include +#include #include "ml_dsa_local.h" #include "ml_dsa_vector.h" #include "ml_dsa_matrix.h" @@ -159,13 +160,14 @@ static int rej_bounded_poly(EVP_MD_CTX *h_ctx, const EVP_MD *md, COEFF_FROM_NIBBLE_FUNC *coef_from_nibble, const uint8_t *seed, size_t seed_len, POLY *out) { + int ret = 0; int j = 0; uint32_t z0, z1; uint8_t blocks[SHAKE256_BLOCKSIZE], *b, *end = blocks + sizeof(blocks); /* Instead of just squeezing 1 byte at a time, we grab a whole block */ if (!shake_xof(h_ctx, md, seed, seed_len, blocks, sizeof(blocks))) - return 0; + goto err; while (1) { for (b = blocks; b < end; b++) { @@ -173,15 +175,22 @@ static int rej_bounded_poly(EVP_MD_CTX *h_ctx, const EVP_MD *md, z1 = *b >> 4; /* high nibble of byte */ if (coef_from_nibble(z0, &out->coeff[j]) - && ++j >= ML_DSA_NUM_POLY_COEFFICIENTS) - return 1; + && ++j >= ML_DSA_NUM_POLY_COEFFICIENTS) { + ret = 1; + goto err; + } if (coef_from_nibble(z1, &out->coeff[j]) - && ++j >= ML_DSA_NUM_POLY_COEFFICIENTS) - return 1; + && ++j >= ML_DSA_NUM_POLY_COEFFICIENTS) { + ret = 1; + goto err; + } } if (!EVP_DigestSqueeze(h_ctx, blocks, sizeof(blocks))) - return 0; + goto err; } +err: + OPENSSL_cleanse(blocks, sizeof(blocks)); + return ret; } /** @@ -205,6 +214,13 @@ int ossl_ml_dsa_matrix_expand_A(EVP_MD_CTX *g_ctx, const EVP_MD *md, uint8_t derived_seed[ML_DSA_RHO_BYTES + 2]; POLY *poly = out->m_poly; + /* + * The seeds derived below and the sampling buffers in rej_ntt_poly() are + * not cleansed: per FIPS 204 section 3.6.3 the matrix A is easily + * computed from the public key and does not require any special + * protections. + */ + /* The seed used for each matrix element is rho + column_index + row_index */ memcpy(derived_seed, rho, ML_DSA_RHO_BYTES); @@ -274,6 +290,7 @@ int ossl_ml_dsa_vector_expand_S(EVP_MD_CTX *h_ctx, const EVP_MD *md, int eta, } ret = 1; err: + OPENSSL_cleanse(derived_seed, sizeof(derived_seed)); return ret; } @@ -284,9 +301,11 @@ int ossl_ml_dsa_poly_expand_mask(POLY *out, const uint8_t *seed, size_t seed_len { uint8_t buf[32 * 20]; size_t buf_len = 32 * (gamma1 == ML_DSA_GAMMA1_TWO_POWER_19 ? 20 : 18); - - return shake_xof(h_ctx, md, seed, seed_len, buf, buf_len) + int ret = shake_xof(h_ctx, md, seed, seed_len, buf, buf_len) && ossl_ml_dsa_poly_decode_expand_mask(out, buf, buf_len, gamma1); + + OPENSSL_cleanse(buf, sizeof(buf)); + return ret; } /* @@ -311,13 +330,14 @@ int ossl_ml_dsa_poly_sample_in_ball(POLY *out_c, const uint8_t *seed, int seed_l uint64_t signs; int offset = 8; size_t end; + int ret = 0; /* * Rather than squeeze 8 bytes followed by lots of 1 byte squeezes * the SHAKE blocksize is squeezed each time and buffered into 'block'. */ if (!shake_xof(h_ctx, md, seed, seed_len, block, sizeof(block))) - return 0; + goto err; /* * grab the first 64 bits - since tau < 64 @@ -336,7 +356,7 @@ int ossl_ml_dsa_poly_sample_in_ball(POLY *out_c, const uint8_t *seed, int seed_l if (offset == sizeof(block)) { /* squeeze another block if the bytes from block have been used */ if (!EVP_DigestSqueeze(h_ctx, block, sizeof(block))) - return 0; + goto err; offset = 0; } @@ -354,5 +374,8 @@ int ossl_ml_dsa_poly_sample_in_ball(POLY *out_c, const uint8_t *seed, int seed_l out_c->coeff[index] = mod_sub(1, 2 * (signs & 1)); signs >>= 1; /* grab the next random bit */ } - return 1; + ret = 1; +err: + OPENSSL_cleanse(block, sizeof(block)); + return ret; } diff --git a/crypto/ml_dsa/ml_dsa_sign.c b/crypto/ml_dsa/ml_dsa_sign.c index 71eccf8759635..166a604bcd577 100644 --- a/crypto/ml_dsa/ml_dsa_sign.c +++ b/crypto/ml_dsa/ml_dsa_sign.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -197,6 +197,7 @@ static int ml_dsa_sign_internal(const ML_DSA_KEY *priv, int msg_is_mu, EVP_MD_CTX_free(md_ctx); OPENSSL_clear_free(alloc, alloc_len); OPENSSL_cleanse(rho_prime, sizeof(rho_prime)); + OPENSSL_cleanse(c_tilde, sizeof(c_tilde)); return ret; } @@ -387,7 +388,13 @@ int ossl_ml_dsa_sign(const ML_DSA_KEY *priv, int msg_is_mu, alloced_m = m; } ret = ml_dsa_sign_internal(priv, msg_is_mu, m, m_len, rand, rand_len, sig); - OPENSSL_free(alloced_m); + /* The encoded message may contain confidential message content */ + if (m != msg) { + if (m != m_tmp) + OPENSSL_clear_free(alloced_m, m_len); + else + OPENSSL_cleanse(m_tmp, sizeof(m_tmp)); + } } if (sig_len != NULL) *sig_len = priv->params->sig_len; @@ -424,6 +431,12 @@ int ossl_ml_dsa_verify(const ML_DSA_KEY *pub, int msg_is_mu, } ret = ml_dsa_verify_internal(pub, msg_is_mu, m, m_len, sig, sig_len); - OPENSSL_free(alloced_m); + /* The encoded message may contain confidential message content */ + if (m != msg) { + if (m != m_tmp) + OPENSSL_clear_free(alloced_m, m_len); + else + OPENSSL_cleanse(m_tmp, sizeof(m_tmp)); + } return ret; } diff --git a/crypto/ml_dsa/ml_dsa_vector.h b/crypto/ml_dsa/ml_dsa_vector.h index d24bf031a292a..1f3e6a03299cf 100644 --- a/crypto/ml_dsa/ml_dsa_vector.h +++ b/crypto/ml_dsa/ml_dsa_vector.h @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -8,6 +8,7 @@ */ #include +#include #include "ml_dsa_poly.h" struct vector_st { @@ -153,6 +154,7 @@ vector_expand_mask(VECTOR *out, const uint8_t *rho_prime, size_t rho_prime_len, poly_expand_mask(out->poly + i, derived_seed, sizeof(derived_seed), gamma1, h_ctx, md); } + OPENSSL_cleanse(derived_seed, sizeof(derived_seed)); } /* Scale back previously rounded value */ diff --git a/crypto/ml_kem/ml_kem.c b/crypto/ml_kem/ml_kem.c index dd8a39197ac8b..6c3141ca2d32e 100644 --- a/crypto/ml_kem/ml_kem.c +++ b/crypto/ml_kem/ml_kem.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -1310,6 +1310,12 @@ static __owur int matrix_expand(EVP_MD_CTX *mdctx, ML_KEM_KEY *key) int rank = key->vinfo->rank; int i, j; + /* + * The seeds derived below and the sampling buffers in sample_scalar() + * are not cleansed: per FIPS 203 section 3.3 the matrix A is easily + * computed from the public encapsulation key and does not require any + * special protections. + */ memcpy(input, key->rho, ML_KEM_RANDOM_BYTES); for (i = 0; i < rank; i++) { for (j = 0; j < rank; j++) { @@ -1340,8 +1346,10 @@ static __owur int cbd_2(scalar *out, uint8_t in[ML_KEM_RANDOM_BYTES + 1], uint16_t value, mask; uint8_t b; - if (!prf(randbuf, sizeof(randbuf), in, mdctx, key)) + if (!prf(randbuf, sizeof(randbuf), in, mdctx, key)) { + OPENSSL_cleanse((void *)randbuf, sizeof(randbuf)); return 0; + } do { b = *r++; @@ -1363,6 +1371,8 @@ static __owur int cbd_2(scalar *out, uint8_t in[ML_KEM_RANDOM_BYTES + 1], mask = constish_time_non_zero(value >> 15); *curr++ = value + (kPrime & mask); } while (curr < end); + + OPENSSL_cleanse((void *)randbuf, sizeof(randbuf)); return 1; } @@ -1380,8 +1390,10 @@ static __owur int cbd_3(scalar *out, uint8_t in[ML_KEM_RANDOM_BYTES + 1], uint8_t b1, b2, b3; uint16_t value, mask; - if (!prf(randbuf, sizeof(randbuf), in, mdctx, key)) + if (!prf(randbuf, sizeof(randbuf), in, mdctx, key)) { + OPENSSL_cleanse((void *)randbuf, sizeof(randbuf)); return 0; + } do { b1 = *r++; @@ -1415,6 +1427,8 @@ static __owur int cbd_3(scalar *out, uint8_t in[ML_KEM_RANDOM_BYTES + 1], mask = constish_time_non_zero(value >> 15); *curr++ = value + (kPrime & mask); } while (curr < end); + + OPENSSL_cleanse((void *)randbuf, sizeof(randbuf)); return 1; } @@ -1427,14 +1441,19 @@ static __owur int gencbd_vector(scalar *out, CBD_FUNC cbd, uint8_t *counter, EVP_MD_CTX *mdctx, const ML_KEM_KEY *key) { uint8_t input[ML_KEM_RANDOM_BYTES + 1]; + int ret = 0; memcpy(input, seed, ML_KEM_RANDOM_BYTES); do { input[ML_KEM_RANDOM_BYTES] = (*counter)++; if (!cbd(out++, input, mdctx, key)) - return 0; + goto end; } while (--rank > 0); - return 1; + ret = 1; + +end: + OPENSSL_cleanse((void *)input, sizeof(input)); + return ret; } /* @@ -1445,15 +1464,20 @@ static __owur int gencbd_vector_ntt(scalar *out, CBD_FUNC cbd, uint8_t *counter, EVP_MD_CTX *mdctx, const ML_KEM_KEY *key) { uint8_t input[ML_KEM_RANDOM_BYTES + 1]; + int ret = 0; memcpy(input, seed, ML_KEM_RANDOM_BYTES); do { input[ML_KEM_RANDOM_BYTES] = (*counter)++; if (!cbd(out, input, mdctx, key)) - return 0; + goto end; scalar_ntt(out++); } while (--rank > 0); - return 1; + ret = 1; + +end: + OPENSSL_cleanse((void *)input, sizeof(input)); + return ret; } /* The |ETA1| value for ML-KEM-512 is 3, the rest and all ETA2 values are 2. */ @@ -1492,10 +1516,11 @@ static __owur int encrypt_cpa(uint8_t out[ML_KEM_SHARED_SECRET_BYTES], uint8_t counter = 0; int du = vinfo->du; int dv = vinfo->dv; + int ret = 0; /* FIPS 203 "y" vector */ if (!gencbd_vector_ntt(y, cbd_1, &counter, r, rank, mdctx, key)) - return 0; + goto end; /* FIPS 203 "v" scalar */ inner_product(&v, key->t, y, rank); scalar_inverse_ntt(&v); @@ -1504,7 +1529,7 @@ static __owur int encrypt_cpa(uint8_t out[ML_KEM_SHARED_SECRET_BYTES], /* All done with |y|, now free to reuse tmp[0] for FIPS 203 |e1| */ if (!gencbd_vector(e1, cbd_2, &counter, r, rank, mdctx, key)) - return 0; + goto end; vector_add(u, e1, rank); vector_compress(u, du, rank); vector_encode(out, u, du, rank); @@ -1513,14 +1538,19 @@ static __owur int encrypt_cpa(uint8_t out[ML_KEM_SHARED_SECRET_BYTES], memcpy(input, r, ML_KEM_RANDOM_BYTES); input[ML_KEM_RANDOM_BYTES] = counter; if (!cbd_2(e2, input, mdctx, key)) - return 0; + goto end; scalar_add(&v, e2); /* Combine message with |v| */ scalar_decode_decompress_add(&v, message); scalar_compress(&v, dv); scalar_encode(out + vinfo->u_vector_bytes, &v, dv); - return 1; + ret = 1; + +end: + OPENSSL_cleanse((void *)input, sizeof(input)); + OPENSSL_cleanse((void *)&v, sizeof(v)); + return ret; } /* @@ -1544,6 +1574,9 @@ decrypt_cpa(uint8_t out[ML_KEM_SHARED_SECRET_BYTES], scalar_sub(&v, &mask); scalar_compress(&v, 1); scalar_encode_1(out, &v); + + OPENSSL_cleanse((void *)&v, sizeof(v)); + OPENSSL_cleanse((void *)&mask, sizeof(mask)); } /*- @@ -1737,8 +1770,8 @@ static __owur int genkey(const uint8_t seed[ML_KEM_SEED_BYTES], ret = 1; end: - OPENSSL_cleanse((void *)augmented_seed, ML_KEM_RANDOM_BYTES); - OPENSSL_cleanse((void *)sigma, ML_KEM_RANDOM_BYTES); + OPENSSL_cleanse((void *)augmented_seed, sizeof(augmented_seed)); + OPENSSL_cleanse((void *)hashed, sizeof(hashed)); if (ret == 0) { ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR, "internal error while generating %s private key", @@ -1776,6 +1809,7 @@ static int encap(uint8_t *ctext, uint8_t secret[ML_KEM_SHARED_SECRET_BYTES], ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR, "internal error while performing %s encapsulation", key->vinfo->algorithm_name); + OPENSSL_cleanse((void *)Kr, sizeof(Kr)); return ret; } @@ -1822,6 +1856,7 @@ static int decap(uint8_t secret[ML_KEM_SHARED_SECRET_BYTES], ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR, "internal error while performing %s decapsulation", vinfo->algorithm_name); + OPENSSL_cleanse(failure_key, sizeof(failure_key)); return 0; } decrypt_cpa(decrypted, ctext, tmp, key); @@ -1830,6 +1865,8 @@ static int decap(uint8_t secret[ML_KEM_SHARED_SECRET_BYTES], || !encrypt_cpa(tmp_ctext, decrypted, r, tmp, mdctx, key)) { memcpy(secret, failure_key, ML_KEM_SHARED_SECRET_BYTES); OPENSSL_cleanse(decrypted, ML_KEM_SHARED_SECRET_BYTES); + OPENSSL_cleanse(Kr, sizeof(Kr)); + OPENSSL_cleanse(failure_key, sizeof(failure_key)); return 1; } mask = constant_time_eq_int_8(0, @@ -1838,6 +1875,7 @@ static int decap(uint8_t secret[ML_KEM_SHARED_SECRET_BYTES], secret[i] = constant_time_select_8(mask, Kr[i], failure_key[i]); OPENSSL_cleanse(decrypted, ML_KEM_SHARED_SECRET_BYTES); OPENSSL_cleanse(Kr, sizeof(Kr)); + OPENSSL_cleanse(failure_key, sizeof(failure_key)); return 1; } @@ -1845,7 +1883,7 @@ static int decap(uint8_t secret[ML_KEM_SHARED_SECRET_BYTES], * After allocating storage for public or private key data, update the key * component pointers to reference that storage. */ -static __owur int add_storage(scalar *p, int private, ML_KEM_KEY *key) +static __owur int add_storage(scalar *p, int private, int dup, ML_KEM_KEY *key) { int rank = key->vinfo->rank; @@ -1854,9 +1892,12 @@ static __owur int add_storage(scalar *p, int private, ML_KEM_KEY *key) /* * We're adding key material, the seed buffer will now hold |rho| and - * |pkhash|. + * |pkhash|. Zero the key hash when creating fresh keys; when + * duplicating, |key| was memdup'd from the source so |seedbuf| + * already carries the correct |rho|/|pkhash| bytes — preserve them. */ - memset(key->seedbuf, 0, sizeof(key->seedbuf)); + if (dup == 0) + memset(key->seedbuf, 0, sizeof(key->seedbuf)); key->rho = key->seedbuf; key->pkhash = key->seedbuf + ML_KEM_RANDOM_BYTES; key->d = key->z = NULL; @@ -1980,18 +2021,18 @@ ML_KEM_KEY *ossl_ml_kem_key_dup(const ML_KEM_KEY *key, int selection) selection = 0; else if (!ossl_ml_kem_have_prvkey(key)) selection &= ~OSSL_KEYMGMT_SELECT_PRIVATE_KEY; + else if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + selection &= ~OSSL_KEYMGMT_SELECT_PUBLIC_KEY; switch (selection & OSSL_KEYMGMT_SELECT_KEYPAIR) { case 0: ok = 1; break; case OSSL_KEYMGMT_SELECT_PUBLIC_KEY: - ok = add_storage(OPENSSL_memdup(key->t, key->vinfo->puballoc), 0, ret); - ret->rho = ret->seedbuf; - ret->pkhash = ret->rho + ML_KEM_RANDOM_BYTES; + ok = add_storage(OPENSSL_memdup(key->t, key->vinfo->puballoc), 0, 1, ret); break; case OSSL_KEYMGMT_SELECT_PRIVATE_KEY: - ok = add_storage(OPENSSL_memdup(key->t, key->vinfo->prvalloc), 1, ret); + ok = add_storage(OPENSSL_memdup(key->t, key->vinfo->prvalloc), 1, 1, ret); /* Duplicated keys retain |d|, if available */ if (key->d != NULL) ret->d = ret->z + ML_KEM_RANDOM_BYTES; @@ -2111,7 +2152,7 @@ int ossl_ml_kem_parse_public_key(const uint8_t *in, size_t len, ML_KEM_KEY *key) || (mdctx = EVP_MD_CTX_new()) == NULL) return 0; - if (add_storage(OPENSSL_malloc(vinfo->puballoc), 0, key)) + if (add_storage(OPENSSL_malloc(vinfo->puballoc), 0, 0, key)) ret = parse_pubkey(in, mdctx, key); if (!ret) @@ -2139,7 +2180,7 @@ int ossl_ml_kem_parse_private_key(const uint8_t *in, size_t len, || (mdctx = EVP_MD_CTX_new()) == NULL) return 0; - if (add_storage(OPENSSL_malloc(vinfo->prvalloc), 1, key)) + if (add_storage(OPENSSL_malloc(vinfo->prvalloc), 1, 0, key)) ret = parse_prvkey(in, mdctx, key); if (!ret) @@ -2187,7 +2228,7 @@ int ossl_ml_kem_genkey(uint8_t *pubenc, size_t publen, ML_KEM_KEY *key) */ CONSTTIME_SECRET(seed, ML_KEM_SEED_BYTES); - if (add_storage(OPENSSL_malloc(vinfo->prvalloc), 1, key)) + if (add_storage(OPENSSL_malloc(vinfo->prvalloc), 1, 0, key)) ret = genkey(seed, mdctx, pubenc, key); OPENSSL_cleanse(seed, sizeof(seed)); @@ -2196,6 +2237,9 @@ int ossl_ml_kem_genkey(uint8_t *pubenc, size_t publen, ML_KEM_KEY *key) EVP_MD_CTX_free(mdctx); if (!ret) { + /* Erase any partial public key output */ + if (pubenc != NULL) + OPENSSL_cleanse(pubenc, vinfo->pubkey_bytes); ossl_ml_kem_key_reset(key); return 0; } @@ -2254,6 +2298,10 @@ int ossl_ml_kem_encap_seed(uint8_t *ctext, size_t clen, } #undef case_encap_seed + /* Erase any partial ciphertext output on failure */ + if (!ret) + OPENSSL_cleanse(ctext, clen); + /* Declassify secret inputs and derived outputs before returning control */ CONSTTIME_DECLASSIFY(entropy, elen); CONSTTIME_DECLASSIFY(ctext, clen); @@ -2268,6 +2316,7 @@ int ossl_ml_kem_encap_rand(uint8_t *ctext, size_t clen, const ML_KEM_KEY *key) { uint8_t r[ML_KEM_RANDOM_BYTES]; + int ret; if (key == NULL) return 0; @@ -2277,8 +2326,11 @@ int ossl_ml_kem_encap_rand(uint8_t *ctext, size_t clen, < 1) return 0; - return ossl_ml_kem_encap_seed(ctext, clen, shared_secret, slen, + ret = ossl_ml_kem_encap_seed(ctext, clen, shared_secret, slen, r, sizeof(r), key); + + OPENSSL_cleanse((void *)r, sizeof(r)); + return ret; } int ossl_ml_kem_decap(uint8_t *shared_secret, size_t slen, @@ -2293,11 +2345,13 @@ int ossl_ml_kem_decap(uint8_t *shared_secret, size_t slen, #endif /* Need a private key here */ - if (!ossl_ml_kem_have_prvkey(key)) + if (!ossl_ml_kem_have_prvkey(key) + || shared_secret == NULL + || slen < ML_KEM_SHARED_SECRET_BYTES) return 0; vinfo = key->vinfo; - if (shared_secret == NULL || slen != ML_KEM_SHARED_SECRET_BYTES + if (slen != ML_KEM_SHARED_SECRET_BYTES || ctext == NULL || clen != vinfo->ctext_bytes || (mdctx = EVP_MD_CTX_new()) == NULL) { (void)RAND_bytes_ex(key->libctx, shared_secret, @@ -2326,6 +2380,7 @@ int ossl_ml_kem_decap(uint8_t *shared_secret, size_t slen, \ ret = decap(shared_secret, ctext, cbuf, tmp, mdctx, key); \ OPENSSL_cleanse((void *)tmp, sizeof(tmp)); \ + OPENSSL_cleanse((void *)cbuf, sizeof(cbuf)); \ break; \ } switch (vinfo->evp_type) { diff --git a/crypto/modes/asm/aes-gcm-avx512.pl b/crypto/modes/asm/aes-gcm-avx512.pl index 054672bb6b9bf..3da7c69cb985c 100644 --- a/crypto/modes/asm/aes-gcm-avx512.pl +++ b/crypto/modes/asm/aes-gcm-avx512.pl @@ -1,4 +1,4 @@ -# Copyright 2021-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2021-2026 The OpenSSL Project Authors. All Rights Reserved. # Copyright (c) 2021, Intel Corporation. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use @@ -72,6 +72,13 @@ } } +if (!$avx512vaes && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx512vaes = ($1>=11); #icx started with clang 11 + } +} + open OUT, "| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT = *OUT; diff --git a/crypto/modes/asm/aesni-gcm-x86_64.pl b/crypto/modes/asm/aesni-gcm-x86_64.pl index c63570bae42f6..202883dac35e5 100644 --- a/crypto/modes/asm/aesni-gcm-x86_64.pl +++ b/crypto/modes/asm/aesni-gcm-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2013-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2013-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -73,6 +73,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/crypto/modes/asm/ghash-x86_64.pl b/crypto/modes/asm/ghash-x86_64.pl index 6ef8e555d0a25..181793c5523cc 100644 --- a/crypto/modes/asm/ghash-x86_64.pl +++ b/crypto/modes/asm/ghash-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2010-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2010-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -121,6 +121,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/crypto/pem/pvkfmt.c b/crypto/pem/pvkfmt.c index 9bfbb01e430aa..8b81f66e0e3b7 100644 --- a/crypto/pem/pvkfmt.c +++ b/crypto/pem/pvkfmt.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2005-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -893,13 +893,13 @@ static void *do_PVK_body_key(const unsigned char **in, (unsigned char *)psbuf, inlen, libctx, propq)) goto err; p += saltlen; - /* Copy BLOBHEADER across, decrypt rest */ - memcpy(enctmp, p, 8); - p += 8; if (keylen < 8) { ERR_raise(ERR_LIB_PEM, PEM_R_PVK_TOO_SHORT); goto err; } + /* Copy BLOBHEADER across, decrypt rest */ + memcpy(enctmp, p, 8); + p += 8; inlen = keylen - 8; q = enctmp + 8; if ((rc4 = EVP_CIPHER_fetch(libctx, "RC4", propq)) == NULL) diff --git a/crypto/pkcs12/p12_add.c b/crypto/pkcs12/p12_add.c index 4750974d60443..977aa8b658358 100644 --- a/crypto/pkcs12/p12_add.c +++ b/crypto/pkcs12/p12_add.c @@ -1,5 +1,5 @@ /* - * Copyright 1999-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1999-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -222,6 +222,6 @@ STACK_OF(PKCS7) *PKCS12_unpack_authsafes(const PKCS12 *p12) } return p7s; err: - sk_PKCS7_free(p7s); + sk_PKCS7_pop_free(p7s, PKCS7_free); return NULL; } diff --git a/crypto/pkcs12/p12_decr.c b/crypto/pkcs12/p12_decr.c index 0d415e755a183..31766989fc4a0 100644 --- a/crypto/pkcs12/p12_decr.c +++ b/crypto/pkcs12/p12_decr.c @@ -55,7 +55,8 @@ unsigned char *PKCS12_pbe_crypt_ex(const X509_ALGOR *algor, if ((EVP_CIPHER_get_flags(EVP_CIPHER_CTX_get0_cipher(ctx)) & EVP_CIPH_FLAG_CIPHER_WITH_MAC) != 0) { - if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_TLS1_AAD, 0, &mac_len) < 0) { + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_TLS1_AAD, 0, &mac_len) + <= 0) { ERR_raise(ERR_LIB_PKCS12, ERR_R_INTERNAL_ERROR); goto err; } @@ -70,7 +71,7 @@ unsigned char *PKCS12_pbe_crypt_ex(const X509_ALGOR *algor, inlen -= mac_len; if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, (int)mac_len, (unsigned char *)in + inlen) - < 0) { + <= 0) { ERR_raise(ERR_LIB_PKCS12, ERR_R_INTERNAL_ERROR); goto err; } diff --git a/crypto/pkcs12/p12_utl.c b/crypto/pkcs12/p12_utl.c index a6f3248c554c9..f252fd1a0061a 100644 --- a/crypto/pkcs12/p12_utl.c +++ b/crypto/pkcs12/p12_utl.c @@ -186,6 +186,8 @@ char *OPENSSL_uni2utf8(const unsigned char *uni, int unilen) /* string must contain an even number of bytes */ if (unilen & 1) return NULL; + if (unilen < 0) + return NULL; for (asclen = 0, i = 0; i < unilen;) { j = bmp_to_utf8(NULL, uni + i, unilen - i); diff --git a/crypto/pkcs7/pk7_doit.c b/crypto/pkcs7/pk7_doit.c index 1ec7895fc1976..aaf3c19aaeae0 100644 --- a/crypto/pkcs7/pk7_doit.c +++ b/crypto/pkcs7/pk7_doit.c @@ -1200,7 +1200,7 @@ PKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx) rsk = p7->d.signed_and_enveloped->recipientinfo; if (rsk == NULL) return NULL; - if (sk_PKCS7_RECIP_INFO_num(rsk) <= idx) + if (idx < 0 || sk_PKCS7_RECIP_INFO_num(rsk) <= idx) return NULL; ri = sk_PKCS7_RECIP_INFO_value(rsk, idx); return ri->issuer_and_serial; diff --git a/crypto/pkcs7/pk7_lib.c b/crypto/pkcs7/pk7_lib.c index 6cd0c3f025c5c..2fd753e873d09 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) @@ -727,6 +727,10 @@ int PKCS7_stream(unsigned char ***boundary, PKCS7 *p7) break; case NID_pkcs7_signedAndEnveloped: + if (p7->d.signed_and_enveloped == NULL || p7->d.signed_and_enveloped->enc_data == NULL) { + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_NO_CONTENT); + break; + } os = p7->d.signed_and_enveloped->enc_data->enc_data; if (os == NULL) { os = ASN1_OCTET_STRING_new(); @@ -735,6 +739,10 @@ int PKCS7_stream(unsigned char ***boundary, PKCS7 *p7) break; case NID_pkcs7_enveloped: + if (p7->d.enveloped == NULL || p7->d.enveloped->enc_data == NULL) { + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_NO_CONTENT); + break; + } os = p7->d.enveloped->enc_data->enc_data; if (os == NULL) { os = ASN1_OCTET_STRING_new(); @@ -747,7 +755,13 @@ int PKCS7_stream(unsigned char ***boundary, PKCS7 *p7) ERR_raise(ERR_LIB_PKCS7, PKCS7_R_NO_CONTENT); break; } - os = p7->d.sign->contents->d.data; + + if (!PKCS7_type_is_data(p7->d.sign->contents)) { + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_UNSUPPORTED_CONTENT_TYPE); + break; + } + + os = PKCS7_get_octet_string(p7->d.sign->contents); break; default: diff --git a/crypto/poly1305/asm/poly1305-x86.pl b/crypto/poly1305/asm/poly1305-x86.pl index c91d01fb3ba4e..6d367d858da72 100755 --- a/crypto/poly1305/asm/poly1305-x86.pl +++ b/crypto/poly1305/asm/poly1305-x86.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2016-2020 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2016-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -73,6 +73,13 @@ if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:clang|LLVM) version|based on LLVM) ([0-9]+\.[0-9]+)/) { $avx = ($2>=3.0) + ($2>3.0); } + + if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } + } } ######################################################################## diff --git a/crypto/poly1305/asm/poly1305-x86_64.pl b/crypto/poly1305/asm/poly1305-x86_64.pl index 305099ca0308a..081fe4117ad90 100755 --- a/crypto/poly1305/asm/poly1305-x86_64.pl +++ b/crypto/poly1305/asm/poly1305-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2016-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2016-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -95,6 +95,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c index f03bb2967c436..616e70792c9bb 100644 --- a/crypto/rand/rand_lib.c +++ b/crypto/rand/rand_lib.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -103,6 +103,13 @@ static RAND_GLOBAL *rand_get_global(OSSL_LIB_CTX *libctx) return ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_DRBG_INDEX); } + +#if defined(__has_feature) +# if __has_feature(address_sanitizer) +#include +# endif +#endif + #ifndef FIPS_MODULE #include #include @@ -674,7 +681,6 @@ static EVP_RAND_CTX *rand_new_drbg(OSSL_LIB_CTX *libctx, EVP_RAND_CTX *parent, EVP_RAND_CTX *ctx; OSSL_PARAM params[9], *p = params; const OSSL_PARAM *settables; - const char *prov_name; char *name, *cipher; int use_df = 1; @@ -686,7 +692,6 @@ static EVP_RAND_CTX *rand_new_drbg(OSSL_LIB_CTX *libctx, EVP_RAND_CTX *parent, ERR_raise(ERR_LIB_RAND, RAND_R_UNABLE_TO_FETCH_DRBG); return NULL; } - prov_name = ossl_provider_name(EVP_RAND_get0_provider(rand)); ctx = EVP_RAND_CTX_new(rand, parent); EVP_RAND_free(rand); if (ctx == NULL) { @@ -704,9 +709,6 @@ static EVP_RAND_CTX *rand_new_drbg(OSSL_LIB_CTX *libctx, EVP_RAND_CTX *parent, && OSSL_PARAM_locate_const(settables, OSSL_DRBG_PARAM_DIGEST)) *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_DIGEST, dgbl->rng_digest, 0); - if (prov_name != NULL) - *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PROV_PARAM_CORE_PROV_NAME, - (char *)prov_name, 0); if (dgbl->rng_propq != NULL) *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_PROPERTIES, dgbl->rng_propq, 0); @@ -862,13 +864,25 @@ static EVP_RAND_CTX *rand_get0_public(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl) if (CRYPTO_THREAD_get_local(&dgbl->private) == NULL && !ossl_init_thread_start(NULL, ctx, rand_delete_thread_state)) return NULL; +#if defined(__has_feature) +# if __has_feature(address_sanitizer) + __lsan_disable(); +# endif +#endif rand = rand_new_drbg(ctx, primary, SECONDARY_RESEED_INTERVAL, - SECONDARY_RESEED_TIME_INTERVAL); - CRYPTO_THREAD_set_local(&dgbl->public, rand); + SECONDARY_RESEED_TIME_INTERVAL); + if (!CRYPTO_THREAD_set_local(&dgbl->public, rand)) { + EVP_RAND_CTX_free(rand); + rand = NULL; + } +#if defined(__has_feature) +# if __has_feature(address_sanitizer) + __lsan_enable(); +# endif +#endif } return rand; } - /* * Get the public random generator. * Returns pointer to its EVP_RAND_CTX on success, NULL on failure. @@ -901,9 +915,22 @@ static EVP_RAND_CTX *rand_get0_private(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl) if (CRYPTO_THREAD_get_local(&dgbl->public) == NULL && !ossl_init_thread_start(NULL, ctx, rand_delete_thread_state)) return NULL; +#if defined(__has_feature) +# if __has_feature(address_sanitizer) + __lsan_disable(); +# endif +#endif rand = rand_new_drbg(ctx, primary, SECONDARY_RESEED_INTERVAL, - SECONDARY_RESEED_TIME_INTERVAL); - CRYPTO_THREAD_set_local(&dgbl->private, rand); + SECONDARY_RESEED_TIME_INTERVAL); + if (!CRYPTO_THREAD_set_local(&dgbl->private, rand)) { + EVP_RAND_CTX_free(rand); + rand = NULL; + } +#if defined(__has_feature) +# if __has_feature(address_sanitizer) + __lsan_enable(); +# endif +#endif } return rand; } diff --git a/crypto/rsa/rsa_gen.c b/crypto/rsa/rsa_gen.c index 554f9d349b857..777a485422dda 100644 --- a/crypto/rsa/rsa_gen.c +++ b/crypto/rsa/rsa_gen.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -636,7 +636,6 @@ static int rsa_keygen(OSSL_LIB_CTX *libctx, RSA *rsa, int bits, int primes, OSSL_SELF_TEST_get_callback(libctx, &stcb, &stcbarg); ok = rsa_keygen_pairwise_test(rsa, stcb, stcbarg); if (!ok) { - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); /* Clear intermediate results */ BN_clear_free(rsa->d); BN_clear_free(rsa->p); diff --git a/crypto/rsa/rsa_ossl.c b/crypto/rsa/rsa_ossl.c index 2fcf02a9ab05d..73a4b7c20a47e 100644 --- a/crypto/rsa/rsa_ossl.c +++ b/crypto/rsa/rsa_ossl.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -160,6 +160,14 @@ static int rsa_ossl_public_encrypt(int flen, const unsigned char *from, * See SP800-56Br2, section 7.1.1.1 * RSAEP: 1 < f < (n – 1). * (where f is the plaintext). + * + * This bound is somewhat overkill here. RSASVE.GENERATE (7.2.1.2) + * regenerates z until 1 < z < n-1, so on that path the plaintext is in + * range unconditionally. On the OAEP path the leading 0x00 octet of the + * encoding forces m < n-1 unconditionally, while m = 0 or 1 is only + * cryptographically negligible, not impossible. The check is kept to + * mirror the RSADP bound in rsa_ossl_private_decrypt() and to keep RSAEP + * faithful to 7.1.1 of the SP; nothing in the SP relies on it here. */ if (padding == RSA_NO_PADDING) { BIGNUM *nminus1 = BN_CTX_get(ctx); @@ -572,6 +580,12 @@ static int rsa_ossl_private_decrypt(int flen, const unsigned char *from, * See SP800-56Br2, section 7.1.2.1 * RSADP: 1 < f < (n – 1) * (where f is the ciphertext). + * + * Kept under FIPS_MODULE because SP 800-56B KTS-OAEP (section 9.2) also + * decrypts through RSADP and needs this bound in a FIPS build, and there + * is no KTS-OAEP-specific path to attach it to. The non-FIPS RSASVE path + * applies the same 1 < c < n-1 in rsasve_recover() + * (providers/implementations/kem/rsa_kem.c); keep the two in step. */ if (padding == RSA_NO_PADDING) { BIGNUM *nminus1 = BN_CTX_get(ctx); diff --git a/crypto/sha/asm/sha1-586.pl b/crypto/sha/asm/sha1-586.pl index 00350324a117d..81c3658b0adfb 100644 --- a/crypto/sha/asm/sha1-586.pl +++ b/crypto/sha/asm/sha1-586.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 1998-2020 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 1998-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -146,6 +146,9 @@ $ymm=1 if ($xmm && !$ymm && `$ENV{CC} -v 2>&1` =~ /((?:clang|LLVM) version|based on LLVM) ([0-9]+\.[0-9]+)/ && $2>=3.0); # first version supporting AVX +$ymm=1 if ($xmm && !$ymm && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` =~ /#define __clang_major__.([0-9]+)/ && + $1>=11); #icx started with clang 11 + $shaext=$xmm; ### set to zero if compiling for 1.0.1 &external_label("OPENSSL_ia32cap_P") if ($xmm); diff --git a/crypto/sha/asm/sha1-mb-x86_64.pl b/crypto/sha/asm/sha1-mb-x86_64.pl index d9d1630d16dbc..59042c90b2fec 100644 --- a/crypto/sha/asm/sha1-mb-x86_64.pl +++ b/crypto/sha/asm/sha1-mb-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2013-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2013-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -76,6 +76,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/crypto/sha/asm/sha1-x86_64.pl b/crypto/sha/asm/sha1-x86_64.pl index 30c545cf419a7..829fe16a82724 100755 --- a/crypto/sha/asm/sha1-x86_64.pl +++ b/crypto/sha/asm/sha1-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2006-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2006-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -124,6 +124,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + $shaext=1; ### set to zero if compiling for 1.0.1 $avx=1 if (!$shaext && $avx); diff --git a/crypto/sha/asm/sha256-586.pl b/crypto/sha/asm/sha256-586.pl index 8e19cd875e3f3..3983e55ff9e89 100644 --- a/crypto/sha/asm/sha256-586.pl +++ b/crypto/sha/asm/sha256-586.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2007-2020 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2007-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -99,6 +99,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if ($xmm && !$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + $shaext=$xmm; ### set to zero if compiling for 1.0.1 $unroll_after = 64*4; # If pre-evicted from L1P cache first spin of diff --git a/crypto/sha/asm/sha256-mb-x86_64.pl b/crypto/sha/asm/sha256-mb-x86_64.pl index 9398b7954a7f4..e53517d787f69 100644 --- a/crypto/sha/asm/sha256-mb-x86_64.pl +++ b/crypto/sha/asm/sha256-mb-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2013-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2013-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -77,6 +77,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"" or die "can't call $xlate: $!"; *STDOUT=*OUT; diff --git a/crypto/sha/asm/sha512-x86_64.pl b/crypto/sha/asm/sha512-x86_64.pl index b37058ae03faf..cbdd7df67561b 100755 --- a/crypto/sha/asm/sha512-x86_64.pl +++ b/crypto/sha/asm/sha512-x86_64.pl @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2005-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2005-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -140,6 +140,13 @@ $avx = ($2>=3.0) + ($2>3.0); } +if (!$avx && `$ENV{CC} -x c /dev/null -dM -E|grep __clang_major__` + =~ /#define __clang_major__.([0-9]+)/) { + if ($1) { + $avx = ($1>=11); #icx started with clang 11 + } +} + $shaext=1; ### set to zero if compiling for 1.0.1 $avx=1 if (!$shaext && $avx); diff --git a/crypto/sha/sha3.c b/crypto/sha/sha3.c index 21e1070beed27..1cdc8e983e8e8 100644 --- a/crypto/sha/sha3.c +++ b/crypto/sha/sha3.c @@ -13,6 +13,12 @@ #endif #include "internal/sha3.h" +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) +# include +# endif +#endif + void SHA3_squeeze(uint64_t A[5][5], unsigned char *out, size_t len, size_t r, int next); void ossl_sha3_reset(KECCAK1600_CTX *ctx) @@ -122,8 +128,21 @@ int ossl_sha3_final(KECCAK1600_CTX *ctx, unsigned char *out, size_t outlen) (void)SHA3_absorb(ctx->A, ctx->buf, bsz, bsz); +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) + __msan_unpoison(ctx->buf, bsz); +# endif +#endif + ctx->xof_state = XOF_STATE_FINAL; SHA3_squeeze(ctx->A, out, outlen, bsz, 0); + +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) + __msan_unpoison(out, outlen); +# endif +#endif + return 1; } @@ -191,6 +210,13 @@ int ossl_sha3_squeeze(KECCAK1600_CTX *ctx, unsigned char *out, size_t outlen) if (outlen >= bsz) { len = bsz * (outlen / bsz); SHA3_squeeze(ctx->A, out, len, bsz, next); + +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) + __msan_unpoison(out, len); +# endif +#endif + next = 1; out += len; outlen -= len; @@ -198,6 +224,13 @@ int ossl_sha3_squeeze(KECCAK1600_CTX *ctx, unsigned char *out, size_t outlen) if (outlen > 0) { /* Step 3. Squeeze one more block into a buffer */ SHA3_squeeze(ctx->A, ctx->buf, bsz, bsz, next); + +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) + __msan_unpoison(ctx->buf, bsz); +# endif +#endif + memcpy(out, ctx->buf, outlen); /* Step 4. Remember the leftover part of the squeezed block */ ctx->bufsz = bsz - outlen; diff --git a/crypto/sha/sha_riscv.c b/crypto/sha/sha_riscv.c index 61ceaa22a4bd8..dad1b1187671c 100644 --- a/crypto/sha/sha_riscv.c +++ b/crypto/sha/sha_riscv.c @@ -1,5 +1,5 @@ /* - * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2023-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -17,9 +17,9 @@ void sha256_block_data_order_zvkb_zvknha_or_zvknhb(void *ctx, const void *in, size_t num); void sha256_block_data_order_c(void *ctx, const void *in, size_t num); -void sha256_block_data_order(SHA256_CTX *ctx, const void *in, size_t num); +void sha256_block_data_order(void *ctx, const void *in, size_t num); -void sha256_block_data_order(SHA256_CTX *ctx, const void *in, size_t num) +void sha256_block_data_order(void *ctx, const void *in, size_t num) { if (RISCV_HAS_ZVKB() && (RISCV_HAS_ZVKNHA() || RISCV_HAS_ZVKNHB()) && riscv_vlen() >= 128) { sha256_block_data_order_zvkb_zvknha_or_zvknhb(ctx, in, num); @@ -30,9 +30,9 @@ void sha256_block_data_order(SHA256_CTX *ctx, const void *in, size_t num) void sha512_block_data_order_zvkb_zvknhb(void *ctx, const void *in, size_t num); void sha512_block_data_order_c(void *ctx, const void *in, size_t num); -void sha512_block_data_order(SHA512_CTX *ctx, const void *in, size_t num); +void sha512_block_data_order(void *ctx, const void *in, size_t num); -void sha512_block_data_order(SHA512_CTX *ctx, const void *in, size_t num) +void sha512_block_data_order(void *ctx, const void *in, size_t num) { if (RISCV_HAS_ZVKB_AND_ZVKNHB() && riscv_vlen() >= 128) { sha512_block_data_order_zvkb_zvknhb(ctx, in, num); diff --git a/crypto/slh_dsa/slh_dsa.c b/crypto/slh_dsa/slh_dsa.c index 41fc494048b4b..4cf75089920a0 100644 --- a/crypto/slh_dsa/slh_dsa.c +++ b/crypto/slh_dsa/slh_dsa.c @@ -8,6 +8,7 @@ */ #include #include +#include #include #include #include "slh_dsa_local.h" @@ -122,8 +123,13 @@ static int slh_sign_internal(SLH_DSA_HASH_CTX *hctx, err: if (!WPACKET_finish(wpkt)) ret = 0; + OPENSSL_cleanse(m_digest, sizeof(m_digest)); + OPENSSL_cleanse(pk_fors, sizeof(pk_fors)); if (ret) *sig_len = sig_len_expected; + else + /* Erase any partial signature output */ + OPENSSL_cleanse(sig, sig_len_expected); return ret; } @@ -148,6 +154,7 @@ static int slh_verify_internal(SLH_DSA_HASH_CTX *hctx, const uint8_t *msg, size_t msg_len, const uint8_t *sig, size_t sig_len) { + int ret = 0; const SLH_DSA_KEY *pub = hctx->key; SLH_HASH_FUNC_DECLARE(pub, hashf); SLH_ADRS_FUNC_DECLARE(pub, adrsf); @@ -185,7 +192,7 @@ static int slh_verify_internal(SLH_DSA_HASH_CTX *hctx, if (!hashf->H_MSG(hctx, r, pk_seed, pk_root, msg, msg_len, m_digest, sizeof(m_digest))) - return 0; + goto err; /* * Get md (the first md_len bytes of m_digest to use in @@ -195,16 +202,20 @@ static int slh_verify_internal(SLH_DSA_HASH_CTX *hctx, if (!PACKET_buf_init(m_digest_rpkt, m_digest, sizeof(m_digest)) || !PACKET_get_bytes(m_digest_rpkt, &md, md_len) || !get_tree_ids(m_digest_rpkt, params, &tree_id, &leaf_id)) - return 0; + goto err; adrsf->set_tree_address(adrs, tree_id); adrsf->set_type_and_clear(adrs, SLH_ADRS_TYPE_FORS_TREE); adrsf->set_keypair_address(adrs, leaf_id); - return ossl_slh_fors_pk_from_sig(hctx, sig_rpkt, md, pk_seed, adrs, - pk_fors, sizeof(pk_fors)) + ret = ossl_slh_fors_pk_from_sig(hctx, sig_rpkt, md, pk_seed, adrs, + pk_fors, sizeof(pk_fors)) && ossl_slh_ht_verify(hctx, pk_fors, sig_rpkt, pk_seed, tree_id, leaf_id, pk_root) && PACKET_remaining(sig_rpkt) == 0; +err: + OPENSSL_cleanse(m_digest, sizeof(m_digest)); + OPENSSL_cleanse(pk_fors, sizeof(pk_fors)); + return ret; } /** @@ -292,8 +303,13 @@ int ossl_slh_dsa_sign(SLH_DSA_HASH_CTX *slh_ctx, return 0; } ret = slh_sign_internal(slh_ctx, m, m_len, sig, siglen, sigsize, add_rand); - if (m != msg && m != m_tmp) - OPENSSL_free(m); + /* The encoded message may contain confidential message content */ + if (m != msg) { + if (m != m_tmp) + OPENSSL_clear_free(m, m_len); + else + OPENSSL_cleanse(m_tmp, sizeof(m_tmp)); + } return ret; } @@ -317,8 +333,13 @@ int ossl_slh_dsa_verify(SLH_DSA_HASH_CTX *slh_ctx, return 0; ret = slh_verify_internal(slh_ctx, m, m_len, sig, sig_len); - if (m != msg && m != m_tmp) - OPENSSL_free(m); + /* The encoded message may contain confidential message content */ + if (m != msg) { + if (m != m_tmp) + OPENSSL_clear_free(m, m_len); + else + OPENSSL_cleanse(m_tmp, sizeof(m_tmp)); + } return ret; } diff --git a/crypto/slh_dsa/slh_dsa_hash_ctx.c b/crypto/slh_dsa/slh_dsa_hash_ctx.c index 9dca01acf5ffc..513f7f7dafc15 100644 --- a/crypto/slh_dsa/slh_dsa_hash_ctx.c +++ b/crypto/slh_dsa/slh_dsa_hash_ctx.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -109,5 +109,6 @@ void ossl_slh_dsa_hash_ctx_free(SLH_DSA_HASH_CTX *ctx) if (ctx->md_big_ctx != ctx->md_ctx) EVP_MD_CTX_free(ctx->md_big_ctx); EVP_MAC_CTX_free(ctx->hmac_ctx); - OPENSSL_free(ctx); + /* Erases the |scratch| hash intermediates */ + OPENSSL_clear_free(ctx, sizeof(*ctx)); } diff --git a/crypto/slh_dsa/slh_dsa_key.c b/crypto/slh_dsa/slh_dsa_key.c index 6d778a39f46dc..9e980bf1bfb0b 100644 --- a/crypto/slh_dsa/slh_dsa_key.c +++ b/crypto/slh_dsa/slh_dsa_key.c @@ -313,6 +313,12 @@ int ossl_slh_dsa_key_fromdata(SLH_DSA_KEY *key, const OSSL_PARAM params[], key->pub = p; return 1; err: + /* + * A private key of unexpected length may have been copied into |priv| + * before |has_priv| was set, in which case the reset below would not + * erase it, so cleanse unconditionally. + */ + OPENSSL_cleanse(key->priv, sizeof(key->priv)); ossl_slh_dsa_key_reset(key); return 0; } diff --git a/crypto/slh_dsa/slh_dsa_local.h b/crypto/slh_dsa/slh_dsa_local.h index 57dfc1eb13011..d2eccdd08a9a3 100644 --- a/crypto/slh_dsa/slh_dsa_local.h +++ b/crypto/slh_dsa/slh_dsa_local.h @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -45,12 +45,24 @@ * NOTE: Any changes to this structure will need updating in * ossl_slh_dsa_hash_ctx_dup(). */ +/* A SHA-512 digest plus two |n| byte node values */ +#define SLH_DSA_HASH_SCRATCH_LEN (64 + 2 * SLH_MAX_N) + struct slh_dsa_hash_ctx_st { const SLH_DSA_KEY *key; /* This key is not owned by this object */ EVP_MD_CTX *md_ctx; /* Either SHAKE OR SHA-256 */ EVP_MD_CTX *md_big_ctx; /* Either SHA-512 or points to |md_ctx| for SHA-256*/ EVP_MAC_CTX *hmac_ctx; /* required by SHA algorithms for PRFmsg() */ int hmac_digest_used; /* Used for lazy init of hmac_ctx digest */ + /* + * Working storage for the SHA2 hash function intermediates, used in + * place of local stack copies, so that potentially sensitive + * intermediate data lives in one place and is erased when this object + * is freed (FIPS 205 section 3.1). The SHAKE hash functions write + * their output directly to the caller's buffer and need no scratch. + * Not used concurrently. + */ + uint8_t scratch[SLH_DSA_HASH_SCRATCH_LEN]; }; __owur int ossl_slh_wots_pk_gen(SLH_DSA_HASH_CTX *ctx, const uint8_t *sk_seed, diff --git a/crypto/slh_dsa/slh_fors.c b/crypto/slh_dsa/slh_fors.c index 78587589db428..7c8854cc9b386 100644 --- a/crypto/slh_dsa/slh_fors.c +++ b/crypto/slh_dsa/slh_fors.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -17,8 +17,8 @@ /* a = 6, 8, 9, 12 or 14 - There are (2^a) merkle trees */ #define SLH_MAX_A 9 -#define SLH_MAX_K_TIMES_A (SLH_MAX_A * SLH_MAX_K) -#define SLH_MAX_ROOTS (SLH_MAX_K_TIMES_A * SLH_MAX_N) +/* The FORS public key is computed from the roots of k Merkle trees */ +#define SLH_MAX_ROOTS (SLH_MAX_K * SLH_MAX_N) static void slh_base_2b(const uint8_t *in, uint32_t b, uint32_t *out, size_t out_len); @@ -87,25 +87,25 @@ static int slh_fors_node(SLH_DSA_HASH_CTX *ctx, const uint8_t *sk_seed, if (height == 0) { /* Gets here for leaf nodes */ - if (!slh_fors_sk_gen(ctx, sk_seed, pk_seed, adrs, node_id, sk, sizeof(sk))) - return 0; - adrsf->set_tree_height(adrs, 0); - adrsf->set_tree_index(adrs, node_id); - ret = key->hash_func->F(ctx, pk_seed, adrs, sk, n, node, node_len); + if (slh_fors_sk_gen(ctx, sk_seed, pk_seed, adrs, node_id, sk, sizeof(sk))) { + adrsf->set_tree_height(adrs, 0); + adrsf->set_tree_index(adrs, node_id); + ret = key->hash_func->F(ctx, pk_seed, adrs, sk, n, node, node_len); + } OPENSSL_cleanse(sk, n); - return ret; } else { - if (!slh_fors_node(ctx, sk_seed, pk_seed, adrs, 2 * node_id, height - 1, - lnode, sizeof(rnode)) - || !slh_fors_node(ctx, sk_seed, pk_seed, adrs, 2 * node_id + 1, - height - 1, rnode, sizeof(rnode))) - return 0; - adrsf->set_tree_height(adrs, height); - adrsf->set_tree_index(adrs, node_id); - if (!key->hash_func->H(ctx, pk_seed, adrs, lnode, rnode, node, node_len)) - return 0; + if (slh_fors_node(ctx, sk_seed, pk_seed, adrs, 2 * node_id, height - 1, + lnode, sizeof(lnode)) + && slh_fors_node(ctx, sk_seed, pk_seed, adrs, 2 * node_id + 1, + height - 1, rnode, sizeof(rnode))) { + adrsf->set_tree_height(adrs, height); + adrsf->set_tree_index(adrs, node_id); + ret = key->hash_func->H(ctx, pk_seed, adrs, lnode, rnode, node, node_len); + } + OPENSSL_cleanse(lnode, sizeof(lnode)); + OPENSSL_cleanse(rnode, sizeof(rnode)); } - return 1; + return ret; } /** @@ -132,6 +132,7 @@ int ossl_slh_fors_sign(SLH_DSA_HASH_CTX *ctx, const uint8_t *md, const uint8_t *sk_seed, const uint8_t *pk_seed, uint8_t *adrs, WPACKET *sig_wpkt) { + int ret = 0; const SLH_DSA_KEY *key = ctx->key; uint32_t tree_id, layer, s, tree_offset; uint32_t ids[SLH_MAX_K]; @@ -165,7 +166,7 @@ int ossl_slh_fors_sign(SLH_DSA_HASH_CTX *ctx, const uint8_t *md, if (!slh_fors_sk_gen(ctx, sk_seed, pk_seed, adrs, node_id + tree_id_times_two_power_a, out, sizeof(out)) || !WPACKET_memcpy(sig_wpkt, out, n)) - return 0; + goto err; /* * Traverse from the bottom of the tree (layer = 0) @@ -178,15 +179,18 @@ int ossl_slh_fors_sign(SLH_DSA_HASH_CTX *ctx, const uint8_t *md, s = node_id ^ 1; /* XOR gets the index of the other child in a binary tree */ if (!slh_fors_node(ctx, sk_seed, pk_seed, adrs, s + tree_offset, layer, out, sizeof(out))) - return 0; + goto err; node_id >>= 1; /* Get the parent node id */ tree_offset >>= 1; /* Each layer up has half as many nodes */ if (!WPACKET_memcpy(sig_wpkt, out, n)) - return 0; + goto err; } tree_id_times_two_power_a += two_power_a; } - return 1; + ret = 1; +err: + OPENSSL_cleanse(out, sizeof(out)); + return ret; } /** @@ -288,6 +292,8 @@ int ossl_slh_fors_pk_from_sig(SLH_DSA_HASH_CTX *ctx, PACKET *fors_sig_rpkt, err: if (!WPACKET_finish(wroot_pkt)) ret = 0; + /* At most one |n| byte root per tree was written */ + OPENSSL_cleanse(roots, k * n); return ret; } diff --git a/crypto/slh_dsa/slh_hash.c b/crypto/slh_dsa/slh_hash.c index bd112f1cb0dba..b0023c955c3e8 100644 --- a/crypto/slh_dsa/slh_hash.c +++ b/crypto/slh_dsa/slh_hash.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -92,12 +92,15 @@ slh_prf_msg_shake(SLH_DSA_HASH_CTX *ctx, const uint8_t *sk_prf, const uint8_t *opt_rand, const uint8_t *msg, size_t msg_len, WPACKET *pkt) { + int ret; unsigned char out[SLH_MAX_N]; const SLH_DSA_PARAMS *params = ctx->key->params; size_t n = params->n; - return xof_digest_3(ctx->md_ctx, sk_prf, n, opt_rand, n, msg, msg_len, out, n) + ret = xof_digest_3(ctx->md_ctx, sk_prf, n, opt_rand, n, msg, msg_len, out, n) && WPACKET_memcpy(pkt, out, n); + OPENSSL_cleanse(out, sizeof(out)); + return ret; } static int @@ -151,6 +154,7 @@ slh_hmsg_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *r, const uint8_t *pk_seed, const uint8_t *pk_root, const uint8_t *msg, size_t msg_len, uint8_t *out, size_t out_len) { + int ret; const SLH_DSA_PARAMS *params = hctx->key->params; size_t m = params->m; size_t n = params->n; @@ -163,9 +167,11 @@ slh_hmsg_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *r, const uint8_t *pk_seed, memcpy(seed, r, n); memcpy(seed + n, pk_seed, n); - return digest_4(hctx->md_big_ctx, r, n, pk_seed, n, pk_root, n, msg, msg_len, - seed + 2 * n) + ret = digest_4(hctx->md_big_ctx, r, n, pk_seed, n, pk_root, n, msg, msg_len, + seed + 2 * n) && (PKCS1_MGF1(out, m, seed, seed_len, hctx->key->md_big) == 0); + OPENSSL_cleanse(seed, sizeof(seed)); + return ret; } static int @@ -205,16 +211,23 @@ slh_prf_msg_sha2(SLH_DSA_HASH_CTX *hctx, && EVP_MAC_update(mctx, msg, msg_len) == 1 && EVP_MAC_final(mctx, mac, NULL, sizeof(mac)) == 1 && WPACKET_memcpy(pkt, mac, n); /* Truncate output to n bytes */ + OPENSSL_cleanse(mac, sizeof(mac)); return ret; } +/* + * The |digest| scratch storage in the hash context is used in place of a + * local stack buffer, and is erased when the hash context is freed + * (FIPS 205 section 3.1). On the PRF path it holds a derived chain secret. + */ static ossl_inline int -do_hash(EVP_MD_CTX *ctx, size_t n, const uint8_t *pk_seed, const uint8_t *adrs, +do_hash(SLH_DSA_HASH_CTX *hctx, EVP_MD_CTX *ctx, size_t n, + const uint8_t *pk_seed, const uint8_t *adrs, const uint8_t *m, size_t m_len, size_t b, uint8_t *out, size_t out_len) { int ret; uint8_t zeros[128] = { 0 }; - uint8_t digest[MAX_DIGEST_SIZE]; + uint8_t *digest = hctx->scratch; ret = digest_4(ctx, pk_seed, n, zeros, b - n, adrs, SLH_ADRSC_SIZE, m, m_len, digest); @@ -230,7 +243,7 @@ slh_prf_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *pk_seed, { size_t n = hctx->key->params->n; - return do_hash(hctx->md_ctx, n, pk_seed, adrs, sk_seed, n, + return do_hash(hctx, hctx->md_ctx, n, pk_seed, adrs, sk_seed, n, OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND1, out, out_len); } @@ -238,21 +251,22 @@ static int slh_f_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *pk_seed, const uint8_t *adrs, const uint8_t *m1, size_t m1_len, uint8_t *out, size_t out_len) { - return do_hash(hctx->md_ctx, hctx->key->params->n, pk_seed, adrs, m1, m1_len, - OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND1, out, out_len); + return do_hash(hctx, hctx->md_ctx, hctx->key->params->n, pk_seed, adrs, + m1, m1_len, OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND1, out, out_len); } static int slh_h_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *pk_seed, const uint8_t *adrs, const uint8_t *m1, const uint8_t *m2, uint8_t *out, size_t out_len) { - uint8_t m[SLH_MAX_N * 2]; + /* The concatenated children go in the scratch after the digest */ + uint8_t *m = hctx->scratch + MAX_DIGEST_SIZE; const SLH_DSA_PARAMS *prms = hctx->key->params; size_t n = prms->n; memcpy(m, m1, n); memcpy(m + n, m2, n); - return do_hash(hctx->md_big_ctx, n, pk_seed, adrs, m, 2 * n, + return do_hash(hctx, hctx->md_big_ctx, n, pk_seed, adrs, m, 2 * n, prms->sha2_h_and_t_bound, out, out_len); } @@ -262,7 +276,7 @@ slh_t_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *pk_seed, const uint8_t *adrs, { const SLH_DSA_PARAMS *prms = hctx->key->params; - return do_hash(hctx->md_big_ctx, prms->n, pk_seed, adrs, ml, ml_len, + return do_hash(hctx, hctx->md_big_ctx, prms->n, pk_seed, adrs, ml, ml_len, prms->sha2_h_and_t_bound, out, out_len); } diff --git a/crypto/slh_dsa/slh_hypertree.c b/crypto/slh_dsa/slh_hypertree.c index bc352bf5bc3a2..e1e2901ce5f32 100644 --- a/crypto/slh_dsa/slh_hypertree.c +++ b/crypto/slh_dsa/slh_hypertree.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -8,6 +8,7 @@ */ #include +#include #include "slh_dsa_local.h" #include "slh_dsa_key.h" @@ -33,6 +34,7 @@ int ossl_slh_ht_sign(SLH_DSA_HASH_CTX *ctx, const uint8_t *pk_seed, uint64_t tree_id, uint32_t leaf_id, WPACKET *sig_wpkt) { + int ret = 0; const SLH_DSA_KEY *key = ctx->key; SLH_ADRS_FUNC_DECLARE(key, adrsf); SLH_ADRS_DECLARE(adrs); @@ -70,7 +72,7 @@ int ossl_slh_ht_sign(SLH_DSA_HASH_CTX *ctx, psig = WPACKET_get_curr(sig_wpkt); if (!ossl_slh_xmss_sign(ctx, root, sk_seed, leaf_id, pk_seed, adrs, sig_wpkt)) - return 0; + goto err; /* * On the last loop it skips getting the public key since it is not needed * to calculate another signature. If this was called it should equal @@ -79,15 +81,18 @@ int ossl_slh_ht_sign(SLH_DSA_HASH_CTX *ctx, if (layer < d - 1) { if (!PACKET_buf_init(xmss_sig_rpkt, psig, WPACKET_get_curr(sig_wpkt) - psig)) - return 0; + goto err; if (!ossl_slh_xmss_pk_from_sig(ctx, leaf_id, xmss_sig_rpkt, root, pk_seed, adrs, root, sizeof(root))) - return 0; + goto err; leaf_id = tree_id & mask; tree_id >>= hm; } } - return 1; + ret = 1; +err: + OPENSSL_cleanse(root, sizeof(root)); + return ret; } /** @@ -108,6 +113,7 @@ int ossl_slh_ht_verify(SLH_DSA_HASH_CTX *ctx, const uint8_t *msg, PACKET *sig_pk const uint8_t *pk_seed, uint64_t tree_id, uint32_t leaf_id, const uint8_t *pk_root) { + int ret = 0; const SLH_DSA_KEY *key = ctx->key; SLH_ADRS_FUNC_DECLARE(key, adrsf); SLH_ADRS_DECLARE(adrs); @@ -127,9 +133,12 @@ int ossl_slh_ht_verify(SLH_DSA_HASH_CTX *ctx, const uint8_t *msg, PACKET *sig_pk adrsf->set_tree_address(adrs, tree_id); if (!ossl_slh_xmss_pk_from_sig(ctx, leaf_id, sig_pkt, node, pk_seed, adrs, node, sizeof(node))) - return 0; + goto err; leaf_id = tree_id & mask; tree_id >>= tree_height; } - return (memcmp(node, pk_root, n) == 0); + ret = (memcmp(node, pk_root, n) == 0); +err: + OPENSSL_cleanse(node, sizeof(node)); + return ret; } diff --git a/crypto/slh_dsa/slh_wots.c b/crypto/slh_dsa/slh_wots.c index ea278fcd84121..79f3bca8747d4 100644 --- a/crypto/slh_dsa/slh_wots.c +++ b/crypto/slh_dsa/slh_wots.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -244,6 +244,8 @@ int ossl_slh_wots_sign(SLH_DSA_HASH_CTX *ctx, const uint8_t *msg, } ret = 1; err: + OPENSSL_cleanse(sk, sizeof(sk)); + OPENSSL_cleanse(msg_and_csum_nibbles, sizeof(msg_and_csum_nibbles)); return ret; } @@ -311,5 +313,7 @@ int ossl_slh_wots_pk_from_sig(SLH_DSA_HASH_CTX *ctx, err: if (!WPACKET_finish(tmp_pkt)) ret = 0; + OPENSSL_cleanse(tmp, sizeof(tmp)); + OPENSSL_cleanse(msg_and_csum_nibbles, sizeof(msg_and_csum_nibbles)); return ret; } diff --git a/crypto/slh_dsa/slh_xmss.c b/crypto/slh_dsa/slh_xmss.c index dae036c6a2189..a53a6c1e99117 100644 --- a/crypto/slh_dsa/slh_xmss.c +++ b/crypto/slh_dsa/slh_xmss.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -8,6 +8,7 @@ */ #include +#include #include "slh_dsa_local.h" #include "slh_dsa_key.h" @@ -39,29 +40,31 @@ int ossl_slh_xmss_node(SLH_DSA_HASH_CTX *ctx, const uint8_t *sk_seed, { const SLH_DSA_KEY *key = ctx->key; SLH_ADRS_FUNC_DECLARE(key, adrsf); + int ret = 0; if (h == 0) { /* For leaf nodes generate the public key */ adrsf->set_type_and_clear(adrs, SLH_ADRS_TYPE_WOTS_HASH); adrsf->set_keypair_address(adrs, node_id); - if (!ossl_slh_wots_pk_gen(ctx, sk_seed, pk_seed, adrs, + if (ossl_slh_wots_pk_gen(ctx, sk_seed, pk_seed, adrs, pk_out, pk_out_len)) - return 0; + ret = 1; } else { uint8_t lnode[SLH_MAX_N], rnode[SLH_MAX_N]; - if (!ossl_slh_xmss_node(ctx, sk_seed, 2 * node_id, h - 1, pk_seed, adrs, + if (ossl_slh_xmss_node(ctx, sk_seed, 2 * node_id, h - 1, pk_seed, adrs, lnode, sizeof(lnode)) - || !ossl_slh_xmss_node(ctx, sk_seed, 2 * node_id + 1, h - 1, - pk_seed, adrs, rnode, sizeof(rnode))) - return 0; - adrsf->set_type_and_clear(adrs, SLH_ADRS_TYPE_TREE); - adrsf->set_tree_height(adrs, h); - adrsf->set_tree_index(adrs, node_id); - if (!key->hash_func->H(ctx, pk_seed, adrs, lnode, rnode, pk_out, pk_out_len)) - return 0; + && ossl_slh_xmss_node(ctx, sk_seed, 2 * node_id + 1, h - 1, + pk_seed, adrs, rnode, sizeof(rnode))) { + adrsf->set_type_and_clear(adrs, SLH_ADRS_TYPE_TREE); + adrsf->set_tree_height(adrs, h); + adrsf->set_tree_index(adrs, node_id); + ret = key->hash_func->H(ctx, pk_seed, adrs, lnode, rnode, pk_out, pk_out_len); + } + OPENSSL_cleanse(lnode, sizeof(lnode)); + OPENSSL_cleanse(rnode, sizeof(rnode)); } - return 1; + return ret; } /** diff --git a/crypto/threads_win.c b/crypto/threads_win.c index 2c0e27ce06eb6..158aa2ea91c98 100644 --- a/crypto/threads_win.c +++ b/crypto/threads_win.c @@ -535,6 +535,20 @@ int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void)) result = InterlockedCompareExchange(lock, ONCE_ININIT, ONCE_UNINITED); if (result == ONCE_UNINITED) { init(); + /* + * On weakly ordered systems, it may happen that the write to *lock + * below completes prior to some writes in whatever the init() + * callback routine above may do. In this case, other threads + * entering here may see unsynchronized data in whatever the init + * routine initializes, leading to erroneous behavior. + * + * We should use InitOnceExecuteOnce here to implement this, but + * doing so requires that we modify the definition of the + * CRYPTO_ONCE type, which is an ABI breakage. So instead + * just insert a memory barrier here to ensure that any pending + * writes are flushed to memory prior to setting ONCE_DONE below + */ + MemoryBarrier(); *lock = ONCE_DONE; return 1; } diff --git a/crypto/x509/by_dir.c b/crypto/x509/by_dir.c index e8b7ca152b2c2..df92e1d1d5894 100644 --- a/crypto/x509/by_dir.c +++ b/crypto/x509/by_dir.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -228,7 +228,7 @@ static int get_cert_by_subject_ex(X509_LOOKUP *xl, X509_LOOKUP_TYPE type, X509 st_x509; X509_CRL crl; } data; - int ok = 0; + int res, ok = 0; int i, j, k; unsigned long h; BUF_MEM *b = NULL; @@ -320,25 +320,35 @@ static int get_cert_by_subject_ex(X509_LOOKUP *xl, X509_LOOKUP_TYPE type, } #ifndef OPENSSL_NO_POSIX_IO #ifdef _WIN32 +#define lstat _stat #define stat _stat #endif { struct stat st; - if (stat(b->data, &st) < 0) - break; - } + if (lstat(b->data, &st) < 0) + break; /* file does not exist, not even a symlink */ +#ifndef _WIN32 + if (stat(b->data, &st) < 0) { + k++; + continue; /* symlink is broken: following it went wrong */ + } #endif - /* found one. */ - if (type == X509_LU_X509) { - if ((X509_load_cert_file_ex(xl, b->data, ent->dir_type, libctx, - propq)) - == 0) - break; - } else if (type == X509_LU_CRL) { - if ((X509_load_crl_file(xl, b->data, ent->dir_type)) == 0) - break; } +#endif + res = 0; + ERR_set_mark(); + if (type == X509_LU_X509) + res = X509_load_cert_file_ex(xl, b->data, ent->dir_type, libctx, propq); + else if (type == X509_LU_CRL) + res = X509_load_crl_file(xl, b->data, ent->dir_type); /* else case will caught higher up */ + ERR_pop_to_mark(); + /* unless OPENSSL_NO_POSIX_IO, gracefully skip found file if cert/CRL fails to load. */ +#ifndef OPENSSL_NO_POSIX_IO + res = 1; +#endif + if (res == 0) + break; k++; } diff --git a/crypto/x509/pcy_cache.c b/crypto/x509/pcy_cache.c index d1ee35377bda3..b3b6a3da1a9a2 100644 --- a/crypto/x509/pcy_cache.c +++ b/crypto/x509/pcy_cache.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2004-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -134,6 +134,7 @@ static int policy_cache_new(X509 *x) /* If not absent some problem with extension */ if (i != -1) goto bad_cache; + POLICY_CONSTRAINTS_free(ext_pcons); return 1; } @@ -141,8 +142,10 @@ static int policy_cache_new(X509 *x) /* NB: ext_cpols freed by policy_cache_set_policies */ - if (i <= 0) + if (i <= 0) { + POLICY_CONSTRAINTS_free(ext_pcons); return i; + } ext_pmaps = X509_get_ext_d2i(x, NID_policy_mappings, &i, NULL); diff --git a/crypto/x509/v3_akid.c b/crypto/x509/v3_akid.c index 08c751b77cfde..9721518ecc0d5 100644 --- a/crypto/x509/v3_akid.c +++ b/crypto/x509/v3_akid.c @@ -1,5 +1,5 @@ /* - * Copyright 1999-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1999-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -173,7 +173,9 @@ static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method, i = X509_get_ext_by_NID(issuer_cert, NID_subject_key_identifier, -1); if (i >= 0 && (ext = X509_get_ext(issuer_cert, i)) != NULL && !(same_issuer && !ss)) { - ikeyid = X509V3_EXT_d2i(ext); + if ((ikeyid = X509V3_EXT_d2i(ext)) == NULL) + goto err; + if (ASN1_STRING_length(ikeyid) == 0) /* indicating "none" */ { ASN1_OCTET_STRING_free(ikeyid); ikeyid = NULL; diff --git a/crypto/x509/v3_ncons.c b/crypto/x509/v3_ncons.c index 2d4b23685b0e0..a0b97bb7081e2 100644 --- a/crypto/x509/v3_ncons.c +++ b/crypto/x509/v3_ncons.c @@ -1,5 +1,5 @@ /* - * Copyright 2003-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2003-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -613,6 +613,12 @@ static int nc_dn(const X509_NAME *nm, const X509_NAME *base) return X509_V_ERR_OUT_OF_MEM; if (base->canon_enclen > nm->canon_enclen) return X509_V_ERR_PERMITTED_VIOLATION; + /* + * An empty base Name has no canonical encoding (canon_enc == NULL) and is + * a prefix of every Name, so it matches unconditionally. + */ + if (base->canon_enclen == 0) + return X509_V_OK; if (memcmp(base->canon_enc, nm->canon_enc, base->canon_enclen)) return X509_V_ERR_PERMITTED_VIOLATION; return X509_V_OK; @@ -789,6 +795,7 @@ static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base) if (scheme == NULL || *scheme == '\0') { ERR_raise_data(ERR_LIB_X509V3, X509_V_ERR_UNSUPPORTED_NAME_SYNTAX, "x509: missing scheme in URI: %s\n", uri_copy); + OPENSSL_free(scheme); OPENSSL_free(uri_copy); ret = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; goto end; diff --git a/crypto/x509/x509_err.c b/crypto/x509/x509_err.c index 3d6e8768f8bf9..7ed046fef4934 100644 --- a/crypto/x509/x509_err.c +++ b/crypto/x509/x509_err.c @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -26,6 +26,8 @@ static const ERR_STRING_DATA X509_str_reasons[] = { { ERR_PACK(ERR_LIB_X509, 0, X509_R_CERT_ALREADY_IN_HASH_TABLE), "cert already in hash table" }, { ERR_PACK(ERR_LIB_X509, 0, X509_R_CRL_ALREADY_DELTA), "crl already delta" }, + { ERR_PACK(ERR_LIB_X509, 0, X509_R_CRL_SIGNATURE_ALGORITHM_MISMATCH), + "crl signature algorithm mismatch" }, { ERR_PACK(ERR_LIB_X509, 0, X509_R_CRL_VERIFY_FAILURE), "crl verify failure" }, { ERR_PACK(ERR_LIB_X509, 0, X509_R_DUPLICATE_ATTRIBUTE), diff --git a/crypto/x509/x509_lu.c b/crypto/x509/x509_lu.c index af8035bce8448..00fe2bbe04155 100644 --- a/crypto/x509/x509_lu.c +++ b/crypto/x509/x509_lu.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -590,7 +590,12 @@ static X509_OBJECT *x509_object_dup(const X509_OBJECT *obj) ret->type = obj->type; ret->data = obj->data; - X509_OBJECT_up_ref_count(ret); + + if (!X509_OBJECT_up_ref_count(ret)) { + OPENSSL_free(ret); + return NULL; + } + return ret; } diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 0994c32ca5336..b3df8c9b71e7e 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -1364,6 +1364,12 @@ static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer, /* Invalid IDP cannot be processed */ if ((crl->idp_flags & IDP_INVALID) != 0) return 0; + /* + * Reject delta CRLs unconditionally here. They are considered by + * get_delta_sk() after a base CRL is selected. + */ + if (crl->base_crl_number != NULL) + return 0; /* Reason codes or indirect CRLs need extended CRL support */ if ((ctx->param->flags & X509_V_FLAG_EXTENDED_CRL_SUPPORT) == 0) { if (crl->idp_flags & (IDP_INDIRECT | IDP_REASONS)) @@ -1373,9 +1379,6 @@ static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer, if ((crl->idp_reasons & ~tmp_reasons) == 0) return 0; } - /* Don't process deltas at this stage */ - else if (crl->base_crl_number != NULL) - return 0; /* If issuer name doesn't match certificate need indirect CRL */ if (X509_NAME_cmp(X509_get_issuer_name(x), X509_CRL_get_issuer(crl)) != 0) { if ((crl->idp_flags & IDP_INDIRECT) == 0) diff --git a/crypto/x509/x_crl.c b/crypto/x509/x_crl.c index 4a93abb8ca3f9..1b498ee6b57d0 100644 --- a/crypto/x509/x_crl.c +++ b/crypto/x509/x_crl.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -404,6 +404,10 @@ int X509_CRL_get0_by_cert(X509_CRL *crl, X509_REVOKED **ret, X509 *x) static int def_crl_verify(X509_CRL *crl, EVP_PKEY *r) { + if (X509_ALGOR_cmp(&crl->sig_alg, &crl->crl.sig_alg) != 0) { + ERR_raise(ERR_LIB_X509, X509_R_CRL_SIGNATURE_ALGORITHM_MISMATCH); + return 0; + } return ASN1_item_verify_ex(ASN1_ITEM_rptr(X509_CRL_INFO), &crl->sig_alg, &crl->signature, &crl->crl, NULL, r, crl->libctx, crl->propq); diff --git a/crypto/x509/x_pubkey.c b/crypto/x509/x_pubkey.c index 03f532ab9cb37..8e0ee3a2197ff 100644 --- a/crypto/x509/x_pubkey.c +++ b/crypto/x509/x_pubkey.c @@ -224,7 +224,7 @@ static int x509_pubkey_ex_d2i_ex(ASN1_VALUE **pval, * bytes. */ ERR_clear_last_mark(); - ERR_raise(ERR_LIB_ASN1, EVP_R_DECODE_ERROR); + ERR_raise(ERR_LIB_ASN1, ASN1_R_DECODE_ERROR); goto end; } } diff --git a/doc/build.info b/doc/build.info index eb4492ba9c753..ce2125a4d3f3a 100644 --- a/doc/build.info +++ b/doc/build.info @@ -1523,6 +1523,10 @@ DEPEND[html/man3/MDC2_Init.html]=man3/MDC2_Init.pod GENERATE[html/man3/MDC2_Init.html]=man3/MDC2_Init.pod DEPEND[man/man3/MDC2_Init.3]=man3/MDC2_Init.pod GENERATE[man/man3/MDC2_Init.3]=man3/MDC2_Init.pod +DEPEND[html/man3/NAME_CONSTRAINTS_check.html]=man3/NAME_CONSTRAINTS_check.pod +GENERATE[html/man3/NAME_CONSTRAINTS_check.html]=man3/NAME_CONSTRAINTS_check.pod +DEPEND[man/man3/NAME_CONSTRAINTS_check.3]=man3/NAME_CONSTRAINTS_check.pod +GENERATE[man/man3/NAME_CONSTRAINTS_check.3]=man3/NAME_CONSTRAINTS_check.pod DEPEND[html/man3/NCONF_new_ex.html]=man3/NCONF_new_ex.pod GENERATE[html/man3/NCONF_new_ex.html]=man3/NCONF_new_ex.pod DEPEND[man/man3/NCONF_new_ex.3]=man3/NCONF_new_ex.pod @@ -1571,6 +1575,10 @@ DEPEND[html/man3/OPENSSL_LH_stats.html]=man3/OPENSSL_LH_stats.pod GENERATE[html/man3/OPENSSL_LH_stats.html]=man3/OPENSSL_LH_stats.pod DEPEND[man/man3/OPENSSL_LH_stats.3]=man3/OPENSSL_LH_stats.pod GENERATE[man/man3/OPENSSL_LH_stats.3]=man3/OPENSSL_LH_stats.pod +DEPEND[html/man3/OPENSSL_armcap.html]=man3/OPENSSL_armcap.pod +GENERATE[html/man3/OPENSSL_armcap.html]=man3/OPENSSL_armcap.pod +DEPEND[man/man3/OPENSSL_armcap.3]=man3/OPENSSL_armcap.pod +GENERATE[man/man3/OPENSSL_armcap.3]=man3/OPENSSL_armcap.pod DEPEND[html/man3/OPENSSL_config.html]=man3/OPENSSL_config.pod GENERATE[html/man3/OPENSSL_config.html]=man3/OPENSSL_config.pod DEPEND[man/man3/OPENSSL_config.3]=man3/OPENSSL_config.pod @@ -3446,6 +3454,7 @@ html/man3/GENERAL_NAME.html \ html/man3/HMAC.html \ html/man3/MD5.html \ html/man3/MDC2_Init.html \ +html/man3/NAME_CONSTRAINTS_check.html \ html/man3/NCONF_new_ex.html \ html/man3/OBJ_nid2obj.html \ html/man3/OCSP_REQUEST_new.html \ @@ -3458,6 +3467,7 @@ html/man3/OPENSSL_Applink.html \ html/man3/OPENSSL_FILE.html \ html/man3/OPENSSL_LH_COMPFUNC.html \ html/man3/OPENSSL_LH_stats.html \ +html/man3/OPENSSL_armcap.html \ html/man3/OPENSSL_config.html \ html/man3/OPENSSL_fork_prepare.html \ html/man3/OPENSSL_gmtime.html \ @@ -4123,6 +4133,7 @@ man/man3/GENERAL_NAME.3 \ man/man3/HMAC.3 \ man/man3/MD5.3 \ man/man3/MDC2_Init.3 \ +man/man3/NAME_CONSTRAINTS_check.3 \ man/man3/NCONF_new_ex.3 \ man/man3/OBJ_nid2obj.3 \ man/man3/OCSP_REQUEST_new.3 \ @@ -4135,6 +4146,7 @@ man/man3/OPENSSL_Applink.3 \ man/man3/OPENSSL_FILE.3 \ man/man3/OPENSSL_LH_COMPFUNC.3 \ man/man3/OPENSSL_LH_stats.3 \ +man/man3/OPENSSL_armcap.3 \ man/man3/OPENSSL_config.3 \ man/man3/OPENSSL_fork_prepare.3 \ man/man3/OPENSSL_gmtime.3 \ diff --git a/doc/internal/man3/DEFINE_LIST_OF.pod b/doc/internal/man3/DEFINE_LIST_OF.pod index d886defc43fb9..95693cf0b2a90 100644 --- a/doc/internal/man3/DEFINE_LIST_OF.pod +++ b/doc/internal/man3/DEFINE_LIST_OF.pod @@ -8,7 +8,7 @@ ossl_list_TYPE_is_empty, ossl_list_TYPE_num, ossl_list_TYPE_head, ossl_list_TYPE_tail, ossl_list_TYPE_next, ossl_list_TYPE_prev, ossl_list_TYPE_remove, ossl_list_TYPE_insert_head, ossl_list_TYPE_insert_tail, -ossl_list_TYPE_insert_before, ossl_list_TYPE_after +ossl_list_TYPE_insert_before, ossl_list_TYPE_after, ossl_list_TYPE_join - doubly linked list =head1 SYNOPSIS @@ -38,6 +38,7 @@ ossl_list_TYPE_insert_before, ossl_list_TYPE_after void ossl_list_TYPE_insert_before(OSSL_LIST(name) *list, type *existing, type *elem); void ossl_list_TYPE_insert_after(OSSL_LIST(name) *list, type *existing, type *elem); + void ossl_list_TYPE_join(OSSL_LIST(name) *lh, OSSL_LIST(name) *lt); =head1 DESCRIPTION @@ -90,6 +91,10 @@ B_insert_after>() inserts the element I, which must not be in the list, into the I immediately after the I element. +B_join<()> joins list B with list B. +List B is appended to list B. The list B becomes empty, +as all its members are part of B after the function returns. + =head1 RETURN VALUES B_is_empty>() returns nonzero if the list is empty and zero @@ -124,11 +129,13 @@ the specified element in the list. =head1 HISTORY -The functions described here were all added in OpenSSL 3.2. +ossl_list_TYPE_join() was added in OpenSSL 4.1, 4.0.2, 3.6.4, 3.5.8, and 3.4.7. + +The rest of the functions described here was added in OpenSSL 3.2. =head1 COPYRIGHT -Copyright 2022 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved. Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy diff --git a/doc/man1/openssl-pkeyutl.pod.in b/doc/man1/openssl-pkeyutl.pod.in index 46b62952590e2..11744c5181e8f 100644 --- a/doc/man1/openssl-pkeyutl.pod.in +++ b/doc/man1/openssl-pkeyutl.pod.in @@ -379,7 +379,7 @@ explicitly set in PSS mode then the signing digest is used. =item BI Sets the digest used for the OAEP hash function. If not explicitly set then -SHA256 is used. +SHA1 is used. =item BI @@ -683,8 +683,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.pod b/doc/man1/openssl.pod index 635b52aeb1208..1963715f38a05 100644 --- a/doc/man1/openssl.pod +++ b/doc/man1/openssl.pod @@ -722,8 +722,8 @@ For information about specific commands, see L, L, and L. For information about querying or specifying CPU architecture flags, see -L, L, L, -and L. +L, L, L, +L and L. =head1 SEE ALSO @@ -801,7 +801,7 @@ that program with no arguments is now equivalent to C. =head1 COPYRIGHT -Copyright 2000-2025 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2000-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/ASN1_INTEGER_get_int64.pod b/doc/man3/ASN1_INTEGER_get_int64.pod index 4ba6c4c0d71f4..69fff46460f25 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 @@ -123,7 +123,7 @@ were added in OpenSSL 1.1.0. =head1 COPYRIGHT -Copyright 2015-2020 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2015-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/ASN1_aux_cb.pod b/doc/man3/ASN1_aux_cb.pod index 9963ea1350252..49299492ad492 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 @@ -274,7 +314,7 @@ B operation types were added in OpenSSL 3.0. =head1 COPYRIGHT -Copyright 2021-2025 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/ASN1_item_d2i_bio.pod b/doc/man3/ASN1_item_d2i_bio.pod index f8e4678367ef8..9b3f389a23fd1 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 87d6fb34e7a29..9b8c98801ff82 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 @@ -260,7 +260,7 @@ L, L, L, L =head1 COPYRIGHT -Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved. Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy diff --git a/doc/man3/BIO_s_file.pod b/doc/man3/BIO_s_file.pod index 5dcd4bbbcaeda..3b867aa6efa86 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. @@ -158,7 +157,7 @@ L, L =head1 COPYRIGHT -Copyright 2000-2020 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2000-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/BN_generate_prime.pod b/doc/man3/BN_generate_prime.pod index 6b8d1de19cd83..876c26816ccb6 100644 --- a/doc/man3/BN_generate_prime.pod +++ b/doc/man3/BN_generate_prime.pod @@ -201,6 +201,8 @@ BN_is_prime_fasttest() and BN_check_prime return 0 if the number is composite, -1 on error. BN_generate_prime() returns the prime number on success, B otherwise. +Please note that the B BIGNUM is freed on failure and must not be +used or freed by the caller in such case. BN_GENCB_new returns a pointer to a BN_GENCB structure on success, or B otherwise. @@ -246,7 +248,7 @@ BN_check_prime() was added in OpenSSL 3.0. =head1 COPYRIGHT -Copyright 2000-2025 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2000-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/CMS_EncryptedData_decrypt.pod b/doc/man3/CMS_EncryptedData_decrypt.pod index 80bbdcc95f35b..c2b00b0584f0c 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 @@ -58,7 +58,7 @@ CMS_EnvelopedData_decrypt() was added in OpenSSL 3.2. =head1 COPYRIGHT -Copyright 2020 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/doc/man3/NAME_CONSTRAINTS_check.pod b/doc/man3/NAME_CONSTRAINTS_check.pod new file mode 100644 index 0000000000000..3dfe39ea29420 --- /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 (RFC 8398) is additionally matched against +B subtrees. Any other general-name type, including +B, B, B, and other B +forms, yields B. + +For each name considered, the function evaluates two conditions: + +=over 4 + +=item * + +If I contains at least one B of the same general-name +type as the name, the name must match at least one of those permitted +subtrees. If I contains no permitted subtrees of that type, no +permitted-subtrees test is imposed on names of that type. + +=item * + +The name must not match any B of the same general-name +type in I. + +=back + +The function returns at the first violation encountered; it does not +collect or report multiple failures. + +For B entries, matching follows the byte/label algorithm of +RFC 5280 section 4.2.1.10, which RFC 5280 mandates when no +protocol-specific matching rules apply. Because this match is performed +without awareness of any specific higher-level protocol, additional +matching rules defined by later or more specific protocols must be +applied independently of this function to the certificate chain. + +NAME_CONSTRAINTS_check() performs only the constraint match for a single +certificate against a single constraint set. It does B perform the +chain-wide enforcement of RFC 5280 section 6.1.4(g)-(j): callers wishing to +enforce name constraints across an entire certification path must walk the +chain themselves and apply each ancestor's constraint set to certificates +lower in the chain, observing the usual exceptions (for example, +self-issued intermediate certificates are exempt from constraints imposed +by certificates above them, except when they are the leaf of the chain). +For full RFC 5280 name-constraint enforcement integrated with chain +validation, applications should use L, which performs +this internally. + +NAME_CONSTRAINTS_check() enforces an implementation limit on the product +of the certificate's name count and the constraint set's subtree count, to +prevent computationally expensive matching on pathological input. If that +limit is exceeded the function returns B without +performing any matching. The current limit is 2**20 (1,048,576) on the +product of the name count (subject DN entries plus B +entries) and the subtree count (B plus +B). + +=head1 RETURN VALUES + +NAME_CONSTRAINTS_check() returns B if every name considered +satisfies the constraints. Otherwise it returns one of the following +B codes: + +=over 4 + +=item B + +A name of a type for which I contains at least one permitted subtree +failed to match any of those subtrees. + +=item B + +A name matched an excluded subtree. + +=item B + +A subtree in I specified a B other than 0 or a B at +all. RFC 5280 requires that these B fields not be used, +and a constraint set that uses them cannot be processed. + +=item B + +A general-name type for which matching is not implemented was encountered. +The list of supported types is given in the DESCRIPTION above. + +=item B + +A name in the certificate is encoded in a way that cannot be matched (for +example, an B attribute in the subject that is not encoded +as an B). + +=item B + +The product of the certificate's name count and the constraint set's +subtree count exceeded the implementation limit; no matching was +performed. + +=back + +Other B codes may be returned by deeper name-matching +helpers (for example, codes arising from individual general-name type +comparisons). Callers should treat the return value as the authoritative +success/failure signal and treat any value other than B as a +failure, rather than enumerating the specific codes above. + +=head1 NOTES + +NAME_CONSTRAINTS_check() does not match the certificate's commonName +against B name constraints; that check is provided by a separate +function, B(). The commonName-as-DNS-identity +practice is a legacy concern: modern certificates assert DNS identities +through B entries in the subject alternative name extension, +which NAME_CONSTRAINTS_check() already covers. NAME_CONSTRAINTS_check_CN() +is required only for older certificates that express a DNS identity +through their commonName instead of, or in addition to, the SAN; for +certificates conforming to modern profiles a call to NAME_CONSTRAINTS_check() +alone is generally sufficient. + +=head1 BUGS + +RFC 9525's wildcard semantics apply only to presented-identifier +matching for TLS service identity, and explicitly call out they are not +valid for any other purpose; they do not define wildcard handling +for name-constraint matching. NAME_CONSTRAINTS_check() therefore +follows RFC 5280's requirements for when this is undefined, and treats +the B<*> character in a B as a literal label component, per +the RFC 5280 algorithm, which is often contrary to caller expectation. + +Even if specified in the future, due to the "fallback implementation" +nature of matching wildcards in SAN B entries specified by +RFC 5280, name constraint behaviour in the presence of wildcards +should not be strictly relied upon across implementations and +protocols. This matters most for the use of B +constraints, which should not be relied upon to reliably constrain +signing certificates for a PKI in a security dependent manner unless +the consumers of these certificates are themselves known to be +constrained by other means to only use implementations that provide +different semantics, or the PKI can be constrained by other means to +ensure that wildcards are never issued from such signing +certificates. + +=head1 SEE ALSO + +L, +L + +=head1 HISTORY + +NAME_CONSTRAINTS_check() was added in OpenSSL 1.0.0. + +NAME_CONSTRAINTS_check_CN() was added in OpenSSL 1.1.0. + +=head1 COPYRIGHT + +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 +L. + +=cut diff --git a/doc/man3/OPENSSL_armcap.pod b/doc/man3/OPENSSL_armcap.pod new file mode 100644 index 0000000000000..78c8d3fbedc9d --- /dev/null +++ b/doc/man3/OPENSSL_armcap.pod @@ -0,0 +1,246 @@ +=pod + +=head1 NAME + +OPENSSL_armcap - the Arm processor capabilities vector + +=head1 SYNOPSIS + + env OPENSSL_armcap=... + +=head1 DESCRIPTION + +libcrypto supports a range of Arm instruction set extensions. These +extensions are represented by bits in the Arm processor capabilities vector. +When libcrypto initializes, it stores the results returned by Arm CPU +capabilities detection logic in the Arm processor capabilities vector. The +CPU capabilities detection methods are OS-dependent, using a combination of +information gathered by the kernel during boot, and probe functions that attempt +to execute instructions and trap illegal instruction signals with a signal +handler. + +To override the set of extensions available to an application, set the +B environment variable before starting the application. The +environment variable is assigned a numerical value that denotes the bits in +the Arm processor capabilities vector. The arm_arch.h header file defines +the possible values, which are explained in detail below. + +Multiple extensions are enabled by logically OR-ing the values that represent +the desired extensions. + +B: Attempting to executing an instruction from an extension that the +target CPU does not support will result in an illegal instruction exception +(SIGILL). + +Please note that not all possible values in the Arm processor capabilities +vector are actual processor capabilities. Some values represent OpenSSL +performance preferences for some implementations which only make sense on +specific CPUs. + +The following extensions are defined: + +=over 4 + +=item 0x0001 + +Name: B + +Meaning: Indicates support for the Armv7 Neon SIMD extensions on the processor. + +Effect: Enables various Armv7 Neon SIMD implementations. + +=item 0x00002 + +Name: B + +Meaning: Indicates support for the Armv7 system timer on the processor. + +Effect: This is used as a seed for some random number generators. + +=item 0x00004 + +Name: B + +Meaning: Indicates support for the Armv8.0 AES hardware-acceleration extensions +on the processor. + +Effect: Enables various Armv8.0 AES hardware-accelerated implementations. + +=item 0x00008 + +Name: B + +Meaning: Indicates support for the Armv8.0 SHA1 hardware-acceleration extensions +on the processor. + +Effect: Enables various Armv8.0 SHA1 hardware-accelerated implementations. + +=item 0x00010 + +Name: B + +Meaning: Indicates support for the Armv8.0 SHA256 hardware-acceleration +extensions on the processor. + +Effect: Enables various Armv8.0 SHA256 hardware-accelerated implementations. + +=item 0x00020 + +Name: B + +Meaning: Indicates support for the Armv8.0 polynomial multiplication +hardware-acceleration extensions on the processor. + +Effect: Used to hardware-accelerate polynomial multiplication, for example in +AES-GCM. + +=item 0x00040 + +Name: B + +Meaning: Indicates support for the Armv8.2 SHA512 hardware-acceleration +extensions on the processor. + +Effect: Enables Armv8.2 SHA512 hardware-accelerated implementations. + +=item 0x00080 + +Name: B + +Meaning: Indicates support for the Armv8.0 hardware identification extensions on +the processor. + +Effect: Allows implementations to change their behaviour, dependant on the +processor platform in order to achieve better performance. + +=item 0x00100 + +Name: B + +Meaning: Indicates support for the Armv8.5 hardware random number generation +extensions on the processor. + +Effect: Enables hardware random number generation on supported AArch64 +processors. + +=item 0x00200 + +Name: B + +Meaning: Indicates support for the Armv8.2 SM3 hardware-acceleration extensions +on the processor. + +Effect: Enables Armv8.2 SM3 hardware-accelerated implementations. + +=item 0x00400 + +Name: B + +Meaning: Indicates support for the Armv8.2 SM4 hardware-acceleration extensions +on the processor. + +Effect: Enables Armv8.2 SM4 hardware-accelerated implementations. + +=item 0x00800 + +Name: B + +Meaning: Indicates support for the Armv8.2 SHA3 hardware-acceleration extensions +on the processor. + +Effect: Enables SHA3 hardware-accelerated implementations (see also +ARMV8_HAVE_SHA3_AND_WORTH_USING). + +=item 0x01000 + +Name: B + +Meaning: Indicates support for the Arm EOR3 instruction, which is a part of the +Armv8.2 SHA3 extensions, and enables 8x Loop unrolling in the AES-CTR +implementation. + +Effect: Enables the 8x loop unrolling utilising EOR3 implementation of AES-CTR +on platforms that support the SHA3 extension and have enough vector bandwidth. + +=item 0x02000 + +Name: B + +Meaning: Indicates support for the Armv8.2 SVE hardware extension on the +processor. + +Effect: Enables various Armv8.2 SVE implementations. + +=item 0x04000 + +Name: B + +Meaning: Indicates support for the Armv9.0 SVE2 hardware extension on the +processor. + +Effect: Enables various Armv9.0 SVE2 implementations. + +=item 0x08000 + +Name: B + +Meaning: Indicates support for the Armv8.2 SHA3 hardware-acceleration extensions +on the processor, and that the hardware bandwidth is sufficient for it to be +worth using. + +Effect: On certain Apple platforms, although the SHA3 extension is supported, it +is actually slower than other implementations. This flag disables the +hardware-accelerated SHA3 implementations on these platforms. + +=item 0x10000 + +Name: B + +Meaning: Indicates support for the Arm EOR3 instruction, which is a part of the +Armv8.2 SHA3 extensions, and enables 12x loop unrolling in the AES-CTR +implementation. + +Effect: Enables the 12x loop unrolling utilising EOR3 implementation of AES-CTR +on platforms that support the extension and have enough vector bandwidth. + +=item 0x20000 + +Name: B + +Meaning: Indicates support for the Armv9.0 SVE2 hardware extension, and enables +its use in the Poly1305 implementation. + +Effect: Enables the Armv9.0 SVE2 Poly1305 implementation if SVE2 is enabled, the +vector length is greater than 128 bits, and the vector length is a power of 2. + +=back + +=head1 RETURN VALUES + +Not available. + +=head1 EXAMPLES + +Check currently detected capabilities: + + $ openssl info -cpusettings + OPENSSL_armcap=0x987d + +The detected capabilities in the above example indicate that ARMV7_NEON, +ARMV8_AES, ARMV8_SHA1, ARMV8_SHA256, ARMV8_PMULL, ARMV8_SHA512, ARMV8_SHA3, +ARMV8_UNROLL8_EOR3, and ARMV8_HAVE_SHA3_AND_WORTH_USING are enabled. + +Disable all instruction set extensions: + + export OPENSSL_armcap=0x00 + +=head1 COPYRIGHT + +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 +L. + +=cut diff --git a/doc/man3/OPENSSL_init_crypto.pod b/doc/man3/OPENSSL_init_crypto.pod index 1363693c779b7..d36aef69521d1 100644 --- a/doc/man3/OPENSSL_init_crypto.pod +++ b/doc/man3/OPENSSL_init_crypto.pod @@ -273,6 +273,9 @@ with those threads. The application should either call OPENSSL_thread_stop() on each thread prior to the dlclose() call, or alternatively the original dlopen() call should use the RTLD_NODELETE flag (where available on the platform). +Thread cleanup does not unwind an OpenSSL function interrupted by cancellation +or thread exit; see L. + =head1 RETURN VALUES The functions OPENSSL_init_crypto, OPENSSL_atexit() and @@ -280,7 +283,7 @@ OPENSSL_INIT_set_config_appname() return 1 on success or 0 on error. =head1 SEE ALSO -L +L, L =head1 HISTORY @@ -290,7 +293,7 @@ and OPENSSL_INIT_free() functions were added in OpenSSL 1.1.0. =head1 COPYRIGHT -Copyright 2016-2024 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2016-2026 The OpenSSL Project Authors. All Rights Reserved. Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy diff --git a/doc/man3/SSL_CTX_set1_curves.pod b/doc/man3/SSL_CTX_set1_curves.pod index 6fedad01b4d0a..1a9231e6e2c98 100755 --- a/doc/man3/SSL_CTX_set1_curves.pod +++ b/doc/man3/SSL_CTX_set1_curves.pod @@ -113,7 +113,7 @@ levels, and can specify which predicted key shares should be sent by a client. Group tuples are used by OpenSSL TLS servers to decide whether to request a stronger keyshare than those predicted by sending a Hello Retry Request (B) even if some of the predicted groups are supported. -OpenSSL clients ignore tuple boundaries, and pay attenion only to the overall +OpenSSL clients ignore tuple boundaries, and pay attention only to the overall order of I elements and which groups are selected as predicted keyshares as described below. @@ -379,6 +379,10 @@ SSL_set1_groups_list() was added in OpenSSL 3.3. Support for B was added in OpenSSL 3.5. +OpenSSL 3.5 also introduced support for group tuples, the C<*> keyshare +prediction prefix, the C tuple separator, the C pseudo-group, +and the C<-> prefix. + OpenSSL 3.5 also introduces support for three I ECDH PQ key exchange TLS groups: B, B and B. diff --git a/doc/man3/SSL_CTX_set_msg_callback.pod b/doc/man3/SSL_CTX_set_msg_callback.pod index f046c77b535b9..f2bdfd7eace55 100644 --- a/doc/man3/SSL_CTX_set_msg_callback.pod +++ b/doc/man3/SSL_CTX_set_msg_callback.pod @@ -92,7 +92,7 @@ The SSL_trace() function can be used as a pre-written callback in a call to SSL_CTX_set_msg_callback() or SSL_set_msg_callback(). It requires a BIO to be set as the callback argument via SSL_CTX_set_msg_callback_arg() or SSL_set_msg_callback_arg(). Setting this callback will cause human readable -diagostic tracing information about an SSL/TLS/QUIC connection to be written to +diagnostic tracing information about an SSL/TLS/QUIC connection to be written to the BIO. =head1 NOTES @@ -181,7 +181,7 @@ the pseudo content type B for DTLS records. =head1 COPYRIGHT -Copyright 2001-2023 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2001-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/SSL_CTX_set_verify.pod b/doc/man3/SSL_CTX_set_verify.pod index 58774796cd921..7ab3575cc5a72 100644 --- a/doc/man3/SSL_CTX_set_verify.pod +++ b/doc/man3/SSL_CTX_set_verify.pod @@ -74,7 +74,9 @@ SSL_CTX_set_client_cert_cb() if no certificate is provided at initialization. SSL_verify_client_post_handshake() causes a CertificateRequest message to be sent by a server on the given B connection. The SSL_VERIFY_PEER flag must -be set; the SSL_VERIFY_POST_HANDSHAKE flag is optional. +be set; the SSL_VERIFY_POST_HANDSHAKE flag is optional. The +SSL_VERIFY_FAIL_IF_NO_PEER_CERT flag is also applicable and has the same +effect as with the client authentication during the handshake. =head1 NOTES @@ -369,7 +371,7 @@ and SSL_set_post_handshake_auth() functions were added in OpenSSL 1.1.1. =head1 COPYRIGHT -Copyright 2000-2024 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2000-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/SSL_get_value_uint.pod b/doc/man3/SSL_get_value_uint.pod index df0ee6176b3c9..907662dc76068 100644 --- a/doc/man3/SSL_get_value_uint.pod +++ b/doc/man3/SSL_get_value_uint.pod @@ -12,6 +12,7 @@ SSL_VALUE_CLASS_FEATURE_REQUEST, SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, SSL_VALUE_CLASS_FEATURE_NEGOTIATED, SSL_VALUE_QUIC_STREAM_BIDI_LOCAL_AVAIL, SSL_VALUE_QUIC_STREAM_BIDI_REMOTE_AVAIL, SSL_VALUE_QUIC_STREAM_UNI_LOCAL_AVAIL, SSL_VALUE_QUIC_STREAM_UNI_REMOTE_AVAIL, SSL_VALUE_QUIC_IDLE_TIMEOUT, +SSL_VALUE_QUIC_MAX_PENDING_CONNS, SSL_VALUE_EVENT_HANDLING_MODE, SSL_VALUE_EVENT_HANDLING_MODE_INHERIT, SSL_VALUE_EVENT_HANDLING_MODE_EXPLICIT, @@ -45,6 +46,7 @@ manage negotiable features and configuration values for an SSL object #define SSL_VALUE_QUIC_STREAM_UNI_LOCAL_AVAIL #define SSL_VALUE_QUIC_STREAM_UNI_REMOTE_AVAIL #define SSL_VALUE_QUIC_IDLE_TIMEOUT + #define SSL_VALUE_QUIC_MAX_PENDING_CONNS #define SSL_VALUE_EVENT_HANDLING_MODE #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT @@ -168,6 +170,16 @@ changed. This release of OpenSSL uses a default value of 30 seconds. This default value may change between releases of OpenSSL. +=item B (listener object) + +Generic value, sets the limit on channels (connection objects) which a QUIC server can +insert into the list of pending connections. A pending connection is a connection +which the local application needs to accept (L) in order to retrieve +an SSL connection object. The connection is removed from the pending queue by a call +to L. The default limit for pending connections is 256. An INITIAL +QUIC packet, which is received by a QUIC server with a full pending connections +queue, is silently discarded. Setting the value to zero disables the limit. + =item B (connection object) Generic read-only statistical value. The number of bidirectional, @@ -335,15 +347,19 @@ time. L, L, L, L, L, L, -L, L +L, L, +L =head1 HISTORY -These functions were added in OpenSSL 3.3. +The value SSL_VALUE_QUIC_MAX_PENDING_CONNS has been added in OpenSSL 4.1 +and ported to older releases 4.0.2, 3.6.4 and 3.5.8. + +The remaining functions and values described here were all added in OpenSSL 3.3. =head1 COPYRIGHT -Copyright 2002-2024 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2002-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/SSL_new.pod b/doc/man3/SSL_new.pod index d01996fba1432..25926d492a440 100644 --- a/doc/man3/SSL_new.pod +++ b/doc/man3/SSL_new.pod @@ -94,6 +94,14 @@ SSL_set0_client_CA_list() or similar functions =item any client certificate types configured via SSL_set1_client_certificate_types +=item type of server certificate set via L. + +=item type of client certificate set via L. + +=item certificate transparency validation callback set via L, + +=item OCSP validation set via L. + =back SSL_dup() is not supported on QUIC SSL objects and returns NULL if called on @@ -127,7 +135,7 @@ L =head1 COPYRIGHT -Copyright 2000-2023 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2000-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/SSL_poll.pod b/doc/man3/SSL_poll.pod index 6047bd6750f8f..be8f8a4f786c3 100644 --- a/doc/man3/SSL_poll.pod +++ b/doc/man3/SSL_poll.pod @@ -337,6 +337,20 @@ stream SSL objects, are supported. This limitation may be revised in a future release of OpenSSL. +=head1 THREAD CANCELLATION + +A finite I limits ordinary waiting by SSL_poll(), but does not make the +call safe against thread cancellation; see L. + +Cancellation can prevent SSL_poll() from removing internal wait state. Because +an I array can span multiple QUIC domains, one interrupted call can leave +stale state in several domains and cause later calls on those domains, including +SSL_poll() with a finite timeout, to block indefinitely. + +For cooperative cancellation, use a finite timeout and check a cancellation +condition between calls; see L +for the nonblocking alternative. + =head1 RETURN VALUES SSL_poll() returns 1 on success and 0 on failure. @@ -406,7 +420,9 @@ I. =head1 SEE ALSO L, L, -L, L +L, L, +L, L, +L =head1 HISTORY @@ -421,7 +437,7 @@ event types were not present. =head1 COPYRIGHT -Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy diff --git a/doc/man3/X509_get_default_cert_file.pod b/doc/man3/X509_get_default_cert_file.pod index 1e65b227006d4..982c8954d89a2 100644 --- a/doc/man3/X509_get_default_cert_file.pod +++ b/doc/man3/X509_get_default_cert_file.pod @@ -24,7 +24,7 @@ the default path when it is asked to load trusted CA certificates from a file and no other path is specified. If the file exists, CA certificates are loaded from the file. -The X509_get_default_cert_dir() function returns a default delimeter-separated +The X509_get_default_cert_dir() function returns a default delimiter-separated list of paths to a directories containing trusted CA certificates named in the hashed format. OpenSSL will use this as the default list of paths when it is asked to load trusted CA certificates from a directory and no other path is @@ -76,7 +76,7 @@ L =head1 COPYRIGHT -Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved. Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy diff --git a/doc/man3/X509_verify_cert.pod b/doc/man3/X509_verify_cert.pod index 360e974812737..bcd4c05399a30 100644 --- a/doc/man3/X509_verify_cert.pod +++ b/doc/man3/X509_verify_cert.pod @@ -2,99 +2,477 @@ =head1 NAME -X509_build_chain, X509_verify_cert, -X509_STORE_CTX_verify - build and verify X509 certificate chain +X509_STORE_CTX_verify, +X509_build_chain - build and verify X509 certificate chain =head1 SYNOPSIS #include + int X509_verify_cert(X509_STORE_CTX *ctx); + int X509_STORE_CTX_verify(X509_STORE_CTX *ctx); STACK_OF(X509) *X509_build_chain(X509 *target, STACK_OF(X509) *certs, X509_STORE *store, int with_self_signed, OSSL_LIB_CTX *libctx, const char *propq); - int X509_verify_cert(X509_STORE_CTX *ctx); - int X509_STORE_CTX_verify(X509_STORE_CTX *ctx); =head1 DESCRIPTION -X509_build_chain() builds a certificate chain starting from I -using the optional list of intermediate CA certificates I. -If I is NULL it builds the chain as far down as possible, ignoring errors. -Else the chain must reach a trust anchor contained in I. -It internally uses a B structure associated with the library -context I and property query string I, both of which may be NULL. -In case there is more than one possibility for the chain, only one is taken. - -On success it returns a pointer to a new stack of (up_ref'ed) certificates -starting with I and followed by all available intermediate certificates. -A self-signed trust anchor is included only if I is the trust anchor -of I is 1. -If a non-NULL stack is returned the caller is responsible for freeing it. - -The X509_verify_cert() function attempts to discover and validate a -certificate chain based on parameters in I. -The verification context, of type B, can be constructed -using L and L. -It usually includes a target certificate to be verified, -a set of certificates serving as trust anchors, -a list of non-trusted certificates that may be helpful for chain construction, -flags such as X509_V_FLAG_X509_STRICT, and various other optional components -such as a callback function that allows customizing the verification outcome. -A complete description of the certificate verification process is contained in -the L manual page. - -Applications rarely call this function directly but it is used by -OpenSSL internally for certificate validation, in both the S/MIME and -SSL/TLS code. - -A negative return value from X509_verify_cert() can occur if it is invoked -incorrectly, such as with no certificate set in I, or when it is called -twice in succession without reinitialising I for the second call. -A negative return value can also happen due to internal resource problems -or because an internal inconsistency has been detected. -Applications must interpret any return value <= 0 as an error. - -The X509_STORE_CTX_verify() behaves like X509_verify_cert() except that its -target certificate is the first element of the list of untrusted certificates -in I unless a target certificate is set explicitly. - -When the verification target is a raw public key, rather than a certificate, -both functions validate the target raw public key. -In that case the number of possible checks is significantly reduced. -The raw public key can be authenticated only via DANE TLSA records, either -locally synthesised or obtained by the application from DNS. -Raw public key DANE TLSA records may be added via L or -L. +=head2 X509_verify_cert and X509_STORE_CTX_verify + +X509_verify_cert() attempts to build and validate a certificate chain for the +target certificate set in I. The verification context, of type +B, must first be constructed with L and +initialised with L. It carries the target certificate, +the trust store, an optional stack of untrusted certificates that may assist +chain construction, verification parameters such as flags and a verification +purpose, an optional verification callback, and, after a call, the verification +outcome. + +A B can be used for only one verification. Calling +X509_verify_cert() a second time on the same context without reinitialising it +fails with a negative return value, and L +subsequently returns B. + +When the target is a certificate, the function performs the following steps in +order. The first step that fails aborts verification, except where a +verification callback explicitly waives the error (see +L below): + +=over 4 + +=item 1. + +B Starting from the target certificate, the verification +machinery seeks an issuer for the certificate currently at the top of the +chain, drawing candidates from I's untrusted stack and from the trust +store. By default the search is untrusted-first: the untrusted stack is +examined before the trust store. Setting B on +I's verification parameters reverses this. When an untrusted-first +search fails to reach a trust anchor and B is not +set, the search is retried with progressively shorter untrusted prefixes in +an attempt to find an alternative trusted path. The chain length is bounded +by the configured depth limit (see L); +exceeding it yields B. If more than one +chain is possible, only one is taken. + +Failure to build a chain to a trust anchor yields an error such as +B, +B, +B, +B, or +B. + +=item 2. + +B per RFC 5280, including basic constraints, +key usage and the verification purpose set via +L. + +=item 3. + +B against the configured authentication level, covering +issuer key sizes (B) and signature algorithm +strength (B). The leaf key is checked separately +before chain construction begins (B). + +=item 4. + +B against any hostnames, email addresses or IP addresses +configured on the verification parameters +(L and related). + +=item 5. + +B via CRLs and, when configured, OCSP. The set of checks +performed is controlled by flags such as B and +B. + +=item 6. + +B on every certificate in the chain, +walking from the trust anchor down to the target. The signature on the +chain's terminating certificate is not verified: trust is taken from its +presence in the trust store rather than from its signature. This applies +both to a conventional self-signed trust anchor and, when +B is in effect, to a non-self-signed +intermediate promoted to anchor status. B +requests that the self-signature on a self-signed terminator be verified; +it has no effect when the terminator is a non-self-signed certificate. +Validity periods are checked on every certificate, including the +terminator. + +=item 7. + +B per RFC 5280 section 4.2.1.10; see +L for details of the matching primitive and +the general-name types it covers. + +=item 8. + +B of AS-number and IP-address delegation +extensions, performed by default unless OpenSSL was built with +B. + +=item 9. + +B, performed only when +B is set. + +=back + +Several B values modify the behaviour of these checks; +representative ones are named at the relevant step above, but the list there +is not exhaustive. The complete set of verification flags, the effect each +one has, and the functions used to query and modify them are documented in +L. + +Applications rarely call X509_verify_cert() directly. It is invoked internally +by OpenSSL during S/MIME and CMS verification and during the TLS handshake. + +X509_STORE_CTX_verify() behaves identically to X509_verify_cert() except for +the selection of the target certificate: if no target has been set on I +(see L) and the untrusted stack is nonempty, the +first certificate in the untrusted stack is adopted as the target before +verification begins. If a target was set explicitly, X509_STORE_CTX_verify() +uses it and does not consult the untrusted stack for this purpose. + +=head2 Raw public key targets + +When the verification target is a raw public key rather than a certificate +(set via L), both functions validate the raw public +key instead of a certificate chain. The set of possible checks is significantly +reduced: there are no extensions, names, CRLs or signatures to verify. The raw +public key can be authenticated only via DANE TLSA records, either locally +synthesised or obtained by the application from DNS. Raw public key DANE TLSA +records may be added via L or L. + +=head2 X509_build_chain + +X509_build_chain() builds a certificate chain starting from I, using +the same chain-construction algorithm as X509_verify_cert() (see +L above). It internally uses a +B structure associated with the library context I +and property query string I, both of which may be NULL. The role of +I depends on I: + +=over 4 + +=item * + +If I is non-NULL, I is treated as an optional list of +B intermediate certificates that may help complete the chain, and +the chain must reach a trust anchor contained in I. If no chain to a +trust anchor can be built, the function fails and returns NULL. + +=item * + +If I is NULL, I is installed as the B stack for the +internal context (see L). In this mode +the function builds the chain as far as it can but does not require it to +reach an anchor: if chain construction fails partway, the partial chain built +so far is still returned. + +=back + +Because the internal B is allocated and freed inside +X509_build_chain(), search-policy flags such as B +and B and the configured depth limit always take +their default values, and the specific B code that caused +chain construction to fail is not reported back: the function signals only +success or failure through its return value (and, when I is NULL, may +also return a partial chain). + +On success the returned stack starts with a newly up-referenced I +followed by the issuer certificates that were found. A self-signed certificate +at the top of the chain is included in the returned stack when either +I is 1, or the chain consists solely of I (for +example because I itself is self-signed or no further issuer could +be found). When the chain has more than one element and I +is 0, the self-signed top is omitted from the result. + +The caller is responsible for freeing the returned stack. + +=head1 THE VERIFICATION CALLBACK + +Each B carries a I with the signature + + int (*verify_cb)(int ok, X509_STORE_CTX *ctx); + +This callback is invoked by X509_verify_cert() and X509_STORE_CTX_verify() +at multiple points during verification, both to B and to +B. It is installed by L +on the context, or it is inherited at L time from +the B (see L). If neither has +been set, a default callback is used which simply returns its I argument +unchanged, causing every error to abort verification. + +=head2 When the callback is called + +There are two distinct invocation patterns: + +=over 4 + +=item B (I = 0) + +The callback is called with I set to 0 each time a check fails. Before the +call, the verification machinery records the B code describing +the failure on I, and for certificate-level errors also records the +depth at which the error was detected and the certificate in question. The +callback inspects these via L, +L, and L. +CRL- and OCSP-related errors update only the error code; the depth and +current certificate retain their values from a preceding context. + +=item B (I = 1) + +During the signature-and-validity pass, after each certificate in the chain +has been checked successfully, the callback is called with I set to 1. +The current certificate, current issuer, and error depth (queryable +respectively via L, +L, and +L) describe the certificate that has just +been accepted. The callback may use this to log progress, but B return +a nonzero value, otherwise verification is aborted. + +=back + +The callback's return value controls subsequent verification: + +=over 4 + +=item * + +A nonzero return value causes verification to B. For an error +notification this constitutes B the error. + +=item * + +A zero return value causes verification to B immediately. The function +returns 0 to its caller in this case, regardless of whether the callback was +invoked with I = 0 or I = 1. + +=back + +=head2 Sticky errors + +When the callback waives an error by returning nonzero, the underlying check is +treated as passed for control-flow purposes, but the error code recorded on +I is B reset to B. A subsequent successful return from +X509_verify_cert() therefore does B imply that +L will return B: it may still hold +the last error code that was waived. This is intentional. Only the callback +itself is permitted to overwrite the error code, via +L, and only at its own risk. + +=head2 Dangers + +A verification callback that returns nonzero on an error notification has, by +definition, suppressed an authentication check that OpenSSL considered +necessary. Callers should treat installing a callback that waives errors as a +deliberate weakening of the security guarantees of X509_verify_cert(), to be +done only for specific, well-understood error codes. The following pitfalls are +common: + +=over 4 + +=item * + +B. A callback that returns 1 unconditionally turns +X509_verify_cert() into "accept anything" and is almost always wrong outside of +diagnostics. Inspect the error code via L and +waive only the specific codes you intend to. + +=item * + +B. Because the callback is also called with +I = 1, a callback that mistakenly returns 0 in that case causes +verification to fail even though every check passed. The caller cannot +distinguish this from a genuine failure based on the return value alone. + +=item * + +B. The sticky-error rule exists so that a waived +error remains visible to the caller after verification returns. A callback +that calls L with B hides this +information and can also mask a later error if the callback is invoked again +before verification completes. + +=item * + +B. The B is live during +the callback: the verification routines are actively reading its chain, +parameters, and other state. Calling context-mutating functions from within +the callback -- for example, replacing the verified chain via +L, swapping the trust store or +untrusted stack, or changing verification flags, depth, purpose, or target +-- can corrupt the in-progress verification, produce inconsistent behaviour +between later steps of the pipeline, or, in the case of the verified chain, +cause use-after-free. The only mutators reasonable from within a callback +are the error-related setters (L, +L, L), +and even those should be used sparingly (see L). + +=item * + +B. The callback is on the hot path of every +certificate check; expensive work performed there will slow every TLS handshake +or S/MIME verification that uses the surrounding context. + +=item * + +B. The error depth, from +L, records where an error was detected +during chain processing, not the position of the certificate in the final +chain. Always consult L in addition to +the depth when deciding whether to waive. + +=item * + +B. The set of errors the callback +observes, and the order in which it observes them, depends on the internal +order in which verification checks are performed. When a certificate has more +than one problem, only the first check to detect a problem causes the +callback to be invoked for that certificate; later checks are not reached +unless the callback waives the earlier error. This ordering is an +implementation detail and is not part of the stable API: a refactor that +reorders internal checks without altering the binary success/failure contract +of X509_verify_cert() may still change which B code the +callback sees, or whether a given code is reported at all. Callbacks that +branch on a specific error code being reported, or that assume earlier checks +have already filtered out certain conditions, can therefore change behaviour +silently across OpenSSL releases. Write callbacks defensively: re-fetch the +error code and the current certificate via L +and L afresh on each invocation, and +treat "this error code never appears" as an assumption that may be +invalidated. More fundamentally, because the set and order of error +notifications is not a stable contract, the callback cannot be relied upon to +observe any particular condition or sequence of conditions; that makes it an +unsound mechanism for enforcing or modifying security policy. Use of the +verification callback to alter verification outcomes -- to waive errors, to +inject conditional acceptance, or to gate behaviour on a specific +B code being reported -- is therefore discouraged in production +code. Reserve the callback for diagnostic and logging purposes, where future +changes in which errors appear, or in what order, are not security-relevant. + +=back + +The default callback waives nothing and is the safe choice; it is the right +behaviour for almost all production uses. =head1 RETURN VALUES -X509_build_chain() returns NULL on error, else a stack of certificates. +X509_verify_cert() and X509_STORE_CTX_verify() return: + +=over 4 + +=item B<1> + +if a complete chain has been built and every check either succeeded or was +waived by the verification callback. Note that the latter case does not +guarantee that L returns B; see +L. The return value is the authoritative success/failure +signal: callers do not need to additionally check that +L returns B to consider verification +successful. They may consult it to learn whether, and which, errors were +waived by the verification callback. + +=item B<0> + +if verification was rejected. This occurs when a check failed and the callback +did not waive the error, when a trust decision actively rejected the chain, or +when the verification callback returned 0 from a success notification (see +L). When a certificate would have failed more +than one check, the specific B code returned by +L reflects whichever check fired first; this +ordering is an implementation detail and is not stable across releases. +Callers must therefore treat the return value as the authoritative +success/failure signal, and treat the specific error code as diagnostic +information that may shift over time. + +=item A B value + +on a hard error that prevented verification from running to completion. The +documented cases are: I is NULL; I has no target certificate set; +I has already been used for a previous verification; memory allocation +failed; the trust store lookup function returned an error; or an internal +invariant was violated. In these cases L +returns an appropriate B value (B, +B, B or +B). + +=back + +In all failure modes, additional information can be obtained from +L and the related accessors. Applications must +treat any return value E= 0 as verification not having succeeded. + +X509_build_chain() returns NULL on error. Otherwise it returns a newly +allocated stack of certificates that the caller must free; the stack may +represent only a partial chain when I is NULL. + +=head1 BUGS + +Several aspects of chain construction depart from the recommendations of +RFC 4158 (Certification Path Building) and from strict RFC 5280 path +validation. Callers should be aware of the following: + +The chain search is not optimised in the manner described by RFC 4158 +sections 3.1 to 3.5. Candidate issuers are not scored against the set of +heuristics RFC 4158 recommends; at each step the first viable candidate +is committed to, with the only preference being for a candidate whose +validity period covers the current time. There is no tree-traversal +backtracking: when an initial chain does not reach a trust anchor, the +search is retried with progressively shorter untrusted prefixes (unless +B is set), but different candidate issuers at +intermediate positions of the same chain are not tried. In simple +hierarchical PKIs this is rarely an issue. In cross-certified or bridged +PKI environments X509_verify_cert() may fail to find a valid certification +path even when one demonstrably exists in the available certificate set. -Both X509_verify_cert() and X509_STORE_CTX_verify() -return 1 if a complete chain can be built and validated, -otherwise they return 0, and in exceptional circumstances (such as malloc -failure and internal errors) they can also return a negative code. +Issuer key usage is not enforced during chain construction. RFC 5280 +section 6.1.4(n) and RFC 4158 section 3.5.3 call for verifying that an +issuer candidate's keyUsage extension permits certificate signing +(B) before that candidate is selected. OpenSSL defers this +check to the later extension-validation pass: if two candidate issuers +exist for a certificate, and the one lacking B happens to be +selected first, verification fails on the extension check rather than +backing off and trying the other candidate. The misuse is ultimately +caught, but a chain that would have validated through the alternative +issuer is not built. -If a complete chain can be built and validated both functions return 1. -If the certificate must be rejected on the basis of the data available -or any required certificate status data is not available they return 0. -If no definite answer possible they usually return a negative code. +B relaxes the trust-anchor requirement from +the one defined by RFC 5280 section 6.1.1(d). With the flag set, any +certificate in the trust store is acceptable as the terminator of the +chain, even if it is not a self-signed root. This is an intentional and +now-common deviation that supports modern practices such as pinning trust +to a specific intermediate, or shortening chains by treating a +sufficiently-trusted intermediate as the trust point and eliding the root +above it. Callers should nevertheless be aware that the chain returned in +this mode does not necessarily terminate at an RFC 5280-style trust +anchor. -On error or failure additional error information can be obtained by -examining I using, for example, L. Even if -verification indicated success, the stored error code may be different from -X509_V_OK, likely because a verification callback function has waived the error. +L caps each per-pair check at 2**20 +comparisons, but the chain orchestrator issues B(B-1)/2 such +checks for an B-certificate chain. An adversary submitting a +maximally constructed chain can therefore force up to approximately +6.3 million name-constraint comparisons in a four-certificate chain +(one leaf and three name-constrained signers), or approximately 5.2 +billion at the default chain-depth limit of 100. =head1 SEE ALSO +L, L, L, L, L, L, L, -L +L, +L, +L, +L =head1 HISTORY @@ -102,7 +480,7 @@ X509_build_chain() and X509_STORE_CTX_verify() were added in OpenSSL 3.0. =head1 COPYRIGHT -Copyright 2009-2023 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2009-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/man7/EVP_CIPHER-SM4.pod b/doc/man7/EVP_CIPHER-SM4.pod index a446fafb6d4b1..b68ffc9b6aae9 100644 --- a/doc/man7/EVP_CIPHER-SM4.pod +++ b/doc/man7/EVP_CIPHER-SM4.pod @@ -39,6 +39,13 @@ L. =head1 NOTES +SM4 implementations in OpenSSL may use secret-dependent table lookups and +are not guaranteed to be constant-time. In particular, the portable C +implementation uses S-box and T-table lookups and may be vulnerable to +cache-timing side-channel attacks. Which code path is used depends on CPU +capabilities; see L, L and +L. + The SM4-XTS implementation allows streaming to be performed, but each L or L call requires each input to be a multiple of the blocksize. Only the final EVP_EncryptUpdate() or @@ -48,11 +55,12 @@ stealing (CTS) is used to fill the block. =head1 SEE ALSO -L, L +L, L, L, +L, L =head1 COPYRIGHT -Copyright 2021 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/man7/EVP_SIGNATURE-ECDSA.pod b/doc/man7/EVP_SIGNATURE-ECDSA.pod index aa1d1a8f0de93..cd9536ef2900f 100644 --- a/doc/man7/EVP_SIGNATURE-ECDSA.pod +++ b/doc/man7/EVP_SIGNATURE-ECDSA.pod @@ -89,7 +89,7 @@ EVP_PKEY_CTX_get_params(). =item "fips-indicator" (B) -=item "verify-message" (B +=item "verify-message" (B) The parameters are described in L. diff --git a/doc/man7/EVP_SIGNATURE-RSA.pod b/doc/man7/EVP_SIGNATURE-RSA.pod index 7ec9eda5c1a5c..6de51825b5d34 100644 --- a/doc/man7/EVP_SIGNATURE-RSA.pod +++ b/doc/man7/EVP_SIGNATURE-RSA.pod @@ -167,7 +167,7 @@ EVP_PKEY_CTX_get_params(). =item "fips-indicator" (B) -=item "verify-message" (B +=item "verify-message" (B) These common parameter are described in L. diff --git a/doc/man7/fips_module.pod b/doc/man7/fips_module.pod index f32c65081e12a..9bd82f46d25d7 100644 --- a/doc/man7/fips_module.pod +++ b/doc/man7/fips_module.pod @@ -589,13 +589,16 @@ L /for further information. Some released versions of OpenSSL do not include a validated FIPS provider. To determine which versions have undergone the validation process, please refer to the -L. If you +L. If you require FIPS-approved functionality, it is essential to build your FIPS provider using one of the validated versions listed there. Normally, it is possible to utilize a FIPS provider constructed from one of the validated versions alongside F and F compiled from any -release within the same major release series. This flexibility enables -you to address bug fixes and CVEs that fall outside the FIPS boundary. +supported release from OpenSSL 3.0 onwards; provider compatibility is +maintained backward and forward across these releases, including future +major release series, for as long as the module remains supported. This +flexibility enables you to address bug fixes and CVEs that fall outside +the FIPS boundary. As the FIPS provider still supports non-FIPS validated algorithms, The property query C is mandatory for applications that @@ -614,7 +617,7 @@ FIPS indicators were added in OpenSSL 3.4. =head1 COPYRIGHT -Copyright 2021-2025 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/man7/openssl-core_dispatch.h.pod b/doc/man7/openssl-core_dispatch.h.pod index a19e1331fa68b..84668b8047610 100644 --- a/doc/man7/openssl-core_dispatch.h.pod +++ b/doc/man7/openssl-core_dispatch.h.pod @@ -24,7 +24,7 @@ are named as follows: These macros have the form C>. -=item dipatch numbers +=item dispatch numbers These macros have the form C_I>, where C> is the same as in the macro for the operation this @@ -46,7 +46,7 @@ The types and macros described here were added in OpenSSL 3.0. =head1 COPYRIGHT -Copyright 2020 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/doc/man7/openssl-env.pod b/doc/man7/openssl-env.pod index 5647af84f9634..8e2b391fcd913 100644 --- a/doc/man7/openssl-env.pod +++ b/doc/man7/openssl-env.pod @@ -182,8 +182,8 @@ OpenSSL supports a number of different algorithm implementations for various machines and, by default, it determines which to use based on the processor capabilities and run time feature enquiry. These environment variables can be used to exert more control over this selection process. -See L, L, L, -and L. +See L, L, L, +L and L. =item B, B, B diff --git a/doc/man7/openssl-quic-concurrency.pod b/doc/man7/openssl-quic-concurrency.pod index e79dd2a3a2c67..7f2e54bcb35c9 100644 --- a/doc/man7/openssl-quic-concurrency.pod +++ b/doc/man7/openssl-quic-concurrency.pod @@ -150,6 +150,29 @@ default concurrency model if the application does not explicitly specify a concurrency model or disable it. This is known as Legacy Blocking Compatibility Mode, and its usage is not recommended for multi-threaded applications. +=head1 THREAD CANCELLATION + +The restrictions in L also apply to +OpenSSL QUIC APIs, including calls used in nonblocking mode. + +CCM and TACM use domain-wide synchronisation during API processing. Event +processing may perform network I/O while it is held, which can be a POSIX +cancellation point. Interruption can leave later use or teardown of the domain +unsafe. + +TACM and CCM with B also maintain internal wait state +for blocking calls. If interruption prevents cleanup of this state, later calls +on the affected domain can block indefinitely. L can maintain such +state in multiple domains in one call. + +Because most blocking QUIC functions do not provide a per-call timeout, +applications requiring prompt cooperative cancellation should use nonblocking +mode and an application-driven event loop as described in +L, waiting for the application +cancellation event alongside QUIC events. Alternatively, an application can +call L with a finite timeout and check a cancellation condition +between calls. + =head1 RECOMMENDED USAGE New applications are advised to choose a concurrency model as follows: @@ -323,13 +346,15 @@ blocking mode can be changed explicitly using L. =head1 SEE ALSO -L, L, L, +L, L, L, +L, L, +L, L, L, L, L =head1 COPYRIGHT -Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy diff --git a/doc/man7/openssl-threads.pod b/doc/man7/openssl-threads.pod index 7f29a327ac6a3..ca8d879c457c2 100644 --- a/doc/man7/openssl-threads.pod +++ b/doc/man7/openssl-threads.pod @@ -84,9 +84,35 @@ In this specific case, and probably for factory methods in general, it is not safe to modify the factory object after it has been used to create other objects. +=head1 THREAD CANCELLATION + +Thread safety does not imply cancellation safety. +Unless a specific function documents otherwise, OpenSSL does not guarantee +that an in-progress call can be abandoned safely by thread cancellation or +forced termination. An interruption can leave locks held, resources unreleased, +or shared state inconsistent, making later use or cleanup unsafe. + +Deferred cancellation can take effect at a cancellation point reached directly +or through a callback, BIO, provider, or other pluggable implementation. +Automatic thread-local cleanup and L, when they run, do +not unwind the interrupted call. + +Applications should act on cancellation only between OpenSSL calls. On POSIX +systems, applications using pthread cancellation should disable cancellation +with B() before entering OpenSSL and restore it only +after OpenSSL returns at a point safe for cancellation. Callbacks invoked by +OpenSSL must not re-enable it. Disabling cancellation does not make a blocking +call return on a cancellation request; applications requiring prompt +cancellation should use nonblocking operation where available. + +The same restriction applies to other non-local exits which abandon an OpenSSL +call in progress, including direct thread exit, long jumps, and language +exceptions. + =head1 SEE ALSO -CRYPTO_THREAD_run_once(3), +L, L, +L, local system threads documentation. =head1 BUGS @@ -95,7 +121,7 @@ This page is admittedly very incomplete. =head1 COPYRIGHT -Copyright 2021 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/man7/provider-kem.pod b/doc/man7/provider-kem.pod index 85b8f1a6b80aa..739264ec329f0 100644 --- a/doc/man7/provider-kem.pod +++ b/doc/man7/provider-kem.pod @@ -32,7 +32,8 @@ provider-kem - The kem library E-E provider functions unsigned char *secret, size_t *secretlen); /* Decapsulation */ - int OSSL_FUNC_kem_decapsulate_init(void *ctx, void *provkey); + int OSSL_FUNC_kem_decapsulate_init(void *ctx, void *provkey, + const OSSL_PARAM params[]); int OSSL_FUNC_kem_auth_decapsulate_init(void *ctx, void *provkey, void *provauthkey, const OSSL_PARAM params[]); @@ -129,13 +130,13 @@ context in the I parameter and return the duplicate copy. OSSL_FUNC_kem_encapsulate_init() initialises a context for an asymmetric encapsulation given a provider side asymmetric kem context in the I -parameter, a pointer to a provider key object in the I parameter and -the I of the algorithm. +parameter, a pointer to a provider key object in the I parameter. + The I, if not NULL, should be set on the context in a manner similar to using OSSL_FUNC_kem_set_ctx_params(). The key object should have been previously generated, loaded or imported into the provider using the key management (OSSL_OP_KEYMGMT) operation (see -provider-keymgmt(7)>. +L. OSSL_FUNC_kem_auth_encapsulate_init() is similar to OSSL_FUNC_kem_encapsulate_init(), but also passes an additional authentication @@ -159,11 +160,13 @@ written to I<*secretlen>. OSSL_FUNC_kem_decapsulate_init() initialises a context for an asymmetric decapsulation given a provider side asymmetric kem context in the I -parameter, a pointer to a provider key object in the I parameter, and -a I of the algorithm. +parameter, a pointer to a provider key object in the I parameter. + +The I, if not NULL, should be set on the context in a manner similar to +using OSSL_FUNC_kem_set_ctx_params(). The key object should have been previously generated, loaded or imported into the provider using the key management (OSSL_OP_KEYMGMT) operation (see -provider-keymgmt(7)>. +L. OSSL_FUNC_kem_auth_decapsulate_init() is similar to OSSL_FUNC_kem_decapsulate_init(), but also passes an additional authentication @@ -250,7 +253,7 @@ were added in OpenSSL 3.4. =head1 COPYRIGHT -Copyright 2020-2024 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/doc/man7/provider-signature.pod b/doc/man7/provider-signature.pod index 0e25dc3d32d39..a77062632d467 100644 --- a/doc/man7/provider-signature.pod +++ b/doc/man7/provider-signature.pod @@ -588,7 +588,7 @@ A getter that returns 1 if the operation is FIPS approved, or 0 otherwise. This may be used after calling either the sign or verify final functions. It may return 0 if either the "digest-check", "key-check", or "sign-check" are set to 0. -=item "verify-message" (B +=item "verify-message" (B) A getter that returns 1 if a signature verification operation acted on a raw message, or 0 if it verified a predigested message. A value of 0 diff --git a/fuzz/corpora b/fuzz/corpora deleted file mode 160000 index ce771805c094d..0000000000000 --- a/fuzz/corpora +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ce771805c094d098c25a218bc8e9f7344eccbc5a diff --git a/fuzz/provider.c b/fuzz/provider.c index 8234a7e8dca64..69905223fbb40 100644 --- a/fuzz/provider.c +++ b/fuzz/provider.c @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2023-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,8 +32,11 @@ { \ STACK_OF(evp) *obj_stack = stack; \ \ - if (sk_##evp##_push(obj_stack, obj) > 0) \ - evp##_up_ref(obj); \ + if (!evp##_up_ref(obj)) \ + return; \ + \ + if (sk_##evp##_push(obj_stack, obj) <= 0) \ + evp##_free(obj); \ } \ static void init_##name(OSSL_LIB_CTX *libctx) \ { \ diff --git a/gost-engine b/gost-engine deleted file mode 160000 index 74b1f4fddbc2d..0000000000000 --- a/gost-engine +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 74b1f4fddbc2d6de969815b1992ddc1ae7c643fe diff --git a/include/internal/hashtable.h b/include/internal/hashtable.h index bc44e43678a36..8bfa539236168 100644 --- a/include/internal/hashtable.h +++ b/include/internal/hashtable.h @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -272,7 +272,7 @@ static void ossl_unused ossl_ht_strcase(char *tgt, const char *src, int len) if (src == NULL) return; - for (i = 0; src[i] != '\0' && i < len; i++) + for (i = 0; i < len && src[i] != '\0'; i++) tgt[i] = case_adjust & src[i]; } diff --git a/include/internal/list.h b/include/internal/list.h index 8bb0b741bed12..270e3f1dbb937 100644 --- a/include/internal/list.h +++ b/include/internal/list.h @@ -1,5 +1,5 @@ /* - * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -194,6 +194,35 @@ list->omega = elem; \ list->num_elems++; \ } \ + static ossl_unused ossl_inline void \ + ossl_list_##name##_join(OSSL_LIST(name) * lh, OSSL_LIST(name) * lt) \ + { \ + OSSL_LIST_DBG(type * _p); /* local variable '_p' when debug */ \ + if (lt == NULL || lh == NULL || lt->num_elems == 0 || lh == lt) \ + return; \ + /* \ + * let's be optimistic about size_t overflow here: it can not happen. \ + */ \ + lh->num_elems += lt->num_elems; \ + if (lh->omega == NULL) { \ + assert(lh->alpha == NULL); \ + lh->omega = lt->omega; \ + lh->alpha = lt->alpha; \ + } else { \ + if (lt->alpha != NULL) \ + ((type *)lt->alpha)->ossl_list_##name.prev = lh->omega; \ + ((type *)lh->omega)->ossl_list_##name.next = lt->alpha; \ + } \ + OSSL_LIST_DBG(for (_p = (type *)lt->alpha; \ + assert(_p == NULL || _p->ossl_list_##name.list == lt), _p != NULL; \ + _p = _p->ossl_list_##name.next) \ + _p->ossl_list_##name.list \ + = lh); \ + lh->omega = lt->omega; \ + lt->alpha = NULL; \ + lt->omega = NULL; \ + lt->num_elems = 0; \ + } \ struct ossl_list_st_##name #define DEFINE_LIST_OF(name, type) \ diff --git a/include/internal/quic_ackm.h b/include/internal/quic_ackm.h index c0617da4855f6..5b325e166bd54 100644 --- a/include/internal/quic_ackm.h +++ b/include/internal/quic_ackm.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -129,6 +129,11 @@ struct ossl_ackm_tx_pkt_st { }; int ossl_ackm_on_tx_packet(OSSL_ACKM *ackm, OSSL_ACKM_TX_PKT *pkt); + +/* + * Records transmission of a packet containing only ACK frames. + */ +int ossl_ackm_on_tx_ack_only_packet(OSSL_ACKM *ackm, OSSL_ACKM_TX_PKT *pkt); int ossl_ackm_on_rx_datagram(OSSL_ACKM *ackm, size_t num_bytes); #define OSSL_ACKM_ECN_NONE 0 diff --git a/include/internal/quic_port.h b/include/internal/quic_port.h index 5a2c9352378bf..88fb126e99492 100644 --- a/include/internal/quic_port.h +++ b/include/internal/quic_port.h @@ -1,5 +1,5 @@ /* - * Copyright 2023-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2023-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -187,6 +187,10 @@ uint64_t ossl_quic_port_get_net_bio_epoch(const QUIC_PORT *port); void ossl_quic_port_raise_net_error(QUIC_PORT *port, QUIC_CHANNEL *triggering_ch); +uint64_t ossl_quic_port_get_max_pending_channels(const QUIC_PORT *port); + +void ossl_quic_port_set_max_pending_channels(QUIC_PORT *port, uint64_t max_pending_channels); + #endif #endif diff --git a/include/internal/quic_record_rx.h b/include/internal/quic_record_rx.h index 287837b2a5610..a4e9e7cacd259 100644 --- a/include/internal/quic_record_rx.h +++ b/include/internal/quic_record_rx.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -51,8 +51,9 @@ typedef struct ossl_qrx_args_st { OSSL_QRX *ossl_qrx_new(const OSSL_QRX_ARGS *args); /* - * Frees the QRX. All packets obtained using ossl_qrx_read_pkt must already - * have been released by calling ossl_qrx_release_pkt. + * Frees the QRX/reference to QRX. Frees the QRX object, if all references are + * gone. All packets obtained using ossl_qrx_read_pkt must already have been + * released by calling ossl_qrx_release_pkt. * * You do not need to call ossl_qrx_remove_dst_conn_id first; this function will * unregister the QRX from the demuxer for all registered destination connection @@ -60,6 +61,12 @@ OSSL_QRX *ossl_qrx_new(const OSSL_QRX_ARGS *args); */ void ossl_qrx_free(OSSL_QRX *qrx); +/* + * Obtains a new reference to QRX object. Returns NULL if reference can not + * be obtained. + */ +OSSL_QRX *ossl_qrx_newref(OSSL_QRX *qrx); + /* Setters for the msg_callback and msg_callback_arg */ void ossl_qrx_set_msg_callback(OSSL_QRX *qrx, ossl_msg_cb msg_callback, SSL *msg_callback_ssl); diff --git a/include/internal/quic_ssl.h b/include/internal/quic_ssl.h index f714d10477166..a9c17e1087a3d 100644 --- a/include/internal/quic_ssl.h +++ b/include/internal/quic_ssl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -179,6 +179,7 @@ int ossl_quic_conn_poll_events(SSL *ssl, uint64_t events, int do_tick, int ossl_quic_get_notifier_fd(SSL *ssl); void ossl_quic_enter_blocking_section(SSL *ssl, QUIC_REACTOR_WAIT_CTX *wctx); void ossl_quic_leave_blocking_section(SSL *ssl, QUIC_REACTOR_WAIT_CTX *wctx); +QUIC_PORT *ossl_quic_listener_get_port(SSL *s); #endif diff --git a/include/internal/refcount.h b/include/internal/refcount.h index 61eb78ae41205..5c11c80fc15fa 100644 --- a/include/internal/refcount.h +++ b/include/internal/refcount.h @@ -21,8 +21,9 @@ #define HAVE_C11_ATOMICS #endif -#if defined(HAVE_C11_ATOMICS) && defined(ATOMIC_INT_LOCK_FREE) \ - && ATOMIC_INT_LOCK_FREE > 0 +# if defined(HAVE_C11_ATOMICS) && defined(ATOMIC_INT_LOCK_FREE) \ + && ATOMIC_INT_LOCK_FREE > 0 \ + && 0 /// ClickHouse-specific patch: if we use atomics, tsan complains :( #define HAVE_ATOMICS 1 @@ -74,7 +75,8 @@ static inline int CRYPTO_GET_REF(CRYPTO_REF_COUNT *refcnt, int *ret) return 1; } -#elif defined(__GNUC__) && defined(__ATOMIC_RELAXED) && __GCC_ATOMIC_INT_LOCK_FREE > 0 +# elif defined(__GNUC__) && defined(__ATOMIC_RELAXED) && __GCC_ATOMIC_INT_LOCK_FREE > 0 \ + && 0 /// ClickHouse-specific patch: if we use atomics, tsan complains :( #define HAVE_ATOMICS 1 diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in index e684f7c429750..90be33cb4f176 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in @@ -2441,6 +2441,7 @@ __owur int SSL_get_conn_close_info(SSL *ssl, #define SSL_VALUE_STREAM_WRITE_BUF_SIZE 7 #define SSL_VALUE_STREAM_WRITE_BUF_USED 8 #define SSL_VALUE_STREAM_WRITE_BUF_AVAIL 9 +#define SSL_VALUE_QUIC_MAX_PENDING_CONNS 16 #define SSL_VALUE_EVENT_HANDLING_MODE_INHERIT 0 #define SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT 1 @@ -2688,8 +2689,18 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_OTHER_SIGALG (5 << 16) #define SSL_SECOP_OTHER_CERT (6 << 16) -/* Indicated operation refers to peer key or certificate */ +/* + * Unused values - these do nothing and are never set. + * They are retained because of API. They should + * be removed next major + */ #define SSL_SECOP_PEER 0x1000 +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) /* Values for "op" parameter in security callback */ @@ -2728,12 +2739,6 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); #define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) /* CA digest algorithm in certificate */ #define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) -/* Peer EE key in certificate */ -#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) -/* Peer CA key in certificate */ -#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) -/* Peer CA digest algorithm in certificate */ -#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) void SSL_set_security_level(SSL *s, int level); __owur int SSL_get_security_level(const SSL *s); diff --git a/include/openssl/x509err.h b/include/openssl/x509err.h index 7123a725e8254..4bbff54a380eb 100644 --- a/include/openssl/x509err.h +++ b/include/openssl/x509err.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -27,6 +27,7 @@ #define X509_R_CERTIFICATE_VERIFICATION_FAILED 139 #define X509_R_CERT_ALREADY_IN_HASH_TABLE 101 #define X509_R_CRL_ALREADY_DELTA 127 +#define X509_R_CRL_SIGNATURE_ALGORITHM_MISMATCH 147 #define X509_R_CRL_VERIFY_FAILURE 131 #define X509_R_DUPLICATE_ATTRIBUTE 140 #define X509_R_ERROR_GETTING_MD_BY_NID 141 diff --git a/krb5 b/krb5 deleted file mode 160000 index 784c38f50e70a..0000000000000 --- a/krb5 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 784c38f50e70a739400cdd3f2620bac2e2788e6c diff --git a/oqs-provider b/oqs-provider deleted file mode 160000 index 7bc597c04b534..0000000000000 --- a/oqs-provider +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7bc597c04b534ddea9b6654481deb31ded8e1bbc diff --git a/pkcs11-provider b/pkcs11-provider deleted file mode 160000 index 663dea335c80b..0000000000000 --- a/pkcs11-provider +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 663dea335c80bec7fd96d544ff875af08d6461a9 diff --git a/providers/baseprov.c b/providers/baseprov.c index 16d2f91bb1ac1..ad08765f006cf 100644 --- a/providers/baseprov.c +++ b/providers/baseprov.c @@ -1,5 +1,5 @@ /* - * Copyright 2020-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2020-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -29,10 +29,6 @@ static OSSL_FUNC_provider_gettable_params_fn base_gettable_params; static OSSL_FUNC_provider_get_params_fn base_get_params; static OSSL_FUNC_provider_query_operation_fn base_query; -/* Functions provided by the core */ -static OSSL_FUNC_core_gettable_params_fn *c_gettable_params = NULL; -static OSSL_FUNC_core_get_params_fn *c_get_params = NULL; - /* Parameters we provide to the core */ static const OSSL_PARAM base_param_types[] = { OSSL_PARAM_DEFN(OSSL_PROV_PARAM_NAME, OSSL_PARAM_UTF8_PTR, NULL, 0), @@ -139,15 +135,13 @@ int ossl_base_provider_init(const OSSL_CORE_HANDLE *handle, void **provctx) { OSSL_FUNC_core_get_libctx_fn *c_get_libctx = NULL; + OSSL_FUNC_core_get_params_fn *c_get_params = NULL; BIO_METHOD *corebiometh; if (!ossl_prov_bio_from_dispatch(in)) return 0; for (; in->function_id != 0; in++) { switch (in->function_id) { - case OSSL_FUNC_CORE_GETTABLE_PARAMS: - c_gettable_params = OSSL_FUNC_core_gettable_params(in); - break; case OSSL_FUNC_CORE_GET_PARAMS: c_get_params = OSSL_FUNC_core_get_params(in); break; diff --git a/providers/defltprov.c b/providers/defltprov.c index a74a048d6f76a..de2a46515e113 100644 --- a/providers/defltprov.c +++ b/providers/defltprov.c @@ -34,10 +34,6 @@ static OSSL_FUNC_provider_query_operation_fn deflt_query; #define ALGC(NAMES, FUNC, CHECK) { { NAMES, "provider=default", FUNC }, CHECK } #define ALG(NAMES, FUNC) ALGC(NAMES, FUNC, NULL) -/* Functions provided by the core */ -static OSSL_FUNC_core_gettable_params_fn *c_gettable_params = NULL; -static OSSL_FUNC_core_get_params_fn *c_get_params = NULL; - /* Parameters we provide to the core */ static const OSSL_PARAM deflt_param_types[] = { OSSL_PARAM_DEFN(OSSL_PROV_PARAM_NAME, OSSL_PARAM_UTF8_PTR, NULL, 0), @@ -733,6 +729,7 @@ int ossl_default_provider_init(const OSSL_CORE_HANDLE *handle, void **provctx) { OSSL_FUNC_core_get_libctx_fn *c_get_libctx = NULL; + OSSL_FUNC_core_get_params_fn *c_get_params = NULL; BIO_METHOD *corebiometh; if (!ossl_prov_bio_from_dispatch(in) @@ -740,9 +737,6 @@ int ossl_default_provider_init(const OSSL_CORE_HANDLE *handle, return 0; for (; in->function_id != 0; in++) { switch (in->function_id) { - case OSSL_FUNC_CORE_GETTABLE_PARAMS: - c_gettable_params = OSSL_FUNC_core_gettable_params(in); - break; case OSSL_FUNC_CORE_GET_PARAMS: c_get_params = OSSL_FUNC_core_get_params(in); break; diff --git a/providers/fips-sources.checksums b/providers/fips-sources.checksums index a2f5817e26de4..85af251d79e22 100644 --- a/providers/fips-sources.checksums +++ b/providers/fips-sources.checksums @@ -20,12 +20,12 @@ f1d8b7a3da1ec053d38be4fc776fef1e4fba328bfa2bfd928c2a2cd3b14f08ff crypto/aes/asm ee4e8cacef972942d2a89c1a83c984df9cad87c61a54383403c5c4864c403ba1 crypto/aes/asm/aes-sparcv9.pl 391497550eaca253f64b2aba7ba2e53c6bae7dff01583bc6bfc12e930bb7e217 crypto/aes/asm/aes-x86_64.pl 3b5ee174fa52d732d882ab4b2ffe59235d3bff66651714f32e743fcadaf1d970 crypto/aes/asm/aesfx-sparcv9.pl -14359dc32b7f4e5c08227fb9ac8f9232c1287399463b233fec4a2ab0c19f68d1 crypto/aes/asm/aesni-mb-x86_64.pl -f525e1bca51d39adcd411cbf8f874fe1441b23a6f614644da78dfd8544d13b23 crypto/aes/asm/aesni-sha1-x86_64.pl -895f94d7befb90e82f9d300ed8f870e790101f30ba72b249a2c503f07aec7dd2 crypto/aes/asm/aesni-sha256-x86_64.pl +e220d630965eb2672dca757aefcb9654928288772fd495da3a495b405b5f21ff crypto/aes/asm/aesni-mb-x86_64.pl +83a08babb80e15606bb52c6b4fcd1a6416d3b165b9cbfa42678ebe2e27c3b8d4 crypto/aes/asm/aesni-sha1-x86_64.pl +6808938757a489c3827e6da78f9ce227d88efcc29c3467fa0329b50b761523eb crypto/aes/asm/aesni-sha256-x86_64.pl 4ff74d4e629a88ef5a9e3d3f5b340fc0a4793d16d7cc7f1b70da62512a856248 crypto/aes/asm/aesni-x86.pl 25881237d026cebd96877a2ea2729db1ce512875cb2a10ca0cd1d6ddf4b51a3b crypto/aes/asm/aesni-x86_64.pl -6047359ad3967168812fbc8a95cb851b72c09f7846be2f03ec2ab93531a9c2bd crypto/aes/asm/aesni-xts-avx512.pl +00dd3a64df71ebd61fd35d2a6179d07cc86fc156cce1541ef176ecafb815f4bb crypto/aes/asm/aesni-xts-avx512.pl 0489a10fbb1a8ca3652848d5c1e14e519501e189bad3e5827a573c26df359691 crypto/aes/asm/aesp8-ppc.pl e397a5781893e97dd90a5a52049633be12a43f379ec5751bca2a6350c39444c8 crypto/aes/asm/aest4-sparcv9.pl 578142d03bc47353952fca2027eb63ec97ce9a1379c0f3c7ac0fdf110eb3378b crypto/aes/asm/aesv8-armx.pl @@ -39,7 +39,7 @@ c3541865cd02d81101cdbab4877ed82772e6980d2c677b9008b38fa1b26d36d4 crypto/aes/asm c6935d2ab7925022cb3d76446536ff01b1a1b8eb7eac619d034a29aad17ed45f crypto/aes/asm/vpaes-x86_64.pl 2bc67270155e2d6c7da87d9070e005ee79cea18311004907edfd6a078003532a crypto/alphacpuid.pl 269e52f8867c13ca75d2f88ec1f89b692cb8c6c3ee89abe2fd3c1821925191d8 crypto/arm64cpuid.pl -7a7c1d063be476f35442b0b056cfad0cf62190b603304abd283906ab40590167 crypto/armcap.c +b0242943b097f7640f1b3c33313934a98caf45d47d4403e9e53d826f6d2dc0c4 crypto/armcap.c d9f923daabe7537d1063b182f9f220655abd182ef4c55a0194a7ee8d6030b5bd crypto/armv4cpuid.pl e886d814c34492504cc9a2451c67fd8c0b4e83e8618f931632400cfe522b6e4d crypto/asn1_dsa.c 819c9fd2b0cae9aab81c3cbd1815c2e22949d75f132f649b5883812d0bbaa39a crypto/bn/asm/alpha-mont.pl @@ -58,14 +58,14 @@ b27ec5181e387e812925bb26823b830f49d7a6e4971b6d11ea583f5632a1504b crypto/bn/asm/ 59cd27e1e10c4984b7fb684b27f491e7634473b1bcff197a07e0ca653124aa9a crypto/bn/asm/ppc.pl 0b3350f56d423a4df918a08e90c7c66227c4449a9f9c44096eacc254ebc65f9f crypto/bn/asm/ppc64-mont-fixed.pl a25be64867ab837d93855af232e2bfa71b85b2c6f00e35e620fdc5618187fb6f crypto/bn/asm/ppc64-mont.pl -b3aad31ab658eceaa9c5e734e19f39c33991f4839ab55b0cec8018020b1a305e crypto/bn/asm/rsaz-2k-avx512.pl -03f6cc678f377c5cd953e8da135c5d76dc1cd011565118c99e25bff91e7271df crypto/bn/asm/rsaz-2k-avxifma.pl -e914311420ae4486ab6000cc6ab424f04d8a042bda40ab8f288348dc9f0eb595 crypto/bn/asm/rsaz-3k-avx512.pl -95b11e0b04c38bde06d152dfde5ab970dab27cccdfeac998e1bc293e01520474 crypto/bn/asm/rsaz-3k-avxifma.pl -e13bd2df8c591052ddf16a839072f43353841f9f35e0ac95f836511838dbc771 crypto/bn/asm/rsaz-4k-avx512.pl -cf92b66c4032703b7ce03ff6aa36887d14e31a8861e7aa21c46a466ea4802851 crypto/bn/asm/rsaz-4k-avxifma.pl -6e47bf041e51d8086c4933c2a5da3ce6d1b136592984754461d59aa81e4995a6 crypto/bn/asm/rsaz-avx2.pl -b42f6cf0fbf9eae58343df9629e7a9e5b8814195ea0c9882d7b143a0841cc018 crypto/bn/asm/rsaz-x86_64.pl +d48aded8547aa44a4af0d76d4675320628c66ba54e6fda865804953eefa8e853 crypto/bn/asm/rsaz-2k-avx512.pl +ae2e714dc003867c31136f939f8d47eb35eac3de36dbeea8f028a48d03b964ec crypto/bn/asm/rsaz-2k-avxifma.pl +6b5f35bf328f19b3add87a9715736ca92a8165920264311e20d3477a41a90a82 crypto/bn/asm/rsaz-3k-avx512.pl +b0ef4c3bb3a835066e9f7cafab22efc9d668b6debf5b9b9ec312cabae9412631 crypto/bn/asm/rsaz-3k-avxifma.pl +ca2d4486ee67f2015a8580664f3bbc28c23201205a2422d3a972cdf6ba59147a crypto/bn/asm/rsaz-4k-avx512.pl +80b0e7aca0ebee78fb3c651723e7f0eaac43a5b6a2bcf87b98a454a248abb945 crypto/bn/asm/rsaz-4k-avxifma.pl +7d686b484ea2bb65091c6ed3e74d5f4063ed4a8ecc09b7bef8d3a3aa57c4121e crypto/bn/asm/rsaz-avx2.pl +bec7e89c5a33652bbff20c95a6fe82bd96f7f2f61a3544c122f3af6f4f162110 crypto/bn/asm/rsaz-x86_64.pl 30fedf48dfc5fec1c2044b6c226dd9fc42a92522cc589797a23a79d452bdd2cf crypto/bn/asm/s390x-gf2m.pl 590388d69d7ac3a0e9af4014792f4f0fdb9552719e8fb48ebc7e5dfca2a491d4 crypto/bn/asm/s390x-mont.pl aa02597f3dc09cfbc190aedb75711859ba0f3efff87067ebfba1ec78ebee40d7 crypto/bn/asm/s390x.S @@ -81,9 +81,9 @@ d24f3e97239c8eed5efc721521b025b7256c15e67a54ea6b5c4cf8f7cd0f89ea crypto/bn/asm/ 90d4ae234c08267adce9ed38d56e0edc223f7480cb9605f5d7399d0b3914c6be crypto/bn/asm/x86-mont.pl 0e3e572cd864bcb9222cdad7ca4e8dae4250f6f76c2b66e1f0e46df1cc0cf371 crypto/bn/asm/x86_64-gcc.c 709ddee92e9222ee0ed27bfb90db556e85e2d302e4a9131afa25fdc14c4d858f crypto/bn/asm/x86_64-gf2m.pl -da7f7780d27eed164797e5334cd45b35d9c113e86afaca051463aef9a8fd787c crypto/bn/asm/x86_64-mont.pl -efe70ef06b5d92539f8a239c98c0261d93a15b3e418ca87d97ec569da9e6e9d3 crypto/bn/asm/x86_64-mont5.pl -0ea8185a037a2951bb3d1e590bbbdeac305176d5e618f3e43a04c09733a9de34 crypto/bn/bn_add.c +4ad5e97a7ed376d2cc079a3eabfbdc0cce3fe6e61751324ef18b72d24f7851d6 crypto/bn/asm/x86_64-mont.pl +11eebbeb8ae59158e780d74300b333de9705aefdde73cff280286c053c8743da crypto/bn/asm/x86_64-mont5.pl +7c81cd72fbf6f2dd85cbcbf40027301c98c1701928d3199edb2b8fdf04a5ca5e crypto/bn/bn_add.c 529933a6592cf82abde515dae10db17833a16ec29cb89ec577c0a184838fe27b crypto/bn/bn_asm.c feef3a84a40034291286882d483ac23ab55631c3c93f40ba0ea98944916ff3ec crypto/bn/bn_blind.c 1b8f89064c287669a834fe032ef823796f7355ed7e6da08d6c56c0a4cd0bba01 crypto/bn/bn_const.c @@ -91,13 +91,13 @@ eee3d2710144b0e860c57e84f5adc6b2bf64fc27cbd202a8ca2630aefed3b84c crypto/bn/bn_c 282f06fbdeb991d90337787c6407020e940b6d5e187a06866f1a7787c10a0c1b crypto/bn/bn_ctx.c b1b1c5fb8a45fde5755dfd5da62b68100b94f8c492c950719c108c384ea7f3c4 crypto/bn/bn_dh.c 4824f271f0ddc487b5991fbd92f7f7695aeeac234e076078f37da027999cdd88 crypto/bn/bn_div.c -d36b2be05469f144f52173616e413a7bdd836607fccf94cf543cc7f5a343b962 crypto/bn/bn_exp.c +f1e98f178356791a3d54f586c19d1639d8e89b2cf6e6a4de783327ceada296a2 crypto/bn/bn_exp.c ce5219203bf869561297978d6d416357a441864cd801865503dfd455c481960c crypto/bn/bn_exp2.c 18ac3f6fe64225f72243689199839ea2ce2aa61d80b084bc4cd9efe1c7cc9d89 crypto/bn/bn_gcd.c b643fdcd91ad7dfcfa97a0bb235221b024b8a77faa7890f0bcb9681ea2c64c49 crypto/bn/bn_gf2m.c 73ee247467879d4ec984c9900dfe7761233c5b889b8762be37c7e8fdd6d1d210 crypto/bn/bn_intern.c ff147e5e032cc7c772b73a91fc6e24d8d9516e642d29354445d1f82d64b1d924 crypto/bn/bn_kron.c -df9aebbdcca87fc5715dde430687fb516d8de0dac70c8910409fb73d6dd2305b crypto/bn/bn_lib.c +c4bae573e4e7132106b1151e8983cb63200dd9e49dc464e805f0fc50d55374d0 crypto/bn/bn_lib.c cd7bade0f2e223fe34f6e2f8cc87098ac8f0af96ec62ada5e67f6a2344d48ef0 crypto/bn/bn_local.h b494fd85387afa7816422922e52987e0faefc3c890c972e7d4fe04f620dfc59a crypto/bn/bn_mod.c 39a8fe0bb625b4c11b74998ce6fd99b7655228aaa7d7ad3076f61741937ae14d crypto/bn/bn_mont.c @@ -126,7 +126,7 @@ ab29529cca1308302d852999f2790c404a4dc0ef8cd6653260739f70b2f22758 crypto/core_fe 0e3519aec0d93b0700d1175616b8bfca9c045989fad515d2202dd7dff9caa5ac crypto/core_namemap.c a62f653b8a6ee765be704980425617e04e1d242f9735efaf35fc6e00815ff2a7 crypto/cpuid.c a73118d14eeb232ff250ae908204ddd7cf33deba5f3ca68a2dbb51b020946b0e crypto/cryptlib.c -66dbfc58916709d5a6913777346083247942a8d9458ee9b2bf443f0ea4988d64 crypto/ctype.c +0145299d43dbb60e85ef6b97cf7496dec55cc37b75433e1403c11adfa3e90c5f crypto/ctype.c b9fabcf8480b8c9c7847a0c9af0fcc13b6c4b4a4558d5e445e6409221e6f8113 crypto/der_writer.c 135ef65f7602432f8c87ad18fdd90b867f1c46b1c631522d56181fbed2106b05 crypto/des/des_enc.c 7c2cea4c850398158b4aff172b242de0cc436b66f62fc701ccca3fe5489925a5 crypto/des/des_local.h @@ -136,7 +136,7 @@ c1e015556147b40c854bf0ab275c54235f99001d04c6d49f158fba6865eb5439 crypto/des/fcr dc2e7899593032fdf0fcab18f5549c52f12bad2225aac9a08c4622ffee34b193 crypto/des/set_key.c 41b7fc5e67814311b878684e3f29cff60e228f1516f670d81bf43130f2668ae8 crypto/des/spr.h b842e39f34996d74cdc9b9be5fc93c27fc91ef6141fae83163e09f6b0eff1e09 crypto/dh/dh_backend.c -091ec05b6316cce34305ae8f8014043c7c9b72098aa1abe9c35dcbcdb4b77cd0 crypto/dh/dh_check.c +380d55ea09a50ba3ece173e64db90782efae08ca56ac51cb4d31b9a303b429ea crypto/dh/dh_check.c c117ac4fd24369c7813ac9dc9685640700a82bb32b0f7e038e85afd6c8db75c7 crypto/dh/dh_gen.c 1149e214ed664540434912e284730a3c87385172e4c6d1c944ea56659e2dd762 crypto/dh/dh_group_params.c a539a8930035fee3b723d74a1d13e931ff69a2b523c83d4a2d0d9db6c78ba902 crypto/dh/dh_kdf.c @@ -146,7 +146,7 @@ a9166c3cc60f4281e9d471c64145e0a78fc9dc43b8bc9e5de96d91eb7d277da3 crypto/dh/dh_l 40065939139ac28aa52838aa54d257da82fce73504557f7a9ad34d13824e0cb9 crypto/dsa/dsa_backend.c 786d6c65ced7ee4e25f5dd7c3150259ec95b6aa321a7590d905757b8139f8230 crypto/dsa/dsa_check.c ae727bf6319eb57e682de35d75ea357921987953b3688365c710e7fba51c7c58 crypto/dsa/dsa_gen.c -dee83cb278b3f712a62bd3477bdecf7b83e6df38ada2f3e1ca043d37327e2da4 crypto/dsa/dsa_key.c +43f8fba4f50fbc94b1532a7667c9cfdc91b357e8658fd5fe0dcd302ea93ae9a0 crypto/dsa/dsa_key.c 7d44106570c0ff9a44de874ea2daeaa87ea4c814fef6af0a26f655120a54f529 crypto/dsa/dsa_lib.c 98ce52d325d2409d7851f1e1226755136f115c884d227d2ae3e4f9b61fc323b8 crypto/dsa/dsa_local.h 3428bc7602f344f8b8d4a5807b0a7e982cbead1ec28be73ad77b5f849b034993 crypto/dsa/dsa_ossl.c @@ -159,9 +159,9 @@ d9722ad8c6b6e209865a921f3cda831d09bf54a55cacd1edd9802edb6559190a crypto/ec/asm/ 3715ddd921425f3018741037f01455ed26a840ace08691a800708170a66cf4d2 crypto/ec/asm/ecp_nistz256-ppc64.pl cfe7e75a2fddc87a7251684469a8808b9da82b2f5725eafad5806920f89932bd crypto/ec/asm/ecp_nistz256-sparcv9.pl 922725c4761cfa567af6ed9ecab04f2c7729ae2595f2fc0fa46dc67879dc87b0 crypto/ec/asm/ecp_nistz256-x86.pl -afa4497cfbf9ef7805e42ae6a61c7d983e8a789b270d498a07785570ab85a9fa crypto/ec/asm/ecp_nistz256-x86_64.pl +f5c4f8c74a44c8723293e3bb64c0c2cf75dc354466ac9f93ebfdab1df34b64c4 crypto/ec/asm/ecp_nistz256-x86_64.pl cc727533130f5f1a29229929b3d4e8454585d647be25d6344f3c6a0240998368 crypto/ec/asm/x25519-ppc64.pl -ee897e230964511baa0d1bf95fb938312407a40a88ebe01476879c2763e5f732 crypto/ec/asm/x25519-x86_64.pl +ee576a748991bb2cf0a37437e46a23dd55dfd35d989e087d122c7cf0f332eb2a crypto/ec/asm/x25519-x86_64.pl 2e7b5d2a3eff0b8a90c1de3f28a7bf59b1057e7694c0e36909e774343cef609f crypto/ec/curve25519.c 784c03c3f81fd0c363cd0500fbd95f3e49c65f47a249f7ba25fad42a41d3eea2 crypto/ec/curve448/arch_32/f_impl32.c 8e75602d4d492316d318bac147eaa09d87b0eeda0d450e18683d935673ab61b0 crypto/ec/curve448/arch_64/arch_intrinsics.h @@ -185,7 +185,7 @@ dfbccf591879eecbd9ed75da1fbe6c7b1672d07648fd43b37755dfe248253bb2 crypto/ec/ec_b 3a3c4f4767513b4fbbabdea2918d7c7d105eb573334a7fd893b866989463c4d2 crypto/ec/ec_check.c f3991bfc65a7371b84afd0cc328e3cbd4736edf7267e4b731dd82677bfab047a crypto/ec/ec_curve.c 8cfd0dcfb5acbf6105691a2d5e2826dba1ff3906707bc9dd6ff9bffcc306468f crypto/ec/ec_cvt.c -add58bcaf43a28e66b3a6ec1f70ed9b0b4a4a0d40230e903a26a1ff1129649e0 crypto/ec/ec_key.c +b94eb087740dde2bf697cfbc5e8a17efd80e84c5072c9c72f8ed2f9155976d37 crypto/ec/ec_key.c 35515133fb3c33c5736a9f744e835b9fc0775193357ab2492f11d0f63503c65e crypto/ec/ec_kmeth.c 652a1544120bf0fecde46a8e18cc28fffcb7cd864be2e2b84c99d571ba320e64 crypto/ec/ec_lib.c 0d113ac5dbdb420ba3d1c060f4fa3300fc0a81b571a919c2b176022fdca89878 crypto/ec/ec_local.h @@ -214,7 +214,7 @@ ed0217e7c2049b44a454b40e7e18385eadb34bce1bcf54337f420cbf988775da crypto/evp/asy e997e921669076c51e230ccb2e36b1c6755fe408c61b1177d2aa67529cab15f3 crypto/evp/evp_local.h 8963ef06e4d228f7067917434f60f0502dc4bbdf3b271649498b734f4074bfb0 crypto/evp/evp_rand.c 0bdae4714221662282dccd5b1f2485370d24e463c11bdbb71a310f34616954fe crypto/evp/evp_utils.c -8f4194bcc2e0de69236925aa7515bc31f36ed113dcd3cee5d71167ac770cdfdd crypto/evp/exchange.c +1d78745866dde8224eec50c8553a15b51aa14bc3313969479806b3c3024c7282 crypto/evp/exchange.c 294284ad040fe4b74845f91b1903c961c757e1ef3fcc2ffa35f43f37f1655e64 crypto/evp/kdf_lib.c 532f0ff4ab32068f160016f39cd520fadfbd09b81b3b3b562bf543acafb38889 crypto/evp/kdf_meth.c d911878128b90b98f3a4a1fb844ef3a20d35eafda3f80773dac8ce93c55bc352 crypto/evp/kem.c @@ -239,7 +239,7 @@ bb208ef3a2c7ebdc518bd38f2f07a17cff356040f1c5d68eea13bd9275897a52 crypto/ffc/ffc e9a500ddbe96cb5b302fd2db74fac0924a6ac45732df5ee1c09e82b19d06ccfd crypto/ffc/ffc_params_validate.c f172c8c2112ee82716a7bc3a3e05d5cc26188c66b9d768ac1ff906845063d2cc crypto/hashtable/hashfunc.c ed523d9793ff9db947857bca354067d17b8de5a4b28604dbf902320e62d93e33 crypto/hashtable/hashtable.c -7a9af0b14f1463b36de0689bc434a318adcb7990bb23862bf1d2a0adf510583a crypto/hmac/hmac.c +9a63ec43c8b9a55e0b135394a659026c1d1236978ebbb5df0e3c4c5c58b62ef4 crypto/hmac/hmac.c 907dd44e0bf873eebefcb4d82975b72ecec9e0f3c348c79314450fdaa78d4073 crypto/hmac/hmac_local.h 0e2d6129504d15ffaf5baa63158ccec0e4b6193a8275333956d8f868ef35127e crypto/ia64cpuid.S 29c020cf599c24ef9969a42e00e690a7b463c20dd90356b0a4117ca31b13db6f crypto/initthread.c @@ -248,28 +248,28 @@ ed523d9793ff9db947857bca354067d17b8de5a4b28604dbf902320e62d93e33 crypto/hashtab 899ba6a9049a61d5b175637907f747f58863cd8950409cefac8fbc8f574f970c crypto/loongarch64cpuid.pl 460a7af09cde89a820b091522ada1310cfcec99c60aee505f94c48c35e9a29e8 crypto/loongarchcap.c f866aafae928db1b439ac950dc90744a2397dfe222672fe68b3798396190c8b0 crypto/mem_clr.c -23ff635daa1a3149e14de6c2a41b82a7587801581bdf39b8a82e9c624da95471 crypto/ml_dsa/ml_dsa_encoders.c +1812ee360303b9fdcebe6dd0690944646bd9605ee67e3554c691cf5993293c46 crypto/ml_dsa/ml_dsa_encoders.c 825105b0a2c4844b2b4229001650ff7e61e1348e52f1072210f70b97cd4adb71 crypto/ml_dsa/ml_dsa_hash.h -2fbef0188a8606c56f2ffffecfbbbd13ccd454c2af949d6e37fb7c929974f1d4 crypto/ml_dsa/ml_dsa_key.c +2bebd01093de6f77dabb8b6e5ac3deaad9104904956691e22d80f105a3e526c2 crypto/ml_dsa/ml_dsa_key.c 579c1a12a5c5f014476a6bf695dc271f63074fb187e23ffc3f9ccb5b7ea044f1 crypto/ml_dsa/ml_dsa_key.h 3f98eb0467033d0a40867ef1c1036dcfea5d231eeac2321196f7d7c7243edace crypto/ml_dsa/ml_dsa_key_compress.c 170292bfc8761e39b688ccfb21b3660af6e1a875aa38ff7448cc22f71f5874c5 crypto/ml_dsa/ml_dsa_local.h -0490a89372b79d98c2fdc294f836fddd7a54a148202ffbd50c2d4371816a94d8 crypto/ml_dsa/ml_dsa_matrix.c +6ac18f9ef27efc7fddc38ad5edec94fcf76a972ca9fcb6bdc5472673d885d238 crypto/ml_dsa/ml_dsa_matrix.c ff65c82c56e341f47df03d0c74de7fb537de0e68a4fa23fa07a9fdb51c511f1c crypto/ml_dsa/ml_dsa_matrix.h c2652262227348b8bb053a239e8491b26f08d6fadc47ba3471302f5797ae1c62 crypto/ml_dsa/ml_dsa_ntt.c 3e0980e67842c4d8637fa449ac41e9d650c614c1074c29f1021605d229a4f73d crypto/ml_dsa/ml_dsa_params.c 10e37ab3ee09a45d99007665e073efb2b062c819f30af8694c6b0f411eb33822 crypto/ml_dsa/ml_dsa_poly.h -26be5266a9f1a33999a5a68c96cffc7932ba64521d9554dabe7397591611c852 crypto/ml_dsa/ml_dsa_sample.c -26ce39dd4cdac0a1c00cee24d53e156c16a1577c71a8a96bce3e2b4130afa6f5 crypto/ml_dsa/ml_dsa_sign.c +abb4f2263fb9b6d08911e1b8e2df2c2de636d6255f7cf3eee594f50dedcefc0c crypto/ml_dsa/ml_dsa_sample.c +f1cbf5ebe46fe456e338a496193bf028d48a28bb3d4804591094babe84d83b25 crypto/ml_dsa/ml_dsa_sign.c 5217ef237e21872205703b95577290c34898423466a465c7bd609b2eb4627964 crypto/ml_dsa/ml_dsa_sign.h -8311e08d9d0e2e073092d0cfaf64851fb8d0f0708dfc2707422f525f87f269d0 crypto/ml_dsa/ml_dsa_vector.h -0fbbb11e30b7e3f4e5366334e273dcc3f6440ed04a0758f0c99279c25b8c0baf crypto/ml_kem/ml_kem.c +afc44b2cdf6a03555cebcc0398179b44f5810098d0b17dcb2b0c0c62023d6964 crypto/ml_dsa/ml_dsa_vector.h +dd95a5261fd1624e1e93270b0dc9404c887506a402d55521a5074975db833fd6 crypto/ml_kem/ml_kem.c 36e24eae5d38cc9666ae40e4e8a2dc12328e1159fea68447cb19dab174d25adf crypto/modes/asm/aes-gcm-armv8-unroll8_64.pl 33357356cd739d4ae89d52f0804b6900e4b94d8829323819c6f64c8908e978df crypto/modes/asm/aes-gcm-armv8_64.pl -a91995f81b384b175ecf252690030bb068d6af64bfcdab2fe753484b2d07a184 crypto/modes/asm/aes-gcm-avx512.pl +573c286991352233cb068d0e218c5cb1e6fe5d07a924496dbccca95fa82e1d4d crypto/modes/asm/aes-gcm-avx512.pl 8fab6574aa99ee635d564dbe68b014562b61af37fa4f151210690837cdae6707 crypto/modes/asm/aes-gcm-ppc.pl dd0de5ca8913a941cfff781a42fba43227e133976a24d0fddebf63909f7e010a crypto/modes/asm/aes-gcm-riscv64-zvkb-zvkg-zvkned.pl -9dcd3be86cda832ebe0394f5a859a761f4b711f2010fb606457f754722c5fb84 crypto/modes/asm/aesni-gcm-x86_64.pl +a4fad5a5cb112929323632e4f3f5fce7d6f0ceb6ea2e3ed1a4a2165f05fbf0b5 crypto/modes/asm/aesni-gcm-x86_64.pl c2e874a8deb418b5d8c935b2e256370566a5150e040c9fa008cdb5b463c26904 crypto/modes/asm/ghash-alpha.pl 6bc7d63569c73d7020ede481f2de05221ac92403c7cc11e7263ada7644f6aa9b crypto/modes/asm/ghash-armv4.pl 097975df63370de7ebea012d17de14fc1f361fb83acf03b432a99ae7d5bceb24 crypto/modes/asm/ghash-c64xplus.pl @@ -281,7 +281,7 @@ e6d6ce559210aee1e97f098683e290c221cc90f6f4f8047b331e8071a8387559 crypto/modes/a 92071f9c046f312c4eb7df483f385bc71ade863392e1acf3e821912bcc5cfaa7 crypto/modes/asm/ghash-s390x.pl 6af1a05981e1d41e4dea51e58938360e3abc4a4f58e179908242466d032b1a8a crypto/modes/asm/ghash-sparcv9.pl 26f55a57e77f774d17dfba93d757f78edfa3a03f68a71ffa37ccf3bfc468b1e2 crypto/modes/asm/ghash-x86.pl -487e23973c9c782d375a956da6231e91f450182d8822d3f86fd4924e143fed70 crypto/modes/asm/ghash-x86_64.pl +3d746cc0cf6cca866e34cdbbd79f5660244033fa440ed82aaaa9dd16cebf821f crypto/modes/asm/ghash-x86_64.pl a4e9f2e496bd9362b17a1b5989aa4682647cefcff6117f0607122a9e11a9dfd9 crypto/modes/asm/ghashp8-ppc.pl 92f17ee53bd40123358ce5b37bcd6063bfa7d6860dd734d4ac585249c03a6b32 crypto/modes/asm/ghashv8-armx.pl ca4be187fc1805d498f2adb823509f0519e214644029c18d331b5b01a0891a9d crypto/modes/cbc128.c @@ -312,7 +312,7 @@ ed6956c34da5127fbf8f1a067654b617c261039743a12fd1d296a1dd01b05c26 crypto/params_ fcafd9ac56254e921f43dda47aa6d19ff42b3461ff3a72e0bff1840793f96701 crypto/provider_core.c aa58d7800d3ccf2989b0de3c2e2710dfac36c88dc51659129897b0dfd2162527 crypto/provider_local.h 5ba2e1c74ddcd0453d02e32612299d1eef18eff8493a7606c15d0dc3738ad1d9 crypto/provider_predefined.c -5f077b3d3c0127c9051907f91b7184d18ad045452e0cd891937932c8fb1f129f crypto/rand/rand_lib.c +1e919f7f3c860eb21bf2f6f868dae076c64c53f1ad794c6764f69329724c3fc2 crypto/rand/rand_lib.c 9e162caba63741e3df4d0f1c49a7555263ebc120cfb643546ea7e34d3f5eb862 crypto/rand/rand_local.h dce7413b4c4e588c9a099c6fd7c6c9a397e034f259a2027d4ea8bdfe149164fa crypto/rcu_internal.h 0c1d3e0e857e9e4f84752a8ef0b619d8af0d81427b52facbd0174e685dac9a47 crypto/riscv32cpuid.pl @@ -322,7 +322,7 @@ f0c8792a99132e0b9c027cfa7370f45594a115934cdc9e8f23bdd64abecaf7fd crypto/rsa/rsa b1584c4a1a5f83a1fd43d854ce72bb11735aa34945f2b2f983228f36f27fdad2 crypto/rsa/rsa_backend.c 38a102cd1da1f6ca5a46e6a22f018237964336274385f5c70cbedcaa6997647e crypto/rsa/rsa_chk.c e762c599b17d5c89f4b1c9eb7d0ca1f04a95d815c86a3e72c30b231ce57fb199 crypto/rsa/rsa_crpt.c -e666568eadfd01ff3e435364dee2575fca7ff3e6855b2c258fa1e4d04239d933 crypto/rsa/rsa_gen.c +157eec6c45b95ed974324055f594885c50e33616af3af06efb558d651a786c69 crypto/rsa/rsa_gen.c f22bc4e2c3acab83e67820c906c1caf048ec1f0d4fcb7472c1bec753c75f8e93 crypto/rsa/rsa_lib.c 969a13b951b8a77337fef84437b1aeec49ab1c73ecbceeb4b0df2174ae16a9a2 crypto/rsa/rsa_local.h cf0b75cd54b61b9b9a290ef18d0ddce9fb26a029a54eb3f720d9b25188440f00 crypto/rsa/rsa_mp_names.c @@ -350,13 +350,13 @@ be1e7dd9998e3f31cfa6e1b17bc198aeec584a8b76820e38f71d51b05f8a9f2a crypto/sha/asm 79dec13ccbee4a6758a22d92bfd5694565416219e48b6894dfb63c6b0029ae28 crypto/sha/asm/keccak1600-s390x.pl 3fb93b9440f5c3008b5c876a8106acc5f8d38f1afedd79381f0befec7dd7d72b crypto/sha/asm/keccak1600-x86_64.pl 831b8b02ab25d78ba6300ce960d96c13439bfba5844e13061e19c4e25cbacc3d crypto/sha/asm/keccak1600p8-ppc.pl -75d832db9bf0e98e7a5c522169060a6dd276c5118cfb297fc3f1111f55cd4007 crypto/sha/asm/sha1-586.pl +131d338bc716d9b5d4c1d3e8de213aa621f7581f91ec0ee7e2e56a9a94f1822b crypto/sha/asm/sha1-586.pl c96e87d4f5311cd73bbdf499acc03418588be12426d878e157dd67e0099e0219 crypto/sha/asm/sha1-alpha.pl 695ef6f8041f37f4b39cb7099e9c7c3a29d6f823823df7333530d375f5f5e01b crypto/sha/asm/sha1-armv4-large.pl cb32284af92d99d7046b99dd5bbd894d53531f7b99d351235a939c542680193b crypto/sha/asm/sha1-armv8.pl 11d332b4e058e9fa418d6633316d2e9f9bf520a08b2d933e877bdf38b2edefcf crypto/sha/asm/sha1-c64xplus.pl 32ff0e701a7b8f25bcfe8477b20795de54f536527bd87d3ce694fd9aaae356d4 crypto/sha/asm/sha1-ia64.pl -de6c7e8c1e27779a8cf1ce2a04f487a3d4dc510d5ba240cd06128ecc8574e424 crypto/sha/asm/sha1-mb-x86_64.pl +9fdde42e62c5a5c0457316ac35e6f6f940061634ab1e44a1ef5cdbacb656d738 crypto/sha/asm/sha1-mb-x86_64.pl 0f5c63cf09e950d1b488935ab3b5562e3e9d5cd1a563fb88a41e3dae90a35e6d crypto/sha/asm/sha1-mips.pl b5ffd7b6dbb04c05de7efa2945adb67ea845e7e61a3bf163a532f7b6acdf4267 crypto/sha/asm/sha1-parisc.pl 482cd23ca6ec38d6f62b90c68f9f20643579c50f2c0fbb0dab1c10a0e35efe77 crypto/sha/asm/sha1-ppc.pl @@ -364,11 +364,11 @@ b5ffd7b6dbb04c05de7efa2945adb67ea845e7e61a3bf163a532f7b6acdf4267 crypto/sha/asm 7fd355b412ddfa1c510e0ba3284f75b1c0d621b6db2ecb1d2a935d5cdb706628 crypto/sha/asm/sha1-sparcv9.pl 24554e68b0e7b7db7b635ff149549015f623ca0bcd9ae90439586a2076f6ae80 crypto/sha/asm/sha1-sparcv9a.pl 74d197cdd72400cabbff7e173f72c8976723081508b095dc995e8cd1abf3daa6 crypto/sha/asm/sha1-thumb.pl -dc363497de4fa3bc88b16e834ddf4967aecabdba5ea3ddd6113cf00da7e278bd crypto/sha/asm/sha1-x86_64.pl -c099059ef107f548ea2c2bab64a4eb8c277070ce6d74c4d32bb9808dc19c5fa3 crypto/sha/asm/sha256-586.pl +a579c0ab82151f8879bac23ef1ffb198dfbf9b02d2015c500a232baafc6a3722 crypto/sha/asm/sha1-x86_64.pl +494390ee974a00a0bfdb0ee46116efa45379b5e63988c0a3be9ff6183be2359d crypto/sha/asm/sha256-586.pl 0f01f7b5b0699f1e8ca260439d009febfa5b85b9e7b0933d236467e383aaaa2e crypto/sha/asm/sha256-armv4.pl 93ddc97651ee3e779144a3c6b3e46a1bc4aa81e75cd7b9df068a2aef8743d25f crypto/sha/asm/sha256-c64xplus.pl -9a68b6642b20e3cdccd636c4a934a6e0114160506784583f684ad65aefac2872 crypto/sha/asm/sha256-mb-x86_64.pl +478035fb599566f468f68ae9a3c5311b1e9c6257de6c47a7a32082c8aee41c8d crypto/sha/asm/sha256-mb-x86_64.pl b14670492f24cd0d2fedf8780e981b7da123203395c085334d4571b619b0a610 crypto/sha/asm/sha256-riscv64-zvkb-zvknha_or_zvknhb.pl dd82e1311703abb019975fc7b61fb87d67e1ed916dddd065aced051e851114b9 crypto/sha/asm/sha512-586.pl 16e68ac669860c5bf8e4db81cd3d64fc2c22168e129c2597e94b0f56fafcdfa8 crypto/sha/asm/sha512-armv4.pl @@ -381,7 +381,7 @@ fb06844e7c3b014a58dccc8ec6020c71843cfdc5be08288bc7d204f0a840c474 crypto/sha/asm 07804b96dda856cffaef291641c4ae7f59288ed1e65e38823cfdcb74f8ac5295 crypto/sha/asm/sha512-riscv64-zvkb-zvknhb.pl 38e0455fd6a2b93a7a5385379ca92bc6526585ca1eb4af365fac4c78f7285c72 crypto/sha/asm/sha512-s390x.pl 0611845c52091b0208dd41f22ddef9dd1e68d3d92fa4c4360738b840a6314de6 crypto/sha/asm/sha512-sparcv9.pl -473874a27b031e3d6c3dd0388c7231aa299e07c5832fa7499a081488e6f5680a crypto/sha/asm/sha512-x86_64.pl +14b563ed790d9bd76b0f45e27b75b5fa46d393d7bea8704d2894004adc3f4ac6 crypto/sha/asm/sha512-x86_64.pl 8725cabb8d695c576619f19283b034074a3fa0f1c0be952a9dbe9793be15b907 crypto/sha/asm/sha512p8-ppc.pl 93858e3b530333a129127b8df8cd3326cf55b770238b4fff2474c4e6e3def1dd crypto/sha/keccak1600.c 306cacd3f86e5cacaca74c58ef862516515e5c0cafaff48636d537fd84f1c2fb crypto/sha/sha1dgst.c @@ -391,19 +391,19 @@ a7e074a2f2cea0c33e7875eacc8adb465b5802e4c1d100cda79ac3dd52cdb453 crypto/sha/sha 61ab6d7d7da9e65120ec59cfa9f5ede785502ae371696c3e4e04e039743ca111 crypto/sha/sha_local.h dfd99e02830973ab349409ac6ba0ee901ba7736216030965bd7e5a54356abd7c crypto/slh_dsa/slh_adrs.c c9b270de1259d9fa71a4d352786357bcf1dd3d22075edab84501e2f8e550b271 crypto/slh_dsa/slh_adrs.h -95d42ca839ff34a050a7006734a06c157ad259512c1a10b978e9f899efe69f12 crypto/slh_dsa/slh_dsa.c -ab7b580b1cba302c5675918b457794a3b3d00aac42297312d9447bc6f6a40b09 crypto/slh_dsa/slh_dsa_hash_ctx.c -892a5ed5213c0898882bfc42f72be2864b363cd62d08a3b337c20b4fa557bef0 crypto/slh_dsa/slh_dsa_key.c +26566d0e641456101bd17338dbbb16f59dfacd34f76cff5882133a0ab7323130 crypto/slh_dsa/slh_dsa.c +6b88a8ca514dd2ead7808bf08ea7c7e89125cdcfae8f0db4f3518069382fdfa0 crypto/slh_dsa/slh_dsa_hash_ctx.c +924e686178fdc5984d1a09b02d91e04d4b9c4eb818ee384107ca64357c237e39 crypto/slh_dsa/slh_dsa_key.c 4c7981f7db69025f52495c549fb3b3a76be62b9e13072c3f3b7f1dedeaf8cc91 crypto/slh_dsa/slh_dsa_key.h -5dcb631891eb6afcd27a6b19d2de4d493c71dab159e53620d86d9b96642e97e8 crypto/slh_dsa/slh_dsa_local.h -adb3f4dea52396935b8442df7b36ed99324d3f3e8ce3fdf714d6dfd683e1f9f0 crypto/slh_dsa/slh_fors.c -5d3855cb2927efa4b28fec4357694bf863ac8dc6556009bdfa800ba16cb80b4d crypto/slh_dsa/slh_hash.c +f8007c0f93908810f138f872809cd49013e22192907f4c38d290b6c4566230f5 crypto/slh_dsa/slh_dsa_local.h +6d3f3c0be706c1dd871db863f2344f709a2b7fbb60a0d91298aeb2222f767a87 crypto/slh_dsa/slh_fors.c +f6f5286c6ce9f37cbb527144ec09fd86ae796ac3e71f0bdbb45b5a08a0692122 crypto/slh_dsa/slh_hash.c 3af167addbfd97f831f2a1981133bf4e2b62b95dc9477767797f7e4a653556db crypto/slh_dsa/slh_hash.h -6402664fbb259808a6f7b5a5d6be2b4a3cc8a905399d97b160cdb3e4a97c02c4 crypto/slh_dsa/slh_hypertree.c +1eebf59ebd0859be5a8deddd2f664f99158060904234532af608a44dd6d92d19 crypto/slh_dsa/slh_hypertree.c 1ce9b4f4f90a6f82005c9cdc0ea1f6b6876556c76f8bfd95f4c003a1c195a266 crypto/slh_dsa/slh_params.c 86b16a2c36d708cb880ba49648bb3051c2997188c8ea6aec9292534b97232c7f crypto/slh_dsa/slh_params.h -1aa9dc1c6fe59d024485df9a6b782ac4d0656a31b12faee749fe098911799eaf crypto/slh_dsa/slh_wots.c -59db81a3342c0c89b030756168b9a7f09c938b2cd3498335108e0a32c041b6e7 crypto/slh_dsa/slh_xmss.c +668a2431034f8c604970ed531e32b7b20b6b710e258d1db0a8eb06a13d900f0e crypto/slh_dsa/slh_wots.c +37fff5f88dd8bcd0ad8cdbab130c5a9a018422fe59b141bdb11bcee8fd1b046f crypto/slh_dsa/slh_xmss.c 9ef5a01caccc2eb15f72e367d0424737040ac8018479bbbbce3d216c655765c2 crypto/sparccpuid.S b462d1efe0acd798e1ec5f37fd1c824a587e1773e6a6f984d5a332581573ecbc crypto/sparcv9cap.c 9e16e8641ac5ec2cb2fcc8e4796af5b698d6fa4ce85e374bd8f5b4edb51e6428 crypto/sparse_array.c @@ -417,7 +417,7 @@ f06b08138d73b834471abc4a3ba43b2be838f7196c937c3e933694d6cd69f74d crypto/thread/ 2e5955d706b96c487e4875ffbe208fac15bdca06b33cee916d5343978c14efa1 crypto/threads_lib.c b3743dfd1c13fe70dc57a5a0b2ec540ab3afa748699eb6ef36f56f4d36d06ef3 crypto/threads_none.c 7b97b0f57f6b7cac89c1b8bd03bee34fb39d33cfae1632e75571ba106a5b9442 crypto/threads_pthread.c -9dac146cda57fb53d9b9eb30ff1fc81090f5e62dbe05d4cd97ed11cf501fc78c crypto/threads_win.c +a4692ad34bd148e06344672e08a3ba928719ca5af4d11ba54d97926759dcda0b crypto/threads_win.c 93f8fe09f96492a6be6772ddbf0cc37912fc2a90acb7faea378da1735fe20f6f crypto/time.c 88c5f9f4d2611223d283ebd2ae10ae5ecbb9972d00f747d93fcb74b62641e3f9 crypto/x86_64cpuid.pl 085d9fe93adf232f1ff838be9235046c2c2abe2daeb0e6342921d8f2e955dc18 crypto/x86cpuid.pl @@ -468,7 +468,7 @@ b41a5d9a7bdf60df169e327b41f16489830b82393dd663d1f89f81da4483eaa7 include/intern 9bafa62442fdeda25b97fdbe8e8bf8ea62a5b5167adb2ac7ebbb13db271673f9 include/internal/ffc.h 0a82ff0abab6ab815f9cb523b9643854346b47ff276f8868d1cbe48efc1b20ee include/internal/fips.h 923d4fb14a08f9b251b9bf9727bc50930d0279e8b63243faf85374bdcbbfc4e0 include/internal/hashfunc.h -a37a58d887ae4331a19179900b8d077afa1174c5152d53dc1533c37a65f319d6 include/internal/hashtable.h +d76c942d91e97f8954852ec7ae5a790a591b44762bba31930af585ed5f861fe0 include/internal/hashtable.h f6f30785e3eced1ccdd4b149286ff2b8bbb860eb7e070cbe54c997aa022854da include/internal/namemap.h c367e6120d26a2b629f4db7e179973e33fb095e1102d5c7a69c744b88ebe4469 include/internal/nelem.h eef3ec603b9877bd24a8fa1dbcd7752618fa74943b045515720bb0ca61394ae5 include/internal/numbers.h @@ -568,7 +568,7 @@ a481e8762c694b3dac0e74aac8626fe60fa94962a14914f1f6969ea1214c40b1 include/openss 9e04a3e9ca5352adffbdd75a5ea5237e8ff96a8c0a842368cc3a29de006b2ee7 include/openssl/types.h 62e0cddeedfc217ac02bf37f3669ccea8d0822a88a74a8ec82b844a85b2700aa include/openssl/x509.h.in 869959c3d557d2ace84f38b7a8d0f23b3b0854de7f952f46310e828af04554dd include/openssl/x509_vfy.h.in -5dbee881fe4e1f08a773e8bd34eeda7639be7c474a3d4d6e7c8d779e19c7eb2a include/openssl/x509err.h +53a45ca5d00026ef0a256f7ff27f5708d5af0a44177a0fc4b209ec054d44e18c include/openssl/x509err.h c0a9551efccf43f3dd748d4fd8ec897ddaabbc629c00ec1ad76ce983e1195a13 providers/common/bio_prov.c 6d25e1b61731cc558c2f801350d0cd874d3c19a3b0a03f52394c11fcaf2d51a5 providers/common/capabilities.c f94b7435d4ec888ec30df1c611afa8b9eedbb59e905a2c7cb17cfc8c4b9b85b8 providers/common/der/der_digests_gen.c.in @@ -611,7 +611,7 @@ b10730f4d302344579c09f43d5f9c5538bb6b4acd60de7430c24269fc522d5a5 providers/comm e2f8f00519d81aa16f1c30e8cbf9a0d8e898a1cb5c8b38bb01dd9ab513e34c9e providers/common/securitycheck_fips.c abd5997bc33b681a4ab275978b92aebca0806a4a3f0c2f41dacf11b3b6f4e101 providers/fips/fips_entry.c d8cb05784ae8533a7d9569d4fbaaea4175b63a7c9f4fb0f254215224069dea6b providers/fips/fipsindicator.c -0c473190a4b6809caed57997e44ee9ec949bcf01c542633e2881d07c809d3a51 providers/fips/fipsprov.c +f0f1486219ddb5817b5105c36f384cb9ef095ddceec50966fe178f4b4177028c providers/fips/fipsprov.c 8f52eead96febbce9e7f2bf5aaea557efe8f94ce078044959e80e5ae78432539 providers/fips/include/fips/fipsindicator.h ef204adc49776214dbb299265bc4f2c40b48848cbea4c25b8029f2b46a5c9797 providers/fips/include/fips_indicator_params.inc f2581d7b4e105f2bb6d30908f3c2d9959313be08cec6dbeb49030c125a7676d3 providers/fips/include/fips_selftest_params.inc @@ -639,7 +639,7 @@ be18c20e0197f25fe7b9e0268657a2271a69d216b89cb100f082fa5fcaad1e07 providers/impl 60c4f604cf9b5457be48f31cc24ca21729660381081b2dbf99f362a013a09684 providers/implementations/ciphers/cipher_aes_gcm_hw_vaes_avx512.inc e2886780637db72b12c9bc488d81647ed55a7f5c850efd4bdbf88ef7127e1913 providers/implementations/ciphers/cipher_aes_hw.c 89de794c090192459d99d95bc4a422e7782e62192cd0fdb3bdef4128cfedee68 providers/implementations/ciphers/cipher_aes_hw_aesni.inc -eac58fff6aa9918d657228c2707f1b3f0ef8f1210c97575f3c264db78bfd996f providers/implementations/ciphers/cipher_aes_ocb.c +b88e88831695dfc165ce83e64802ffb8240f1f696d9c67f350b9ff1b2e913212 providers/implementations/ciphers/cipher_aes_ocb.c 88138a1aff9705e608c0557653be92eb4de65b152555a2b79ec8b2a8fae73e8f providers/implementations/ciphers/cipher_aes_ocb.h 6c3a89771719b36d6917d23464be5441836378393731af96ba165fd788df1a41 providers/implementations/ciphers/cipher_aes_ocb_hw.c c7aac28a9dca1ad46e5bce4de93e07dffec1f89fab82394c3ff7cf1bda8b483f providers/implementations/ciphers/cipher_aes_wrp.c @@ -655,7 +655,7 @@ dc4626becaabc3990549483d9ef5f05c7dd9a9c2cf9be96ade3ba6a6e203f7f5 providers/impl cca34f1c7baf3a98964f7ce19a59e06d1eaf2ada121a0d4a438f4078a072b325 providers/implementations/ciphers/cipher_tdes_hw.c d2f418806c7ed45f118683bc13329573804592684e522efced0fd0921f4548fd providers/implementations/ciphers/ciphercommon.c ab9a2edb23aa61cf31da6addd8674a6028f93399eceeeee35a56ee770338fd6c providers/implementations/ciphers/ciphercommon_block.c -6b6090c233ddf29d819f2559361aeeae03505de7626a127628d5f0f6d3bce295 providers/implementations/ciphers/ciphercommon_ccm.c +fafb07c3fd77a89cff1d2efbb6edc0767132fc30c57f9e282080da04e6762499 providers/implementations/ciphers/ciphercommon_ccm.c 6632a555d5bcd5af67d0355ce46c2906bb3a0dcdf1651595b29189c40a5ca675 providers/implementations/ciphers/ciphercommon_ccm_hw.c ab51261da6aea5a3cca74a7561e4b89e6ce83f2ac497a5c766ecd3c3bff95152 providers/implementations/ciphers/ciphercommon_gcm.c bb67eaa7a98494ca938726f9218213870fc97dd87b56bda950626cc794baf20b providers/implementations/ciphers/ciphercommon_gcm_hw.c @@ -692,39 +692,39 @@ abe2b0f3711eaa34846e155cffc9242e4051c45de896f747afd5ac9d87f637dc providers/impl a9a5a3ba575b1a372f5a09135667ac1b0e303f8b19b0707804390aba9e266eca providers/implementations/kdfs/sskdf.c f01cbd7c5351d4aa9ae667627503b2cfef6fc0695e7a42296b7bf015c9a418b3 providers/implementations/kdfs/tls1_prf.c 39207243a84beb670cb0e64b6d0fe7bfc6a3dd84000617b647a3ecf52a1da3c2 providers/implementations/kdfs/x942kdf.c -748af266d06006da10524f3a621c65b8c3eeddf8b1ccd06ecdc6b689564d220c providers/implementations/kem/ml_kem_kem.c -35549cec7031452bb5b46aa8a86028abc7a3a2b39f9f6564fa4bd402451bc647 providers/implementations/kem/mlx_kem.c -e89b894af920504160abfc11860b89b505d116d978162a02213f72500180903b providers/implementations/kem/rsa_kem.c -aa13d72bc69a374db72b6d44e2f2c2ddd5f7bddbe16b950e3c4666d876c63735 providers/implementations/keymgmt/dh_kmgmt.c +b1431361b8a3448b73f4a46c48b3a4f9fd378c2abba67563f4407b1c7f007fca providers/implementations/kem/ml_kem_kem.c +926e08e60171cc867220e0f106533ed155132a034690bddea1e7793a879ebf73 providers/implementations/kem/mlx_kem.c +ff22e920552b82db3dab51b09f9dd2fd038ef0d57fb76cea5578e703653d28c9 providers/implementations/kem/rsa_kem.c +6599ad60eef3554741e049c3ff1bd9cc6064d4f3d1835e1ea5dec3a0c14c80bb providers/implementations/keymgmt/dh_kmgmt.c c0446d1b2101ddd977063516b87d23f424cdca33473f293db4c3974b674169b0 providers/implementations/keymgmt/dsa_kmgmt.c -2b98ba2124a86eae2adc7b88bfa26e47b548e9628b99180cc2cd841eed5ed8da providers/implementations/keymgmt/ec_kmgmt.c +45480796e6ea50cbe9529c17f9fa04228a9126dc7e7e32971519eeb6d6ac267c providers/implementations/keymgmt/ec_kmgmt.c 258ae17bb2dd87ed1511a8eb3fe99eed9b77f5c2f757215ff6b3d0e8791fc251 providers/implementations/keymgmt/ec_kmgmt_imexport.inc -167cd7df056bf46f3481cf6101fb6cfca55dea592f896c2b29649df1939885c4 providers/implementations/keymgmt/ecx_kmgmt.c +c559f1f265388e7b1c8195188fcc71ac8af09b3398530ec8ed7a9afd7b41281e providers/implementations/keymgmt/ecx_kmgmt.c daf35a7ab961ef70aefca981d80407935904c5da39dca6692432d6e6bc98759d providers/implementations/keymgmt/kdf_legacy_kmgmt.c 69b509e9c7fe9692622d1059917c3adb991c0047e11bc116f0a393a3a0539445 providers/implementations/keymgmt/mac_legacy_kmgmt.c -3c63e65bd1a6a2e853828205c015a50c38a82f2fee9bf6787dce6dab7331bb91 providers/implementations/keymgmt/ml_dsa_kmgmt.c -5c95eb8192483b2d81435e52aef6b2c96180bb22a67f717c29661a13b5861b02 providers/implementations/keymgmt/ml_kem_kmgmt.c -f37c8b7bb59d4b199889044992cb1b18ad39f2eafc87029f5348c55a95195e8c providers/implementations/keymgmt/mlx_kmgmt.c +7d197679dc4ae59f0e697749c56cb76399fc5eed88e94585dfd5ebdb23466e53 providers/implementations/keymgmt/ml_dsa_kmgmt.c +2df9ca1a68a9b6e1d1b108148b54ccf5454da3afa34e510beb2f4516e473e4c6 providers/implementations/keymgmt/ml_kem_kmgmt.c +4cec24edda3df01c08bef98a0a177ccdd1f8ba84e37c399dc568e010d7c0b29f providers/implementations/keymgmt/mlx_kmgmt.c cd4b8129eaccbd77f9b6c725d3cb57b71109c4649115ec786b6495100afaddf2 providers/implementations/keymgmt/rsa_kmgmt.c -d640cff1c46911b69866eb83f48beba42a1741bb1d3f1db6e7201077a57761fc providers/implementations/keymgmt/slh_dsa_kmgmt.c -9d02d481b9c7c0c9e0932267d1a3e1fef00830aaa03093f000b88aa042972b9f providers/implementations/macs/cmac_prov.c +92621573e975489b821884151d2de751e462fcf91efa83cb3bf8f4fd40cd241b providers/implementations/keymgmt/slh_dsa_kmgmt.c +2a66bc54579cb1fcd72674a1e60a7a1f798c13ab964a45e5603bed699268354f providers/implementations/macs/cmac_prov.c a3bb4d7914f45cf82f86cd92135e20a712274ca153d9ed5ad24db7f33710726c providers/implementations/macs/gmac_prov.c 2d6b8c42c67e3e43d8d0035463cbff590dabb7da815f9e437a3a72d4b6596319 providers/implementations/macs/hmac_prov.c 40686337be4261685f176bb10042d903d46ab10c90e10ac42d3842e9b5ddd960 providers/implementations/macs/kmac_prov.c 0ebc5a48655a697231918644397308e64914c32421e9b8ee7afd7779b6a2fdb8 providers/implementations/rands/drbg.c -d9e41abc1780bb253bdca6c58cc32af7d0a774e52c91fc5d64577f71defc52c2 providers/implementations/rands/drbg_ctr.c -cf98646defb0b385d6ce4bedcd51559c9a03424491f4576ea7eb41e3db8a18b3 providers/implementations/rands/drbg_hash.c -57561d4bd3a79e6a250310a989958409437dfa68b2818d5f0dbb8a5e7ef04bb7 providers/implementations/rands/drbg_hmac.c +d2805527aa28c27dc0d10f3e35b64e18626691b3c864806dd644b7dd1640ec49 providers/implementations/rands/drbg_ctr.c +e624059b1c9f878655d6a21a4c295c43d147ea913f638a2d007a1a68379180f8 providers/implementations/rands/drbg_hash.c +3aa1dd31f0db1ab0a7a5a3037f722e284587c244126810268622fae65bef77d7 providers/implementations/rands/drbg_hmac.c 841617c81d6d5eae5ea59064e8b45947d436d3e53b49283329d17016866d8f34 providers/implementations/rands/drbg_local.h 355bd437dde9ecd1da89f42691147f2b5cf9a012ff5f55062bf83b6bead1e181 providers/implementations/rands/fips_crng_test.c -4913fec58a2648fcec0e5a94dba9decab0505a6d725bed6eb861ce854db81df8 providers/implementations/rands/test_rng.c +90ea602ec88f7c0a78f3e7c801cdd3574a221f04497121a9ea7dcb05b7ee6765 providers/implementations/rands/test_rng.c c6c709dfd8b1be036e2a5232d3b21dc25f0150f2aae24cc7db6b09cd790a04ee providers/implementations/signature/dsa_sig.c d10d611713a6d9aa5cdbe636f1ba90404043431fd1df01fc1a1ce8499bf96ad0 providers/implementations/signature/ecdsa_sig.c a837f69cb1aa5d0327372e26a63a8492b6ffb1156325f66e880c202011d07cbe providers/implementations/signature/eddsa_sig.c e0e67e402ff19b0d2eb5228d7ebd70b9477c12595ac34d6f201373d7c8a516f4 providers/implementations/signature/mac_legacy_sig.c 51251a1ca4c0b6faea059de5d5268167fe47565163317177d09db39978134f78 providers/implementations/signature/ml_dsa_sig.c -94725f9e466c60c710900ca9878196f359e8421f46d5fb62fda91f5f845caff3 providers/implementations/signature/rsa_sig.c -539d3f55b8fd28826c786cb4e5c0e735173dc0faf268527ea007052be623cd37 providers/implementations/signature/slh_dsa_sig.c +6b293ca81102cd2f234d60f52f839e5bd7a746a42df3fe8a4489e6c214108f50 providers/implementations/signature/rsa_sig.c +ec630d49078bdd901132e7651eaf3478ff3b04e5558c435ffd7c77dcb62e46b3 providers/implementations/signature/slh_dsa_sig.c 21f537f9083f0341d9d1b0ace090a8d8f0b2b9e9cf76771c359b6ea00667a469 providers/implementations/skeymgmt/aes_skmgmt.c 2dbf9b8e738fad556c3248fb554ff4cc269ade3c86fa3d2786ba9b6d6016bf22 providers/implementations/skeymgmt/generic.c 9ba8db9b0e18847ef79ecb77fbc383d8762694be29dfb7d269df6f02dc977222 providers/implementations/skeymgmt/skeymgmt_lcl.h diff --git a/providers/fips.checksum b/providers/fips.checksum index 7d8252550bd4c..f236b8ff81a48 100644 --- a/providers/fips.checksum +++ b/providers/fips.checksum @@ -1 +1 @@ -f24213807982cf5d2859d5d1b78caa54c249ec28725645d1af28f092d543962d providers/fips-sources.checksums +ee77588030ee4df89ad9ff70a12118a9b89ebc4fde306fd25e9c01ef719d0b26 providers/fips-sources.checksums diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c index 419878719e98e..3c749018bcfc4 100644 --- a/providers/fips/fipsprov.c +++ b/providers/fips/fipsprov.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -56,7 +56,6 @@ extern OSSL_FUNC_core_thread_start_fn *c_thread_start; */ /* Functions provided by the core */ -static OSSL_FUNC_core_gettable_params_fn *c_gettable_params; static OSSL_FUNC_core_get_params_fn *c_get_params; OSSL_FUNC_core_thread_start_fn *c_thread_start; static OSSL_FUNC_core_new_error_fn *c_new_error; @@ -541,7 +540,7 @@ static const OSSL_ALGORITHM fips_asym_kem[] = { { PROV_NAMES_ML_KEM_1024, FIPS_DEFAULT_PROPERTIES, ossl_ml_kem_asym_kem_functions }, #if !defined(OPENSSL_NO_ECX) { "X25519MLKEM768", FIPS_DEFAULT_PROPERTIES, ossl_mlx_kem_asym_kem_functions }, - { "X448MLKEM1024", FIPS_DEFAULT_PROPERTIES, ossl_mlx_kem_asym_kem_functions }, + { "X448MLKEM1024", FIPS_UNAPPROVED_PROPERTIES, ossl_mlx_kem_asym_kem_functions }, #endif #if !defined(OPENSSL_NO_EC) { "SecP256r1MLKEM768", FIPS_DEFAULT_PROPERTIES, ossl_mlx_kem_asym_kem_functions }, @@ -608,7 +607,7 @@ static const OSSL_ALGORITHM fips_keymgmt[] = { #if !defined(OPENSSL_NO_ECX) { PROV_NAMES_X25519MLKEM768, FIPS_DEFAULT_PROPERTIES, ossl_mlx_x25519_kem_kmgmt_functions, PROV_DESCS_X25519MLKEM768 }, - { PROV_NAMES_X448MLKEM1024, FIPS_DEFAULT_PROPERTIES, ossl_mlx_x448_kem_kmgmt_functions, + { PROV_NAMES_X448MLKEM1024, FIPS_UNAPPROVED_PROPERTIES, ossl_mlx_x448_kem_kmgmt_functions, PROV_DESCS_X448MLKEM1024 }, #endif #if !defined(OPENSSL_NO_EC) @@ -771,9 +770,6 @@ int OSSL_provider_init_int(const OSSL_CORE_HANDLE *handle, case OSSL_FUNC_CORE_GET_LIBCTX: set_func(c_get_libctx, OSSL_FUNC_core_get_libctx(in)); break; - case OSSL_FUNC_CORE_GETTABLE_PARAMS: - set_func(c_gettable_params, OSSL_FUNC_core_gettable_params(in)); - break; case OSSL_FUNC_CORE_GET_PARAMS: set_func(c_get_params, OSSL_FUNC_core_get_params(in)); break; diff --git a/providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c b/providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c index bf3275f97b380..c1079e0e7874a 100644 --- a/providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c +++ b/providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c @@ -267,11 +267,17 @@ static int aes_gcm_siv_finish(PROV_AES_GCM_SIV_CTX *ctx) { int ret = 0; - if (ctx->enc) + if (ctx->enc) { + /* Generate the tag when Final is the first empty-message operation. */ + if (ctx->generated_tag == 0 + && aes_gcm_siv_encrypt(ctx, NULL, NULL, 0) == 0) + return 0; return ctx->generated_tag; - if (!ctx->generated_tag) - aes_gcm_siv_decrypt(ctx, NULL, NULL, 0); - ret = !CRYPTO_memcmp(ctx->tag, ctx->user_tag, sizeof(ctx->tag)); + } + if (ctx->generated_tag == 0 + && aes_gcm_siv_decrypt(ctx, NULL, NULL, 0) == 0) + return 0; + ret = CRYPTO_memcmp(ctx->tag, ctx->user_tag, sizeof(ctx->tag)) == 0; ret &= ctx->have_user_tag; return ret; } diff --git a/providers/implementations/ciphers/cipher_aes_ocb.c b/providers/implementations/ciphers/cipher_aes_ocb.c index 99254cb49a882..62e5a0c1a7665 100644 --- a/providers/implementations/ciphers/cipher_aes_ocb.c +++ b/providers/implementations/ciphers/cipher_aes_ocb.c @@ -509,6 +509,10 @@ static int aes_ocb_cipher(void *vctx, unsigned char *out, size_t *outl, if (!ossl_prov_is_running()) return 0; + /* NULL input indicates Final, which must generate or check the tag. */ + if (in == NULL) + return aes_ocb_block_final(vctx, out, outl, outsize); + if (outsize < inl) { ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); return 0; diff --git a/providers/implementations/ciphers/cipher_chacha20_poly1305.c b/providers/implementations/ciphers/cipher_chacha20_poly1305.c index 977f7000c289e..673e18702cf72 100644 --- a/providers/implementations/ciphers/cipher_chacha20_poly1305.c +++ b/providers/implementations/ciphers/cipher_chacha20_poly1305.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -30,11 +30,11 @@ static OSSL_FUNC_cipher_get_params_fn chacha20_poly1305_get_params; static OSSL_FUNC_cipher_get_ctx_params_fn chacha20_poly1305_get_ctx_params; static OSSL_FUNC_cipher_set_ctx_params_fn chacha20_poly1305_set_ctx_params; static OSSL_FUNC_cipher_cipher_fn chacha20_poly1305_cipher; +static OSSL_FUNC_cipher_update_fn chacha20_poly1305_update; static OSSL_FUNC_cipher_final_fn chacha20_poly1305_final; static OSSL_FUNC_cipher_gettable_ctx_params_fn chacha20_poly1305_gettable_ctx_params; static OSSL_FUNC_cipher_settable_ctx_params_fn chacha20_poly1305_settable_ctx_params; #define chacha20_poly1305_gettable_params ossl_cipher_generic_gettable_params -#define chacha20_poly1305_update chacha20_poly1305_cipher static void *chacha20_poly1305_newctx(void *provctx) { @@ -301,11 +301,6 @@ static int chacha20_poly1305_cipher(void *vctx, unsigned char *out, if (!ossl_prov_is_running()) return 0; - if (inl == 0) { - *outl = 0; - return 1; - } - if (outsize < inl) { ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); return 0; @@ -317,6 +312,24 @@ static int chacha20_poly1305_cipher(void *vctx, unsigned char *out, return 1; } +static int chacha20_poly1305_update(void *vctx, unsigned char *out, + size_t *outl, size_t outsize, + const unsigned char *in, size_t inl) +{ + /* + * A zero-length update is a no-op. Only EVP_Cipher() and Final produce or + * check the authentication tag. + */ + if (inl == 0) { + if (!ossl_prov_is_running()) + return 0; + *outl = 0; + return 1; + } + + return chacha20_poly1305_cipher(vctx, out, outl, outsize, in, inl); +} + static int chacha20_poly1305_final(void *vctx, unsigned char *out, size_t *outl, size_t outsize) { diff --git a/providers/implementations/ciphers/cipher_chacha20_poly1305_hw.c b/providers/implementations/ciphers/cipher_chacha20_poly1305_hw.c index 733547a7e7323..1bd0d6a5fc81c 100644 --- a/providers/implementations/ciphers/cipher_chacha20_poly1305_hw.c +++ b/providers/implementations/ciphers/cipher_chacha20_poly1305_hw.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -301,6 +301,8 @@ static int chacha20_poly1305_aead_cipher(PROV_CIPHER_CTX *bctx, if (in != NULL) { /* aad or text */ if (out == NULL) { /* aad */ + if (ctx->len.text != 0) + goto err; Poly1305_Update(poly, in, inl); ctx->len.aad += inl; ctx->aad = 1; diff --git a/providers/implementations/ciphers/ciphercommon_ccm.c b/providers/implementations/ciphers/ciphercommon_ccm.c index 2b5bddddeb78f..7a70b1b099957 100644 --- a/providers/implementations/ciphers/ciphercommon_ccm.c +++ b/providers/implementations/ciphers/ciphercommon_ccm.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -288,13 +288,19 @@ int ossl_ccm_stream_final(void *vctx, unsigned char *out, size_t *outl, size_t outsize) { PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx; - int i; + unsigned char dummy_in = 0, dummy_out = 0; if (!ossl_prov_is_running()) return 0; - i = ccm_cipher_internal(ctx, out, outl, NULL, 0); - if (i <= 0) + /* + * Encryption sets tag_set after processing the payload, while successful + * decryption clears iv_set. Use those transitions to avoid processing an + * operation twice. + */ + if (!ctx->key_set + || (ctx->iv_set && (!ctx->enc || !ctx->tag_set) + && ccm_cipher_internal(ctx, &dummy_out, outl, &dummy_in, 0) <= 0)) return 0; *outl = 0; @@ -309,6 +315,9 @@ int ossl_ccm_cipher(void *vctx, unsigned char *out, size_t *outl, size_t outsize if (!ossl_prov_is_running()) return 0; + if (in == NULL) + return ossl_ccm_stream_final(vctx, out, outl, outsize); + if (outsize < inl) { ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); return 0; diff --git a/providers/implementations/encode_decode/encode_key2ms.c b/providers/implementations/encode_decode/encode_key2ms.c index 362a806589e6a..2c9bff42bbba1 100644 --- a/providers/implementations/encode_decode/encode_key2ms.c +++ b/providers/implementations/encode_decode/encode_key2ms.c @@ -1,5 +1,5 @@ /* - * Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2020-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -65,10 +65,11 @@ static int write_pvk(struct key2ms_ctx_st *ctx, OSSL_CORE_BIO *cout, return ret; } +static OSSL_FUNC_encoder_newctx_fn key2ms_newctx; static OSSL_FUNC_encoder_freectx_fn key2ms_freectx; static OSSL_FUNC_encoder_does_selection_fn key2ms_does_selection; -static struct key2ms_ctx_st *key2ms_newctx(void *provctx) +static void *key2ms_newctx(void *provctx) { struct key2ms_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); diff --git a/providers/implementations/kem/ml_kem_kem.c b/providers/implementations/kem/ml_kem_kem.c index 722eadf228975..14c670784c544 100644 --- a/providers/implementations/kem/ml_kem_kem.c +++ b/providers/implementations/kem/ml_kem_kem.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -125,6 +125,7 @@ static int ml_kem_set_ctx_params(void *vctx, const OSSL_PARAM params[]) /* Possibly, but much less likely wrong type */ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SEED_LENGTH); + OPENSSL_cleanse((void *)ctx->entropy_buf, sizeof(ctx->entropy_buf)); ctx->entropy = NULL; return 0; } diff --git a/providers/implementations/kem/mlx_kem.c b/providers/implementations/kem/mlx_kem.c index 376b3342ddfa8..a917fa93d5ca7 100644 --- a/providers/implementations/kem/mlx_kem.c +++ b/providers/implementations/kem/mlx_kem.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -118,7 +118,7 @@ static int mlx_kem_encapsulate(void *vctx, unsigned char *ctext, size_t *clen, if (!mlx_kem_have_pubkey(key)) { ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); - goto end; + return 0; } encap_clen = key->minfo->ctext_bytes + key->xinfo->pubkey_bytes; encap_slen = ML_KEM_SHARED_SECRET_BYTES + key->xinfo->shsec_bytes; @@ -236,6 +236,10 @@ static int mlx_kem_encapsulate(void *vctx, unsigned char *ctext, size_t *clen, ret = 1; end: + /* Erase any partial shared secret on failure */ + if (ret == 0) + OPENSSL_cleanse(shsec, + ML_KEM_SHARED_SECRET_BYTES + key->xinfo->shsec_bytes); EVP_PKEY_free(xkey); EVP_PKEY_CTX_free(ctx); return ret; @@ -324,6 +328,10 @@ static int mlx_kem_decapsulate(void *vctx, uint8_t *shsec, size_t *slen, ret = 1; end: + /* Erase any partial shared secret on failure */ + if (ret == 0) + OPENSSL_cleanse(shsec, + ML_KEM_SHARED_SECRET_BYTES + key->xinfo->shsec_bytes); EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(xkey); return ret; diff --git a/providers/implementations/kem/rsa_kem.c b/providers/implementations/kem/rsa_kem.c index 78925809d9853..47f0c80c9443d 100644 --- a/providers/implementations/kem/rsa_kem.c +++ b/providers/implementations/kem/rsa_kem.c @@ -131,6 +131,7 @@ static int rsakem_init(void *vprsactx, void *vrsa, const char *desc) { PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + const BIGNUM *e = NULL; int protect = 0; if (!ossl_prov_is_running()) @@ -146,6 +147,18 @@ static int rsakem_init(void *vprsactx, void *vrsa, RSA_free(prsactx->rsa); prsactx->rsa = vrsa; + /* + * Reject the trivial public exponent e <= 1. The FIPS module enforces the + * full SP 800-56B §6.4.1.1 constraints via ossl_fips_ind_rsa_key_check() + * below; non-FIPS callers wanting the complete §6.4.2 vetting can use + * EVP_PKEY_public_check(). + */ + RSA_get0_key(prsactx->rsa, NULL, &e, NULL); + if (e == NULL || BN_cmp(e, BN_value_one()) <= 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return 0; + } + OSSL_FIPS_IND_SET_APPROVED(prsactx) if (!rsakem_set_ctx_params(prsactx, params)) return 0; @@ -389,6 +402,44 @@ static int rsasve_recover(PROV_RSA_CTX *prsactx, return 0; } +#ifndef FIPS_MODULE + /* + * Reject clearly degenerate ciphertexts, c in {0, 1, n-1}. + * + * SP 800-56B Rev 2, 7.1.2.1 requires RSADP to enforce 1 < c < n-1. In a + * FIPS build that bound is applied by the RSADP primitive itself (see + * crypto/rsa/rsa_ossl.c, guarded by FIPS_MODULE), where it is also needed + * for KTS-OAEP; the primitive does not apply it in a non-FIPS build, so + * enforce it here for RSASVE. Raise the same errors as the primitive so + * the behaviour matches in both builds; keep the two sites in step. + */ + { + const BIGNUM *n = RSA_get0_n(prsactx->rsa); + BIGNUM *c = BN_new(); + BIGNUM *nminus1 = BN_new(); + int reason = 0; + + if (n == NULL || c == NULL || nminus1 == NULL + || BN_bin2bn(in, (int)inlen, c) == NULL + || BN_copy(nminus1, n) == NULL + || !BN_sub_word(nminus1, 1)) { + BN_free(c); + BN_free(nminus1); + return 0; + } + if (BN_ucmp(c, BN_value_one()) <= 0) + reason = RSA_R_DATA_TOO_SMALL; + else if (BN_ucmp(c, nminus1) >= 0) + reason = RSA_R_DATA_TOO_LARGE_FOR_MODULUS; + BN_free(c); + BN_free(nminus1); + if (reason != 0) { + ERR_raise(ERR_LIB_RSA, reason); + return 0; + } + } +#endif + /* Step (3): out = RSADP((n,d), in) */ ret = RSA_private_decrypt(inlen, in, out, prsactx->rsa, RSA_NO_PADDING); if (ret > 0 && outlen != NULL) diff --git a/providers/implementations/keymgmt/dh_kmgmt.c b/providers/implementations/keymgmt/dh_kmgmt.c index 8a1afe7907b1a..eac99a4fed07d 100644 --- a/providers/implementations/keymgmt/dh_kmgmt.c +++ b/providers/implementations/keymgmt/dh_kmgmt.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -793,10 +793,8 @@ static void *dh_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) #ifdef FIPS_MODULE if (!ossl_fips_self_testing()) { ret = ossl_dh_check_pairwise(dh, 0); - if (ret <= 0) { - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); + if (ret <= 0) goto end; - } } #endif /* FIPS_MODULE */ } diff --git a/providers/implementations/keymgmt/ec_kmgmt.c b/providers/implementations/keymgmt/ec_kmgmt.c index 305dc3a6b831d..1d740307f6a45 100644 --- a/providers/implementations/keymgmt/ec_kmgmt.c +++ b/providers/implementations/keymgmt/ec_kmgmt.c @@ -1,5 +1,5 @@ /* - * Copyright 2020-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2020-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -847,8 +847,8 @@ static const OSSL_PARAM sm2_known_gettable_params[] = { OSSL_PARAM_int(OSSL_PKEY_PARAM_EC_DECODED_FROM_EXPLICIT_PARAMS, NULL), EC_IMEXPORTABLE_DOM_PARAMETERS, EC_IMEXPORTABLE_PUBLIC_KEY, - OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_EC_PUB_X, NULL, 0), - OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_EC_PUB_Y, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_PUB_X, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_PUB_Y, NULL, 0), EC_IMEXPORTABLE_PRIVATE_KEY, OSSL_PARAM_END }; @@ -1298,20 +1298,6 @@ static void *ec_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) if (gctx->group_check != NULL) ret = ret && ossl_ec_set_check_group_type_from_name(ec, gctx->group_check); -#ifdef FIPS_MODULE - if (ret > 0 - && !ossl_fips_self_testing() - && EC_KEY_get0_public_key(ec) != NULL - && EC_KEY_get0_private_key(ec) != NULL - && EC_KEY_get0_group(ec) != NULL) { - BN_CTX *bnctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(ec)); - - ret = bnctx != NULL && ossl_ec_key_pairwise_check(ec, bnctx); - BN_CTX_free(bnctx); - if (ret <= 0) - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); - } -#endif /* FIPS_MODULE */ if (ret) return ec; diff --git a/providers/implementations/keymgmt/ecx_kmgmt.c b/providers/implementations/keymgmt/ecx_kmgmt.c index 54af7a6a39568..42a0b9d7aa677 100644 --- a/providers/implementations/keymgmt/ecx_kmgmt.c +++ b/providers/implementations/keymgmt/ecx_kmgmt.c @@ -811,7 +811,6 @@ static void *ed25519_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) if (!key || ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)) return key; if (ecd_fips140_pairwise_test(key, ECX_KEY_TYPE_ED25519, 1) != 1) { - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); ossl_ecx_key_free(key); return NULL; } @@ -844,7 +843,6 @@ static void *ed448_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) if (!key || ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)) return key; if (ecd_fips140_pairwise_test(key, ECX_KEY_TYPE_ED448, 1) != 1) { - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); ossl_ecx_key_free(key); return NULL; } diff --git a/providers/implementations/keymgmt/ml_dsa_kmgmt.c b/providers/implementations/keymgmt/ml_dsa_kmgmt.c index 5ebeaae662bf2..70e943ff5a03e 100644 --- a/providers/implementations/keymgmt/ml_dsa_kmgmt.c +++ b/providers/implementations/keymgmt/ml_dsa_kmgmt.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -96,6 +96,7 @@ static int ml_dsa_pairwise_test(const ML_DSA_KEY *key) err: OSSL_SELF_TEST_onend(st, ret); OSSL_SELF_TEST_free(st); + OPENSSL_cleanse(sig, sizeof(sig)); return ret; } #endif @@ -283,10 +284,8 @@ static int ml_dsa_import(void *keydata, int selection, const OSSL_PARAM params[] #ifdef FIPS_MODULE if (res > 0) { res = ml_dsa_pairwise_test(key); - if (!res) { + if (!res) ossl_ml_dsa_key_reset(key); - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT_IMPORT); - } } #endif /* FIPS_MODULE */ return res; @@ -483,10 +482,8 @@ static void *ml_dsa_gen(void *genctx, int evp_type) goto err; } #ifdef FIPS_MODULE - if (!ml_dsa_pairwise_test(key)) { - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); + if (!ml_dsa_pairwise_test(key)) goto err; - } #endif return key; err: @@ -541,7 +538,7 @@ static void ml_dsa_gen_cleanup(void *genctx) if (gctx == NULL) return; - OPENSSL_cleanse(gctx->entropy, gctx->entropy_len); + OPENSSL_cleanse(gctx->entropy, sizeof(gctx->entropy)); OPENSSL_free(gctx->propq); OPENSSL_free(gctx); } diff --git a/providers/implementations/keymgmt/ml_kem_kmgmt.c b/providers/implementations/keymgmt/ml_kem_kmgmt.c index d95f021eef707..1422a3775c74a 100644 --- a/providers/implementations/keymgmt/ml_kem_kmgmt.c +++ b/providers/implementations/keymgmt/ml_kem_kmgmt.c @@ -109,10 +109,6 @@ static int ml_kem_pairwise_test(const ML_KEM_KEY *key, int key_flags) memset(out, 0, sizeof(out)); - /* - * The pairwise test is skipped unless either RANDOM or FIXED entropy PCTs - * are enabled. - */ if (key_flags & ML_KEM_KEY_RANDOM_PCT) { operation_result = ossl_ml_kem_encap_rand(ctext, v->ctext_bytes, secret, sizeof(secret), key); @@ -147,7 +143,10 @@ static int ml_kem_pairwise_test(const ML_KEM_KEY *key, int key_flags) v->algorithm_name); } #endif - OPENSSL_free(ctext); + OPENSSL_cleanse((void *)entropy, sizeof(entropy)); + OPENSSL_cleanse((void *)secret, sizeof(secret)); + OPENSSL_cleanse((void *)out, sizeof(out)); + OPENSSL_clear_free(ctext, v->ctext_bytes); return ret; } @@ -237,7 +236,7 @@ static int ml_kem_export(void *vkey, int selection, OSSL_CALLBACK *param_cb, { ML_KEM_KEY *key = vkey; OSSL_PARAM_BLD *tmpl = NULL; - OSSL_PARAM *params = NULL; + OSSL_PARAM *params = NULL, *p; const ML_KEM_VINFO *v; uint8_t *pubenc = NULL, *prvenc = NULL, *seedenc = NULL; size_t prvlen = 0, seedlen = 0; @@ -316,13 +315,19 @@ static int ml_kem_export(void *vkey, int selection, OSSL_CALLBACK *param_cb, goto err; ret = param_cb(params, cbarg); + /* + * OSSL_PARAM_free() only wipes the secure-heap data block, + * so wipe the key material copies held in the params first. + */ + for (p = params; p->key != NULL; p++) + OPENSSL_cleanse(p->data, p->data_size); OSSL_PARAM_free(params); err: OSSL_PARAM_BLD_free(tmpl); OPENSSL_secure_clear_free(seedenc, seedlen); OPENSSL_secure_clear_free(prvenc, prvlen); - OPENSSL_free(pubenc); + OPENSSL_clear_free(pubenc, v->pubkey_bytes); return ret; } @@ -477,9 +482,6 @@ static int ml_kem_import(void *vkey, int selection, const OSSL_PARAM params[]) res = ml_kem_key_fromdata(key, params, include_private); if (res > 0 && include_private && !ml_kem_pairwise_test(key, key->prov_flags)) { -#ifdef FIPS_MODULE - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT_IMPORT); -#endif ossl_ml_kem_key_reset(key); res = 0; } @@ -542,12 +544,15 @@ static void *ml_kem_load(const void *reference, size_t reference_sz) if (!ml_kem_pairwise_test(key, key->prov_flags)) goto err; } - OPENSSL_free(encoded_dk); + OPENSSL_clear_free(encoded_dk, key->vinfo->prvkey_bytes); + OPENSSL_cleanse((void *)seed, sizeof(seed)); return key; } err: - OPENSSL_free(encoded_dk); + if (key != NULL && key->vinfo != NULL) + OPENSSL_clear_free(encoded_dk, key->vinfo->prvkey_bytes); + OPENSSL_cleanse((void *)seed, sizeof(seed)); ossl_ml_kem_key_free(key); return NULL; } @@ -708,6 +713,7 @@ static int ml_kem_gen_set_params(void *vgctx, const OSSL_PARAM params[]) /* Possibly, but less likely wrong data type */ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SEED_LENGTH); + OPENSSL_cleanse((void *)gctx->seedbuf, sizeof(gctx->seedbuf)); gctx->seed = NULL; return 0; } @@ -768,8 +774,10 @@ static void *ml_kem_gen(void *vgctx, OSSL_CALLBACK *osslcb, void *cbarg) if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) return key; - if (seed != NULL && !ossl_ml_kem_set_seed(seed, ML_KEM_SEED_BYTES, key)) + if (seed != NULL && !ossl_ml_kem_set_seed(seed, ML_KEM_SEED_BYTES, key)) { + ossl_ml_kem_key_free(key); return NULL; + } genok = ossl_ml_kem_genkey(nopub, 0, key); /* Erase the single-use seed */ @@ -780,7 +788,6 @@ static void *ml_kem_gen(void *vgctx, OSSL_CALLBACK *osslcb, void *cbarg) if (genok) { #ifdef FIPS_MODULE if (!ml_kem_pairwise_test(key, ML_KEM_KEY_FIXED_PCT)) { - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); ossl_ml_kem_key_free(key); return NULL; } diff --git a/providers/implementations/keymgmt/mlx_kmgmt.c b/providers/implementations/keymgmt/mlx_kmgmt.c index 5d1902ce637ca..75267f88e7610 100644 --- a/providers/implementations/keymgmt/mlx_kmgmt.c +++ b/providers/implementations/keymgmt/mlx_kmgmt.c @@ -245,7 +245,7 @@ static int mlx_kem_export(void *vkey, int selection, OSSL_CALLBACK *param_cb, { MLX_KEY *key = vkey; OSSL_PARAM_BLD *tmpl = NULL; - OSSL_PARAM *params = NULL; + OSSL_PARAM *params = NULL, *p; size_t publen; size_t prvlen; int ret = 0; @@ -307,12 +307,18 @@ static int mlx_kem_export(void *vkey, int selection, OSSL_CALLBACK *param_cb, goto err; ret = param_cb(params, cbarg); + /* + * OSSL_PARAM_free() only wipes the secure-heap data block, + * so wipe the key material copies held in the params first. + */ + for (p = params; p->key != NULL; p++) + OPENSSL_cleanse(p->data, p->data_size); OSSL_PARAM_free(params); err: OSSL_PARAM_BLD_free(tmpl); OPENSSL_secure_clear_free(sub_arg.prvenc, prvlen); - OPENSSL_free(sub_arg.pubenc); + OPENSSL_clear_free(sub_arg.pubenc, publen); return ret; } @@ -562,12 +568,18 @@ static int mlx_kem_get_params(void *vkey, OSSL_PARAM params[]) selection |= OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS; /* Extract sub-component key material */ - if (!export_sub(&sub_arg, selection, key)) - return 0; - - if ((pub != NULL && sub_arg.pubcount != 2) - || (prv != NULL && sub_arg.prvcount != 2)) + if (!export_sub(&sub_arg, selection, key) + || (pub != NULL && sub_arg.pubcount != 2) + || (prv != NULL && sub_arg.prvcount != 2)) { + /* Erase any partial key material on failure */ + if (sub_arg.pubenc != NULL) + OPENSSL_cleanse(sub_arg.pubenc, + key->minfo->pubkey_bytes + key->xinfo->pubkey_bytes); + if (sub_arg.prvenc != NULL) + OPENSSL_cleanse(sub_arg.prvenc, + key->minfo->prvkey_bytes + key->xinfo->prvkey_bytes); return 0; + } return 1; } diff --git a/providers/implementations/keymgmt/slh_dsa_kmgmt.c b/providers/implementations/keymgmt/slh_dsa_kmgmt.c index 8a676213903f5..8799df6be6d52 100644 --- a/providers/implementations/keymgmt/slh_dsa_kmgmt.c +++ b/providers/implementations/keymgmt/slh_dsa_kmgmt.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -223,7 +223,7 @@ static int slh_dsa_export(void *keydata, int selection, OSSL_CALLBACK *param_cb, { SLH_DSA_KEY *key = keydata; OSSL_PARAM_BLD *tmpl; - OSSL_PARAM *params = NULL; + OSSL_PARAM *params = NULL, *p; int ret = 0; if (!ossl_prov_is_running() || key == NULL) @@ -244,6 +244,12 @@ static int slh_dsa_export(void *keydata, int selection, OSSL_CALLBACK *param_cb, goto err; ret = param_cb(params, cbarg); + /* + * OSSL_PARAM_free() only wipes the secure-heap data block, + * so wipe the key material copies held in the params first. + */ + for (p = params; p->key != NULL; p++) + OPENSSL_cleanse(p->data, p->data_size); OSSL_PARAM_free(params); err: OSSL_PARAM_BLD_free(tmpl); @@ -298,7 +304,7 @@ static int slh_dsa_fips140_pairwise_test(const SLH_DSA_KEY *key, uint8_t msg[16] = { 0 }; size_t msg_len = sizeof(msg); uint8_t *sig = NULL; - size_t sig_len; + size_t sig_len = 0; OSSL_LIB_CTX *lib_ctx; int alloc_ctx = 0; @@ -341,7 +347,7 @@ static int slh_dsa_fips140_pairwise_test(const SLH_DSA_KEY *key, err: if (alloc_ctx) ossl_slh_dsa_hash_ctx_free(ctx); - OPENSSL_free(sig); + OPENSSL_clear_free(sig, sig_len); OSSL_SELF_TEST_onend(st, ret); OSSL_SELF_TEST_free(st); return ret; @@ -366,10 +372,8 @@ static void *slh_dsa_gen(void *genctx, const char *alg) gctx->entropy, gctx->entropy_len)) goto err; #ifdef FIPS_MODULE - if (!slh_dsa_fips140_pairwise_test(key, ctx)) { - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); + if (!slh_dsa_fips140_pairwise_test(key, ctx)) goto err; - } #endif /* FIPS_MODULE */ ossl_slh_dsa_hash_ctx_free(ctx); return key; @@ -428,7 +432,7 @@ static void slh_dsa_gen_cleanup(void *genctx) if (gctx == NULL) return; - OPENSSL_cleanse(gctx->entropy, gctx->entropy_len); + OPENSSL_cleanse(gctx->entropy, sizeof(gctx->entropy)); OPENSSL_free(gctx->propq); OPENSSL_free(gctx); } diff --git a/providers/implementations/macs/cmac_prov.c b/providers/implementations/macs/cmac_prov.c index 58a842776233c..14542c6716f2c 100644 --- a/providers/implementations/macs/cmac_prov.c +++ b/providers/implementations/macs/cmac_prov.c @@ -1,5 +1,5 @@ /* - * Copyright 2018-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2018-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -275,7 +275,7 @@ static int cmac_set_ctx_params(void *vmacctx, const OSSL_PARAM params[]) && !EVP_CIPHER_is_a(cipher, "AES-192-CBC") && !EVP_CIPHER_is_a(cipher, "AES-128-CBC") && !EVP_CIPHER_is_a(cipher, "DES-EDE3-CBC")) { - ERR_raise(ERR_LIB_PROV, EVP_R_UNSUPPORTED_CIPHER); + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_SUPPORTED); return 0; } } diff --git a/providers/implementations/macs/poly1305_prov.c b/providers/implementations/macs/poly1305_prov.c index 22ff0a2837391..69d4444a58d7c 100644 --- a/providers/implementations/macs/poly1305_prov.c +++ b/providers/implementations/macs/poly1305_prov.c @@ -82,7 +82,7 @@ static size_t poly1305_size(void) static int poly1305_setkey(struct poly1305_data_st *ctx, const unsigned char *key, size_t keylen) { - if (keylen != POLY1305_KEY_SIZE) { + if (key == NULL || keylen != POLY1305_KEY_SIZE) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); return 0; } @@ -111,6 +111,10 @@ static int poly1305_update(void *vmacctx, const unsigned char *data, { struct poly1305_data_st *ctx = vmacctx; + if (!ctx->key_set) { + ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET); + return 0; + } ctx->updated = 1; if (datalen == 0) return 1; diff --git a/providers/implementations/rands/drbg_ctr.c b/providers/implementations/rands/drbg_ctr.c index d42f085857136..fa4a7400ffbd2 100644 --- a/providers/implementations/rands/drbg_ctr.c +++ b/providers/implementations/rands/drbg_ctr.c @@ -1,5 +1,5 @@ /* - * Copyright 2011-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2011-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -25,6 +25,12 @@ #include "internal/provider.h" #include "internal/common.h" +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) +# include +# endif +#endif + static OSSL_FUNC_rand_newctx_fn drbg_ctr_new_wrapper; static OSSL_FUNC_rand_freectx_fn drbg_ctr_free; static OSSL_FUNC_rand_instantiate_fn drbg_ctr_instantiate_wrapper; @@ -72,6 +78,12 @@ static void inc_128(PROV_DRBG_CTR *ctr) p[n] = (u8)c; c >>= 8; } while (n); + +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) + __msan_unpoison(p, 16); +# endif +#endif } static void ctr_XOR(PROV_DRBG_CTR *ctr, const unsigned char *in, size_t inlen) @@ -588,6 +600,18 @@ static int drbg_ctr_init(PROV_DRBG *drbg) drbg->strength = keylen * 8; drbg->seedlen = keylen + 16; +#ifdef FIPS_MODULE + /* + * FIPS requires that we use a derivation function since our + * entropy source is outside the fips boundary + */ + if (ctr->use_df == 0) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_DERIVATION_FUNCTION_INIT_FAILED, + "FIPS requires the use of a derivation function"); + goto err; + } +#endif + if (ctr->use_df) { /* df initialisation */ static const unsigned char df_key[32] = { @@ -713,7 +737,6 @@ static int drbg_ctr_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[]) PROV_DRBG *ctx = (PROV_DRBG *)vctx; PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)ctx->data; OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); - OSSL_PROVIDER *prov = NULL; const OSSL_PARAM *p; char *ecb; const char *propquery = NULL; @@ -731,19 +754,14 @@ static int drbg_ctr_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[]) != NULL) { if (p->data_type != OSSL_PARAM_UTF8_STRING) return 0; - propquery = (const char *)p->data; } - if ((p = OSSL_PARAM_locate_const(params, - OSSL_PROV_PARAM_CORE_PROV_NAME)) - != NULL) { - if (p->data_type != OSSL_PARAM_UTF8_STRING) - return 0; - if ((prov = ossl_provider_find(libctx, - (const char *)p->data, 1)) - == NULL) - return 0; - } +#ifndef FIPS_MODULE + propquery = "provider=default"; + if (p != NULL + && p->data_type == OSSL_PARAM_UTF8_STRING) + propquery = (const char *)p->data; +#endif if ((p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_CIPHER)) != NULL) { const char *base = (const char *)p->data; @@ -752,50 +770,33 @@ static int drbg_ctr_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[]) if (p->data_type != OSSL_PARAM_UTF8_STRING || p->data_size < ctr_str_len) { - ossl_provider_free(prov); return 0; } if (OPENSSL_strcasecmp("CTR", base + p->data_size - ctr_str_len) != 0) { ERR_raise(ERR_LIB_PROV, PROV_R_REQUIRE_CTR_MODE_CIPHER); - ossl_provider_free(prov); return 0; } if ((ecb = OPENSSL_strndup(base, p->data_size)) == NULL) { - ossl_provider_free(prov); return 0; } strcpy(ecb + p->data_size - ecb_str_len, "ECB"); EVP_CIPHER_free(ctr->cipher_ecb); EVP_CIPHER_free(ctr->cipher_ctr); + ctr->cipher_ctr = NULL; + ctr->cipher_ecb = NULL; /* * Try to fetch algorithms from our own provider code, fallback * to generic fetch only if that fails */ - (void)ERR_set_mark(); - ctr->cipher_ctr = evp_cipher_fetch_from_prov(prov, base, NULL); - if (ctr->cipher_ctr == NULL) { - (void)ERR_pop_to_mark(); - ctr->cipher_ctr = EVP_CIPHER_fetch(libctx, base, propquery); - } else { - (void)ERR_clear_last_mark(); - } - (void)ERR_set_mark(); - ctr->cipher_ecb = evp_cipher_fetch_from_prov(prov, ecb, NULL); - if (ctr->cipher_ecb == NULL) { - (void)ERR_pop_to_mark(); - ctr->cipher_ecb = EVP_CIPHER_fetch(libctx, ecb, propquery); - } else { - (void)ERR_clear_last_mark(); - } + ctr->cipher_ctr = EVP_CIPHER_fetch(libctx, base, propquery); + ctr->cipher_ecb = EVP_CIPHER_fetch(libctx, ecb, propquery); OPENSSL_free(ecb); if (ctr->cipher_ctr == NULL || ctr->cipher_ecb == NULL) { ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_FIND_CIPHERS); - ossl_provider_free(prov); return 0; } cipher_init = 1; } - ossl_provider_free(prov); if (cipher_init && !drbg_ctr_init(ctx)) return 0; diff --git a/providers/implementations/rands/drbg_hash.c b/providers/implementations/rands/drbg_hash.c index 92eb443c6e829..504af87d5e131 100644 --- a/providers/implementations/rands/drbg_hash.c +++ b/providers/implementations/rands/drbg_hash.c @@ -1,5 +1,5 @@ /* - * Copyright 2011-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2011-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -508,23 +508,22 @@ static const OSSL_PARAM *drbg_hash_gettable_ctx_params(ossl_unused void *vctx, static int drbg_fetch_digest_from_prov(const OSSL_PARAM params[], OSSL_LIB_CTX *libctx, - EVP_MD **digest) + EVP_MD **digest, + const char *propq) { - OSSL_PROVIDER *prov = NULL; const OSSL_PARAM *p; EVP_MD *md = NULL; int ret = 0; + const char *propquery = NULL; - if (digest == NULL) - return 0; +#ifndef FIPS_MODULE + if (propq == NULL) + propquery = "provider=default"; + else + propquery = propq; +#endif - if ((p = OSSL_PARAM_locate_const(params, - OSSL_PROV_PARAM_CORE_PROV_NAME)) - == NULL) - return 0; - if (p->data_type != OSSL_PARAM_UTF8_STRING) - return 0; - if ((prov = ossl_provider_find(libctx, (const char *)p->data, 1)) == NULL) + if (digest == NULL) return 0; p = OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_DIGEST); @@ -536,15 +535,13 @@ static int drbg_fetch_digest_from_prov(const OSSL_PARAM params[], if (p->data_type != OSSL_PARAM_UTF8_STRING) goto done; - md = evp_digest_fetch_from_prov(prov, (const char *)p->data, NULL); + md = EVP_MD_fetch(libctx, p->data, propquery); if (md) { EVP_MD_free(*digest); *digest = md; ret = 1; } - done: - ossl_provider_free(prov); return ret; } @@ -556,15 +553,24 @@ static int drbg_hash_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[] EVP_MD *prov_md = NULL; const EVP_MD *md; int md_size; + const OSSL_PARAM *p; if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE0, params, OSSL_DRBG_PARAM_FIPS_DIGEST_CHECK)) return 0; /* try to fetch digest from provider */ + p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_PROPERTIES); (void)ERR_set_mark(); - if (!drbg_fetch_digest_from_prov(params, libctx, &prov_md)) { + if (!drbg_fetch_digest_from_prov(params, libctx, &prov_md, + (p != NULL && p->data_type == OSSL_PARAM_UTF8_STRING) ? p->data : NULL)) { (void)ERR_pop_to_mark(); + /* + * Its possible for drbg_fetch_digest_from_prov to return 0 after having set prov_md + * so we need to ensure we free it here + */ + EVP_MD_free(prov_md); + /* fall back to full implementation search */ if (!ossl_prov_digest_load_from_params(&hash->digest, params, libctx)) return 0; diff --git a/providers/implementations/rands/drbg_hmac.c b/providers/implementations/rands/drbg_hmac.c index d3191e55a9291..87050764fe463 100644 --- a/providers/implementations/rands/drbg_hmac.c +++ b/providers/implementations/rands/drbg_hmac.c @@ -412,27 +412,25 @@ static const OSSL_PARAM *drbg_hmac_gettable_ctx_params(ossl_unused void *vctx, static int drbg_fetch_algs_from_prov(const OSSL_PARAM params[], OSSL_LIB_CTX *libctx, EVP_MAC_CTX **macctx, - EVP_MD **digest) + EVP_MD **digest, const char *propq) { - OSSL_PROVIDER *prov = NULL; const OSSL_PARAM *p; const char *digest_name = NULL; const char *hmac_name = NULL; EVP_MD *md = NULL; EVP_MAC *mac = NULL; - OSSL_PARAM mac_params[2], *mp = mac_params; + OSSL_PARAM mac_params[3], *mp = mac_params; int ret = 0; + const char *propquery = NULL; - if (macctx == NULL || digest == NULL) - return 0; +#ifndef FIPS_MODULE + if (propq == NULL) + propquery = "provider=default"; + else + propquery = propq; +#endif - if ((p = OSSL_PARAM_locate_const(params, - OSSL_PROV_PARAM_CORE_PROV_NAME)) - == NULL) - return 0; - if (p->data_type != OSSL_PARAM_UTF8_STRING) - return 0; - if ((prov = ossl_provider_find(libctx, (const char *)p->data, 1)) == NULL) + if (macctx == NULL || digest == NULL) return 0; p = OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_DIGEST); @@ -441,7 +439,7 @@ static int drbg_fetch_algs_from_prov(const OSSL_PARAM params[], ERR_raise(ERR_LIB_PROV, PROV_R_VALUE_ERROR); goto done; } - md = evp_digest_fetch_from_prov(prov, digest_name, NULL); + md = EVP_MD_fetch(libctx, p->data, propquery); if (md) { EVP_MD_free(*digest); *digest = md; @@ -467,12 +465,14 @@ static int drbg_fetch_algs_from_prov(const OSSL_PARAM params[], EVP_MAC_CTX_free(*macctx); *macctx = NULL; - mac = evp_mac_fetch_from_prov(prov, hmac_name, NULL); + mac = EVP_MAC_fetch(libctx, hmac_name, propquery); if (mac) { *macctx = EVP_MAC_CTX_new(mac); /* The context holds on to the MAC */ EVP_MAC_free(mac); *mp++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, (char *)digest_name, 0); + if (propquery) + *mp++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_PROPERTIES, (char *)propquery, 0); *mp = OSSL_PARAM_construct_end(); if (!EVP_MAC_CTX_set_params(*macctx, mac_params)) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MAC); @@ -484,7 +484,6 @@ static int drbg_fetch_algs_from_prov(const OSSL_PARAM params[], } done: - ossl_provider_free(prov); return ret; } @@ -496,15 +495,23 @@ static int drbg_hmac_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[] EVP_MD *prov_md = NULL; const EVP_MD *md; int md_size; + const OSSL_PARAM *p; if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE0, params, OSSL_DRBG_PARAM_FIPS_DIGEST_CHECK)) return 0; /* try to fetch mac and digest from provider */ + p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_PROPERTIES); (void)ERR_set_mark(); - if (!drbg_fetch_algs_from_prov(params, libctx, &hmac->ctx, &prov_md)) { + if (!drbg_fetch_algs_from_prov(params, libctx, &hmac->ctx, &prov_md, + (p != NULL && p->data_type == OSSL_PARAM_UTF8_STRING) ? p->data : NULL)) { (void)ERR_pop_to_mark(); + /* + * Its possible for drbg_fetch_algs_from_prov to return 0 and set prov_md here + * so we need to free prov_md to be leak free + */ + EVP_MD_free(prov_md); /* fall back to full implementation search */ if (!ossl_prov_digest_load_from_params(&hmac->digest, params, libctx)) return 0; diff --git a/providers/implementations/rands/seeding/rand_unix.c b/providers/implementations/rands/seeding/rand_unix.c index 80ae8173131db..ed82495e693fc 100644 --- a/providers/implementations/rands/seeding/rand_unix.c +++ b/providers/implementations/rands/seeding/rand_unix.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -351,8 +351,13 @@ static ssize_t syscall_random(void *buf, size_t buflen) * Note: Sometimes getentropy() can be provided but not implemented * internally. So we need to check errno for ENOSYS */ -#if !defined(__DragonFly__) && !defined(__NetBSD__) && !defined(__FreeBSD__) -#if defined(__GNUC__) && __GNUC__ >= 2 && defined(__ELF__) && !defined(__hpux) +# if !defined(__DragonFly__) && !defined(__NetBSD__) && !defined(__FreeBSD__) + + /// Disable the usage of "getentropy" function from libc (on static link time) to avoid dependency on too new libc version. + /// Otherwise, if we build ClickHouse on a system with new libc and run the built binary on a system with old libc, it will fail. + /// + /// Note that there is a fallback below to (1) runtime symbol lookup and (2) direct syscall, that are equivalent. +# if 0 && defined(__GNUC__) && __GNUC__>=2 && defined(__ELF__) && !defined(__hpux) extern int getentropy(void *buffer, size_t length) __attribute__((weak)); if (getentropy != NULL) { @@ -394,7 +399,7 @@ static ssize_t syscall_random(void *buf, size_t buflen) return getrandom(buf, buflen, 0); #elif (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(KERN_ARND) return sysctl_random(buf, buflen); -#elif defined(__wasi__) +#elif defined(__wasi__) || defined(__EMSCRIPTEN__) if (getentropy(buf, buflen) == 0) return (ssize_t)buflen; return -1; diff --git a/providers/implementations/rands/test_rng.c b/providers/implementations/rands/test_rng.c index 7942537879f1e..88e5fb982aed9 100644 --- a/providers/implementations/rands/test_rng.c +++ b/providers/implementations/rands/test_rng.c @@ -1,5 +1,5 @@ /* - * Copyright 2020-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2020-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include "prov/securitycheck.h" #include "prov/providercommon.h" #include "prov/provider_ctx.h" @@ -305,7 +305,7 @@ static int test_rng_enable_locking(void *vtest) if (t != NULL && t->lock == NULL) { t->lock = CRYPTO_THREAD_lock_new(); if (t->lock == NULL) { - ERR_raise(ERR_LIB_PROV, RAND_R_FAILED_TO_CREATE_LOCK); + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_CREATE_LOCK); return 0; } } diff --git a/providers/implementations/signature/rsa_sig.c b/providers/implementations/signature/rsa_sig.c index 28f3e15b59856..4980474ac03d8 100644 --- a/providers/implementations/signature/rsa_sig.c +++ b/providers/implementations/signature/rsa_sig.c @@ -591,7 +591,7 @@ rsa_signverify_init(PROV_RSA_CTX *prsactx, void *vrsa, break; default: - ERR_raise(ERR_LIB_RSA, PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + ERR_raise(ERR_LIB_PROV, PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return 0; } @@ -1015,7 +1015,13 @@ static int rsa_verify_recover(void *vprsactx, } ret = RSA_public_decrypt((int)siglen, sig, rout, prsactx->rsa, prsactx->pad_mode); - if (ret <= 0) { + /* + * RSA_public_decrypt() returns -1 on error and otherwise the number + * of recovered bytes, which may legitimately be zero for a raw + * PKCS#1 v1.5 signature that encodes an empty payload. Treat only + * a negative result as an error. + */ + if (ret < 0) { ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB); return 0; } @@ -1947,7 +1953,7 @@ static int rsa_sigalg_signverify_init(void *vprsactx, void *vrsa, /* PSS is currently not supported as a sigalg */ if (prsactx->pad_mode == RSA_PKCS1_PSS_PADDING) { - ERR_raise(ERR_LIB_RSA, PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + ERR_raise(ERR_LIB_PROV, PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return 0; } diff --git a/providers/implementations/signature/slh_dsa_sig.c b/providers/implementations/signature/slh_dsa_sig.c index c6d4e04c1b84d..6d43be32f4d2e 100644 --- a/providers/implementations/signature/slh_dsa_sig.c +++ b/providers/implementations/signature/slh_dsa_sig.c @@ -61,7 +61,7 @@ static void slh_dsa_freectx(void *vctx) ossl_slh_dsa_hash_ctx_free(ctx->hash_ctx); OPENSSL_free(ctx->propq); - OPENSSL_cleanse(ctx->add_random, ctx->add_random_len); + OPENSSL_cleanse(ctx->add_random, sizeof(ctx->add_random)); OPENSSL_free(ctx); } diff --git a/providers/implementations/storemgmt/file_store_any2obj.c b/providers/implementations/storemgmt/file_store_any2obj.c index f5553b97da37d..03560ab4902d6 100644 --- a/providers/implementations/storemgmt/file_store_any2obj.c +++ b/providers/implementations/storemgmt/file_store_any2obj.c @@ -1,5 +1,5 @@ /* - * Copyright 2020-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2020-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -191,6 +191,10 @@ static int msblob2obj_decode(void *vctx, OSSL_CORE_BIO *cin, int selection, ok = 0; mem_want = ossl_blob_length(bitlen, isdss, ispub); + + if (mem_want > BLOB_MAX_LENGTH) { + goto next; + } if (!BUF_MEM_grow(mem, mem_len + mem_want)) { ERR_raise(ERR_LIB_PEM, ERR_R_BUF_LIB); goto err; diff --git a/pyca-cryptography b/pyca-cryptography deleted file mode 160000 index 7e33b0e7739d6..0000000000000 --- a/pyca-cryptography +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7e33b0e7739d633c77b8c478620167f693ed13f4 diff --git a/python-ecdsa b/python-ecdsa deleted file mode 160000 index 4096fa0171592..0000000000000 --- a/python-ecdsa +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4096fa01715929e08b97e73f3173aee9d57f2a3f diff --git a/ssl/quic/quic_ackm.c b/ssl/quic/quic_ackm.c index 58318a123a858..5da8af882adee 100644 --- a/ssl/quic/quic_ackm.c +++ b/ssl/quic/quic_ackm.c @@ -1003,6 +1003,7 @@ static void ackm_on_pkts_acked(OSSL_ACKM *ackm, const OSSL_ACKM_TX_PKT *apkt) const OSSL_ACKM_TX_PKT *anext; QUIC_PN last_pn_acked = 0; OSSL_CC_ACK_INFO ainfo = { 0 }; + unsigned int is_inflight; for (; apkt != NULL; apkt = anext) { if (apkt->is_inflight) { @@ -1027,10 +1028,11 @@ static void ackm_on_pkts_acked(OSSL_ACKM *ackm, const OSSL_ACKM_TX_PKT *apkt) ainfo.tx_time = apkt->time; ainfo.tx_size = apkt->num_bytes; + is_inflight = apkt->is_inflight; anext = apkt->anext; apkt->on_acked(apkt->cb_arg); /* may free apkt */ - if (apkt->is_inflight) + if (is_inflight) ackm->cc_method->on_data_acked(ackm->cc_data, &ainfo); } } @@ -1133,6 +1135,38 @@ int ossl_ackm_on_tx_packet(OSSL_ACKM *ackm, OSSL_ACKM_TX_PKT *pkt) return 1; } +int ossl_ackm_on_tx_ack_only_packet(OSSL_ACKM *ackm, OSSL_ACKM_TX_PKT *pkt) +{ + struct tx_pkt_history_st *h; + unsigned int pkt_space; + + if (pkt == NULL || pkt->pkt_space >= QUIC_PN_SPACE_NUM) + return 0; + + /* + * A packet containing only an ACK frame must not be treated as + * in-flight or ack-eliciting; if it were, ossl_ackm_on_tx_packet() + * below would (correctly) perform bytes-in-flight/timer/CC bookkeeping + * for a packet we are about to discard from history, which would be + * incorrect. + */ + if (pkt->is_inflight || pkt->is_ack_eliciting) + return 0; + + pkt_space = pkt->pkt_space; + + /* + * No one can expect ACK for packet which carries ACK frames only + * (ack_only packet). The ACKM does not need to keep record for ack_only + * packet. For ack_only packet the ACKM manager must be updated by the + * highest packet number which got sent. + */ + h = get_tx_history(ackm, pkt_space); + h->highest_sent = pkt->pkt_num; + + return 1; +} + int ossl_ackm_on_rx_datagram(OSSL_ACKM *ackm, size_t num_bytes) { /* No-op on the client. */ @@ -1167,8 +1201,21 @@ int ossl_ackm_on_rx_ack_frame(OSSL_ACKM *ackm, const OSSL_QUIC_FRAME_ACK *ack, int pkt_space, OSSL_TIME rx_time) { OSSL_ACKM_TX_PKT *na_pkts, *lost_pkts; + struct tx_pkt_history_st *h = get_tx_history(ackm, pkt_space); int must_set_timer = 0; + /* + * RFC 9000 s. 13.1 recommends treating an acknowledgment for a packet we + * did not send as a PROTOCOL_VIOLATION, where detectable. The largest + * acknowledged PN is ack_ranges[0].end; if it exceeds the highest PN we have + * sent in this space, reject the ACK. Otherwise the peer-controlled value is + * stored into largest_acked_pkt below, which only ever increases and drives + * loss detection, so a single such ACK would permanently force every + * in-flight and subsequently-sent packet to be declared lost. + */ + if (ack->ack_ranges[0].end > h->highest_sent) + return 0; + if (ackm->largest_acked_pkt[pkt_space] == QUIC_PN_INVALID) ackm->largest_acked_pkt[pkt_space] = ack->ack_ranges[0].end; else diff --git a/ssl/quic/quic_impl.c b/ssl/quic/quic_impl.c index 97efa4908a496..13bb007fa49b4 100644 --- a/ssl/quic/quic_impl.c +++ b/ssl/quic/quic_impl.c @@ -410,6 +410,11 @@ static int expect_quic_cs(const SSL *s, QCTX *ctx) return expect_quic_as(s, ctx, QCTX_C | QCTX_S); } +static int expect_quic_cl(const SSL *s, QCTX *ctx) +{ + return expect_quic_as(s, ctx, QCTX_C | QCTX_L); +} + static int expect_quic_csl(const SSL *s, QCTX *ctx) { return expect_quic_as(s, ctx, QCTX_C | QCTX_S | QCTX_L); @@ -3643,6 +3648,33 @@ static int qc_getset_idle_timeout(QCTX *ctx, uint32_t class_, return ret; } +QUIC_TAKES_LOCK +static int qc_getset_max_pending_channels(QCTX *ctx, uint32_t class_, + uint64_t *p_value_out, uint64_t *p_value_in) +{ + int ret = 0; + uint64_t value_out = 0; + + qctx_lock(ctx); + + if (class_ == SSL_VALUE_CLASS_GENERIC && ctx->is_listener) { + value_out = ossl_quic_port_get_max_pending_channels(ctx->ql->port); + if (p_value_in != NULL) + ossl_quic_port_set_max_pending_channels(ctx->ql->port, *p_value_in); + ret = 1; + } else { + QUIC_RAISE_NON_NORMAL_ERROR(ctx, SSL_R_UNSUPPORTED_CONFIG_VALUE_CLASS, NULL); + ret = 0; + } + + qctx_unlock(ctx); + + if (ret && p_value_out != NULL) + *p_value_out = value_out; + + return ret; +} + QUIC_TAKES_LOCK static int qc_get_stream_avail(QCTX *ctx, uint32_t class_, int is_uni, int is_remote, @@ -3778,6 +3810,8 @@ static int expect_quic_for_value(SSL *s, QCTX *ctx, uint32_t id) case SSL_VALUE_STREAM_WRITE_BUF_USED: case SSL_VALUE_STREAM_WRITE_BUF_AVAIL: return expect_quic_cs(s, ctx); + case SSL_VALUE_QUIC_MAX_PENDING_CONNS: + return expect_quic_cl(s, ctx); default: return expect_quic_conn_only(s, ctx); } @@ -3799,6 +3833,8 @@ int ossl_quic_get_value_uint(SSL *s, uint32_t class_, uint32_t id, switch (id) { case SSL_VALUE_QUIC_IDLE_TIMEOUT: return qc_getset_idle_timeout(&ctx, class_, value, NULL); + case SSL_VALUE_QUIC_MAX_PENDING_CONNS: + return qc_getset_max_pending_channels(&ctx, class_, value, NULL); case SSL_VALUE_QUIC_STREAM_BIDI_LOCAL_AVAIL: return qc_get_stream_avail(&ctx, class_, /*uni=*/0, /*remote=*/0, value); @@ -3845,6 +3881,8 @@ int ossl_quic_set_value_uint(SSL *s, uint32_t class_, uint32_t id, case SSL_VALUE_EVENT_HANDLING_MODE: return qc_getset_event_handling(&ctx, class_, NULL, &value); + case SSL_VALUE_QUIC_MAX_PENDING_CONNS: + return qc_getset_max_pending_channels(&ctx, class_, NULL, &value); default: return QUIC_RAISE_NON_NORMAL_ERROR(&ctx, @@ -4915,6 +4953,11 @@ int ossl_quic_set_peer_token(SSL_CTX *ctx, BIO_ADDR *peer, ossl_quic_free_peer_token(old); } lh_QUIC_TOKEN_insert(c->cache, tok); + if (lh_QUIC_TOKEN_error(c->cache)) { + ossl_quic_free_peer_token(tok); + ossl_crypto_mutex_unlock(c->mutex); + return 0; + } ossl_crypto_mutex_unlock(c->mutex); return 1; @@ -5406,6 +5449,19 @@ QUIC_CHANNEL *ossl_quic_conn_get_channel(SSL *s) return ctx.qc->ch; } +QUIC_PORT *ossl_quic_listener_get_port(SSL *s) +{ + QCTX ctx; + + /* + * expect listerner only + */ + if (!expect_quic_listener(s, &ctx)) + return NULL; + + return ctx.ql->port; +} + int ossl_quic_set_diag_title(SSL_CTX *ctx, const char *title) { #ifndef OPENSSL_NO_QLOG diff --git a/ssl/quic/quic_port.c b/ssl/quic/quic_port.c index 200022ac2c564..aad9c3a5b3d56 100644 --- a/ssl/quic/quic_port.c +++ b/ssl/quic/quic_port.c @@ -93,6 +93,8 @@ typedef struct validation_token { */ #define ENCRYPTED_TOKEN_MAX_LEN (MARSHALLED_TOKEN_MAX_LEN + 16 + 12) +#define DEFAULT_MAX_PENDING_CONNS 256 + DEFINE_LIST_OF_IMPL(ch, QUIC_CHANNEL); DEFINE_LIST_OF_IMPL(incoming_ch, QUIC_CHANNEL); DEFINE_LIST_OF_IMPL(port, QUIC_PORT); @@ -110,6 +112,7 @@ QUIC_PORT *ossl_quic_port_new(const QUIC_PORT_ARGS *args) port->validate_addr = args->do_addr_validation; port->get_conn_user_ssl = args->get_conn_user_ssl; port->user_ssl_arg = args->user_ssl_arg; + port->max_pending_channels = DEFAULT_MAX_PENDING_CONNS; if (!port_init(port)) { OPENSSL_free(port); @@ -531,8 +534,10 @@ static QUIC_CHANNEL *port_make_channel(QUIC_PORT *port, SSL *tls, OSSL_QRX *qrx, * start by allocation and provisioning as much of the channel as we can */ ch = ossl_quic_channel_alloc(&args); - if (ch == NULL) + if (ch == NULL) { + ossl_qrx_free(qrx); return NULL; + } /* * Fixup the channel tls connection here before we init the channel @@ -1488,7 +1493,7 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg, QUIC_CHANNEL *ch = NULL, *new_ch = NULL; QUIC_CONN_ID odcid; uint8_t gen_new_token = 0; - OSSL_QRX *qrx = NULL; + OSSL_QRX *qrx = NULL, *qrx_ref; OSSL_QRX *qrx_src = NULL; OSSL_QRX_ARGS qrx_args = { 0 }; uint64_t cause_flags = 0; @@ -1581,6 +1586,9 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg, if (hdr.type != QUIC_PKT_TYPE_INITIAL) goto undesirable; + if (port->max_pending_channels > 0 && ossl_list_incoming_ch_num(&port->incoming_channel_list) >= port->max_pending_channels) + goto undesirable; + odcid.id_len = 0; /* @@ -1678,8 +1686,22 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg, } } + qrx_ref = NULL; + if (qrx != NULL) { + /* + * if we are here, then client is validated via retry packet + * (client sent a valid token). In this case the qrx has valid + * secrets set for QUIC initial level encryption. We can pass + * reference to qrx to newly created channel. + * + * Note: port_bind_channel()/channel becomes owner of qrx_ref. + */ + qrx_ref = ossl_qrx_newref(qrx); + if (qrx_ref == NULL) + goto undesirable; + } port_bind_channel(port, &e->peer, &hdr.dst_conn_id, - &odcid, qrx, &new_ch); + &odcid, qrx_ref, &new_ch); /* * if packet validates it gets moved to channel, we've just bound @@ -1694,19 +1716,19 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg, if (gen_new_token == 1) generate_new_token(new_ch, &e->peer); - if (qrx != NULL) { + if (qrx_src != NULL) { /* - * The qrx belongs to channel now, so don't free it. - */ - qrx = NULL; - } else { - /* - * We still need to salvage packets from almost forgotten qrx - * and pass them to channel. + * Time to reinject packets from qrx to channel before + * qrx will be destroyed here. */ while (ossl_qrx_read_pkt(qrx_src, &qrx_pkt) == 1) ossl_quic_channel_inject_pkt(new_ch, qrx_pkt); ossl_qrx_update_pn_space(qrx_src, new_ch->qrx); + /* + * transfer ownership back to qrx; + */ + qrx = qrx_src; + qrx_src = NULL; } /* @@ -1723,7 +1745,7 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg, */ undesirable: - ossl_qrx_free(qrx); + ossl_qrx_free(qrx); /* releases reference */ ossl_qrx_free(qrx_src); ossl_quic_demux_release_urxe(port->demux, e); } @@ -1760,3 +1782,13 @@ void ossl_quic_port_restore_err_state(const QUIC_PORT *port) ERR_clear_error(); OSSL_ERR_STATE_restore(port->err_state); } + +uint64_t ossl_quic_port_get_max_pending_channels(const QUIC_PORT *port) +{ + return port->max_pending_channels; +} + +void ossl_quic_port_set_max_pending_channels(QUIC_PORT *port, uint64_t max_pending_channels) +{ + port->max_pending_channels = max_pending_channels; +} diff --git a/ssl/quic/quic_port_local.h b/ssl/quic/quic_port_local.h index 3bad3fc3a3aa5..0cfc75da0ba1c 100644 --- a/ssl/quic/quic_port_local.h +++ b/ssl/quic/quic_port_local.h @@ -1,5 +1,5 @@ /* - * Copyright 2023-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2023-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -118,6 +118,7 @@ struct quic_port_st { /* AES-256 GCM context for token encryption */ EVP_CIPHER_CTX *token_ctx; + uint64_t max_pending_channels; }; #endif diff --git a/ssl/quic/quic_record_rx.c b/ssl/quic/quic_record_rx.c index 8897cc6c2df0d..0065f1c1e5735 100644 --- a/ssl/quic/quic_record_rx.c +++ b/ssl/quic/quic_record_rx.c @@ -171,6 +171,8 @@ struct ossl_qrx_st { ossl_msg_cb msg_callback; void *msg_callback_arg; SSL *msg_callback_ssl; + + uint32_t refcount; }; static RXE *qrx_ensure_free_rxe(OSSL_QRX *qrx, size_t alloc_len); @@ -212,6 +214,7 @@ OSSL_QRX *ossl_qrx_new(const OSSL_QRX_ARGS *args) qrx->short_conn_id_len = args->short_conn_id_len; qrx->init_key_phase_bit = args->init_key_phase_bit; qrx->max_deferred = args->max_deferred; + qrx->refcount = 1; return qrx; } @@ -247,13 +250,10 @@ void ossl_qrx_update_pn_space(OSSL_QRX *src, OSSL_QRX *dst) return; } -void ossl_qrx_free(OSSL_QRX *qrx) +static void qrx_destroy(OSSL_QRX *qrx) { uint32_t i; - if (qrx == NULL) - return; - /* Free RXE queue data. */ qrx_cleanup_rxl(&qrx->rx_free); qrx_cleanup_rxl(&qrx->rx_pending); @@ -267,6 +267,30 @@ void ossl_qrx_free(OSSL_QRX *qrx) OPENSSL_free(qrx); } +void ossl_qrx_free(OSSL_QRX *qrx) +{ + if (qrx == NULL) + return; + + qrx->refcount--; + if (qrx->refcount == 0) + qrx_destroy(qrx); +} + +OSSL_QRX *ossl_qrx_newref(OSSL_QRX *qrx) +{ + OSSL_QRX *rv_qrx; + + if (qrx != NULL && qrx->refcount != (uint32_t)~0) { + qrx->refcount++; + rv_qrx = qrx; + } else { + rv_qrx = NULL; + } + + return rv_qrx; +} + void ossl_qrx_inject_urxe(OSSL_QRX *qrx, QUIC_URXE *urxe) { /* Initialize our own fields inside the URXE and add to the pending list. */ diff --git a/ssl/quic/quic_rx_depack.c b/ssl/quic/quic_rx_depack.c index 7ab59f01a1cde..59d16b2f362c7 100644 --- a/ssl/quic/quic_rx_depack.c +++ b/ssl/quic/quic_rx_depack.c @@ -125,8 +125,19 @@ static int depack_do_frame_ack(PACKET *pkt, QUIC_CHANNEL *ch, } if (!ossl_ackm_on_rx_ack_frame(ch->ackm, &ack, - packet_space, received)) - goto malformed; + packet_space, received)) { + /* + * The ACK manager rejects the frame if it acknowledges a packet number + * we have not sent. RFC 9000 s. 13.1 recommends treating this as a + * PROTOCOL_VIOLATION connection error (distinct from a frame decoding + * error, which is handled at the malformed label below). + */ + ossl_quic_channel_raise_protocol_error(ch, + OSSL_QUIC_ERR_PROTOCOL_VIOLATION, + frame_type, + "ACK for unsent packet number"); + return 0; + } ++ch->diag_num_rx_ack; return 1; diff --git a/ssl/quic/quic_stream_map.c b/ssl/quic/quic_stream_map.c index 84ac6b714e382..da53d4b8054fa 100644 --- a/ssl/quic/quic_stream_map.c +++ b/ssl/quic/quic_stream_map.c @@ -168,6 +168,10 @@ QUIC_STREAM *ossl_quic_stream_map_alloc(QUIC_STREAM_MAP *qsm, s->send_final_size = UINT64_MAX; lh_QUIC_STREAM_insert(qsm->map, s); + if (lh_QUIC_STREAM_error(qsm->map)) { + OPENSSL_free(s); + return NULL; + } return s; } diff --git a/ssl/quic/quic_txp.c b/ssl/quic/quic_txp.c index 5ce8e77f61e08..24314f6b34b7b 100644 --- a/ssl/quic/quic_txp.c +++ b/ssl/quic/quic_txp.c @@ -2935,6 +2935,20 @@ static int txp_generate_for_el(OSSL_QUIC_TX_PACKETISER *txp, return TXP_ERR_INTERNAL; } +static int txp_pkt_is_ack_only(const QUIC_TXPIM_PKT *tpkt) +{ + return tpkt->had_ack_frame + && !tpkt->ackm_pkt.is_inflight + && !tpkt->ackm_pkt.is_ack_eliciting + && !tpkt->had_handshake_done_frame + && !tpkt->had_max_data_frame + && !tpkt->had_max_streams_bidi_frame + && !tpkt->had_max_streams_uni_frame + && !tpkt->had_conn_close + && tpkt->retx_head == NULL + && ossl_quic_txpim_pkt_get_num_chunks(tpkt) == 0; +} + /* * Commits and queues a packet for transmission. There is no backing out after * this. @@ -2943,8 +2957,9 @@ static int txp_generate_for_el(OSSL_QUIC_TX_PACKETISER *txp, * * - Sends the packet to the QTX for encryption and transmission; * - * - Records the packet as having been transmitted in FIFM. ACKM is informed, - * etc. and the TXPIM record is filed. + * - Records non-ACK-only packets as having been transmitted in FIFM. ACKM is + * informed, etc. and the TXPIM record is filed only when later callbacks + * need it. * * - Informs various subsystems of frames that were sent and clears frame * wanted flags so that we do not generate the same frames again. @@ -2971,7 +2986,7 @@ static int txp_pkt_commit(OSSL_QUIC_TX_PACKETISER *txp, uint32_t archetype, int *txpim_pkt_reffed) { - int rc = 1; + int ack_only, rc = 1; uint32_t enc_level = pkt->h.enc_level; uint32_t pn_space = ossl_quic_enc_level_to_pn_space(enc_level); QUIC_TXPIM_PKT *tpkt = pkt->tpkt; @@ -3015,28 +3030,35 @@ static int txp_pkt_commit(OSSL_QUIC_TX_PACKETISER *txp, return 0; /* alloc error */ } - /* Dispatch to FIFD. */ - if (!ossl_quic_fifd_pkt_commit(&txp->fifd, tpkt)) + ack_only = txp_pkt_is_ack_only(tpkt); + + /* Dispatch packets that need loss/retransmit callbacks to FIFD. */ + if (!ack_only && !ossl_quic_fifd_pkt_commit(&txp->fifd, tpkt)) return 0; /* * Transmission and Post-Packet Generation Bookkeeping * =================================================== * - * No backing out anymore - at this point the ACKM has recorded the packet - * as having been sent, so we need to increment our next PN counter, or - * the ACKM will complain when we try to record a duplicate packet with - * the same PN later. At this point actually sending the packet may still - * fail. In this unlikely event it will simply be handled as though it - * were a lost packet. + * No backing out anymore - at this point we need to increment our next PN + * counter, or the ACKM will complain when we try to record a duplicate + * packet with the same PN later. Non-ACK-only packets have also been + * recorded in ACKM, so if QTX write fails they are handled as though they + * were lost. ACK-only packets are not recorded and will be cleaned up by + * the caller. */ ++txp->next_pn[pn_space]; - *txpim_pkt_reffed = 1; + if (!ack_only) + *txpim_pkt_reffed = 1; /* Send the packet. */ if (!ossl_qtx_write_pkt(txp->args.qtx, &txpkt)) return 0; + if (ack_only + && !ossl_ackm_on_tx_ack_only_packet(txp->args.ackm, &tpkt->ackm_pkt)) + rc = 0; + /* * Record FC and stream abort frames as sent; deactivate streams which no * longer have anything to do. diff --git a/ssl/record/methods/dtls_meth.c b/ssl/record/methods/dtls_meth.c index 8cbd7678e193b..c282efc5ca077 100644 --- a/ssl/record/methods/dtls_meth.c +++ b/ssl/record/methods/dtls_meth.c @@ -1,5 +1,5 @@ /* - * Copyright 2018-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2018-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -287,7 +287,7 @@ static int dtls_rlayer_buffer_record(OSSL_RECORD_LAYER *rl, struct pqueue_st *qu pitem *item; /* Limit the size of the queue to prevent DOS attacks */ - if (pqueue_size(queue) >= 100) + if (pqueue_size(queue) >= 16) return 0; rdata = OPENSSL_malloc(sizeof(*rdata)); @@ -299,29 +299,26 @@ static int dtls_rlayer_buffer_record(OSSL_RECORD_LAYER *rl, struct pqueue_st *qu return -1; } - rdata->packet = rl->packet; + /* + * Take a copy of just this record's on-wire bytes (header + ciphertext) + * rather than the whole (much larger) read buffer. The live rl->rbuf is + * left untouched and continues to be used for subsequent reads. + */ rdata->packet_length = rl->packet_length; - memcpy(&(rdata->rbuf), &rl->rbuf, sizeof(TLS_BUFFER)); - memcpy(&(rdata->rrec), &rl->rrec[0], sizeof(TLS_RL_RECORD)); - - item->data = rdata; - - rl->packet = NULL; - rl->packet_length = 0; - memset(&rl->rbuf, 0, sizeof(TLS_BUFFER)); - memset(&rl->rrec[0], 0, sizeof(rl->rrec[0])); - - if (!tls_setup_read_buffer(rl)) { - /* RLAYERfatal() already called */ - OPENSSL_free(rdata->rbuf.buf); + rdata->packet = OPENSSL_memdup(rl->packet, rl->packet_length); + if (rdata->packet == NULL) { OPENSSL_free(rdata); pitem_free(item); + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_CRYPTO_LIB); return -1; } + memcpy(&(rdata->rrec), &rl->rrec[0], sizeof(TLS_RL_RECORD)); + + item->data = rdata; if (pqueue_insert(queue, item) == NULL) { /* Must be a duplicate so ignore it */ - OPENSSL_free(rdata->rbuf.buf); + OPENSSL_free(rdata->packet); OPENSSL_free(rdata); pitem_free(item); } @@ -329,44 +326,6 @@ static int dtls_rlayer_buffer_record(OSSL_RECORD_LAYER *rl, struct pqueue_st *qu return 1; } -/* copy buffered record into OSSL_RECORD_LAYER structure */ -static int dtls_copy_rlayer_record(OSSL_RECORD_LAYER *rl, pitem *item) -{ - DTLS_RLAYER_RECORD_DATA *rdata; - - rdata = (DTLS_RLAYER_RECORD_DATA *)item->data; - - ossl_tls_buffer_release(&rl->rbuf); - - rl->packet = rdata->packet; - rl->packet_length = rdata->packet_length; - memcpy(&rl->rbuf, &(rdata->rbuf), sizeof(TLS_BUFFER)); - memcpy(&rl->rrec[0], &(rdata->rrec), sizeof(TLS_RL_RECORD)); - - /* Set proper sequence number for mac calculation */ - memcpy(&(rl->sequence[2]), &(rdata->packet[5]), 6); - - return 1; -} - -static int dtls_retrieve_rlayer_buffered_record(OSSL_RECORD_LAYER *rl, - struct pqueue_st *queue) -{ - pitem *item; - - item = pqueue_pop(queue); - if (item) { - dtls_copy_rlayer_record(rl, item); - - OPENSSL_free(item->data); - pitem_free(item); - - return 1; - } - - return 0; -} - /*- * Call this to get a new input record. * It will return <= 0 if more data is needed, normally due to an error @@ -400,12 +359,6 @@ int dtls_get_more_records(OSSL_RECORD_LAYER *rl) } again: - /* if we're renegotiating, then there may be buffered records */ - if (dtls_retrieve_rlayer_buffered_record(rl, rl->processed_rcds)) { - rl->num_recs = 1; - return OSSL_RECORD_RETURN_SUCCESS; - } - /* get something from the wire */ /* check if we have the header */ @@ -607,23 +560,13 @@ static int dtls_free(OSSL_RECORD_LAYER *rl) /* Push to the next record layer */ ret &= BIO_write_ex(rl->next, rdata->packet, rdata->packet_length, &written); - OPENSSL_free(rdata->rbuf.buf); + OPENSSL_free(rdata->packet); OPENSSL_free(item->data); pitem_free(item); } pqueue_free(rl->unprocessed_rcds); } - if (rl->processed_rcds != NULL) { - while ((item = pqueue_pop(rl->processed_rcds)) != NULL) { - rdata = (DTLS_RLAYER_RECORD_DATA *)item->data; - OPENSSL_free(rdata->rbuf.buf); - OPENSSL_free(item->data); - pitem_free(item); - } - pqueue_free(rl->processed_rcds); - } - return tls_free(rl) && ret; } @@ -653,10 +596,8 @@ dtls_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers, return ret; (*retrl)->unprocessed_rcds = pqueue_new(); - (*retrl)->processed_rcds = pqueue_new(); - if ((*retrl)->unprocessed_rcds == NULL - || (*retrl)->processed_rcds == NULL) { + if ((*retrl)->unprocessed_rcds == NULL) { dtls_free(*retrl); *retrl = NULL; ERR_raise(ERR_LIB_SSL, ERR_R_SSL_LIB); diff --git a/ssl/record/methods/recmethod_local.h b/ssl/record/methods/recmethod_local.h index 4ffce8d66385c..5e3fdd1d05874 100644 --- a/ssl/record/methods/recmethod_local.h +++ b/ssl/record/methods/recmethod_local.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -344,9 +344,8 @@ struct ossl_record_layer_st { size_t taglen; - /* DTLS received handshake records (processed and unprocessed) */ + /* DTLS received handshake records awaiting the next epoch */ struct pqueue_st *unprocessed_rcds; - struct pqueue_st *processed_rcds; /* records being received in the current epoch */ DTLS_BITMAP bitmap; @@ -374,7 +373,6 @@ struct ossl_record_layer_st { typedef struct dtls_rlayer_record_data_st { unsigned char *packet; size_t packet_length; - TLS_BUFFER rbuf; TLS_RL_RECORD rrec; } DTLS_RLAYER_RECORD_DATA; diff --git a/ssl/record/methods/tls_common.c b/ssl/record/methods/tls_common.c index 9f957b7cc656f..e00ad084cbd9c 100644 --- a/ssl/record/methods/tls_common.c +++ b/ssl/record/methods/tls_common.c @@ -497,7 +497,7 @@ static int tls_record_app_data_waiting(OSSL_RECORD_LAYER *rl) static int rlayer_early_data_count_ok(OSSL_RECORD_LAYER *rl, size_t length, size_t overhead, int send) { - uint32_t max_early_data = rl->max_early_data; + uint64_t max_early_data = rl->max_early_data; if (max_early_data == 0) { RLAYERfatal(rl, send ? SSL_AD_INTERNAL_ERROR : SSL_AD_UNEXPECTED_MESSAGE, @@ -1919,13 +1919,14 @@ int tls_retry_write_records(OSSL_RECORD_LAYER *rl) { int i, ret; TLS_BUFFER *thiswb; - size_t tmpwrit = 0; + size_t tmpwrit = 0, left; if (rl->nextwbuf >= rl->numwpipes) return OSSL_RECORD_RETURN_SUCCESS; for (;;) { thiswb = &rl->wbuf[rl->nextwbuf]; + left = TLS_BUFFER_get_left(thiswb); clear_sys_error(); if (rl->bio != NULL) { @@ -1935,13 +1936,24 @@ int tls_retry_write_records(OSSL_RECORD_LAYER *rl) return ret; } i = BIO_write(rl->bio, (char *)&(TLS_BUFFER_get_buf(thiswb)[TLS_BUFFER_get_offset(thiswb)]), - (unsigned int)TLS_BUFFER_get_left(thiswb)); + (unsigned int)left); if (i >= 0) { tmpwrit = i; - if (i == 0 && BIO_should_retry(rl->bio)) - ret = OSSL_RECORD_RETURN_RETRY; - else + if (i == 0 && left != 0) { + if (BIO_should_retry(rl->bio)) { + ret = OSSL_RECORD_RETURN_RETRY; + } else { + /* + * Treat this as a fatal I/O condition. Do not queue an + * SSL reason: a zero return with no retry flag may come + * from a custom BIO and does not imply an SSL library + * or protocol error. + */ + ret = OSSL_RECORD_RETURN_FATAL; + } + } else { ret = OSSL_RECORD_RETURN_SUCCESS; + } } else { if (BIO_should_retry(rl->bio)) { ret = OSSL_RECORD_RETURN_RETRY; @@ -1964,7 +1976,7 @@ int tls_retry_write_records(OSSL_RECORD_LAYER *rl) * Treat i == 0 as success rather than an error for zero byte * writes to permit this case. */ - if (i >= 0 && tmpwrit == TLS_BUFFER_get_left(thiswb)) { + if (i >= 0 && tmpwrit == left) { TLS_BUFFER_set_left(thiswb, 0); TLS_BUFFER_add_offset(thiswb, tmpwrit); if (++(rl->nextwbuf) < rl->numwpipes) @@ -1982,9 +1994,9 @@ int tls_retry_write_records(OSSL_RECORD_LAYER *rl) */ if (TLS_BUFFER_is_app_buffer(thiswb) && (rl->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER) != 0) { - size_t left = TLS_BUFFER_get_left(thiswb); unsigned char *buf; + left = TLS_BUFFER_get_left(thiswb); buf = OPENSSL_malloc(left); if (buf == NULL) { RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c index ba407478b4121..3ab50facc93eb 100644 --- a/ssl/record/rec_layer_s3.c +++ b/ssl/record/rec_layer_s3.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -150,7 +150,7 @@ static uint32_t ossl_get_max_early_data(SSL_CONNECTION *s) static int ossl_early_data_count_ok(SSL_CONNECTION *s, size_t length, size_t overhead, int send) { - uint32_t max_early_data; + uint64_t max_early_data; max_early_data = ossl_get_max_early_data(s); diff --git a/ssl/rio/poll_builder.c b/ssl/rio/poll_builder.c index 28d93ee1947a9..f808e9b01e748 100644 --- a/ssl/rio/poll_builder.c +++ b/ssl/rio/poll_builder.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -120,8 +120,10 @@ int ossl_rio_poll_builder_add_fd(RIO_POLL_BUILDER *rpb, int fd, assert((rpb->pfd_heap != NULL && rpb->pfd_heap == pfds) || (rpb->pfd_heap == NULL && rpb->pfds == pfds)); assert(i <= rpb->pfd_num && rpb->pfd_num <= rpb->pfd_alloc); + /* Check the index first because an appended entry is uninitialised. */ + if (i == rpb->pfd_num || pfds[i].fd == -1) + pfds[i].events = 0; pfds[i].fd = fd; - pfds[i].events = 0; if (want_read) pfds[i].events |= POLLIN; diff --git a/ssl/rio/poll_builder.h b/ssl/rio/poll_builder.h index 1fe13eacbaba4..48605d7182234 100644 --- a/ssl/rio/poll_builder.h +++ b/ssl/rio/poll_builder.h @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -76,4 +76,17 @@ int ossl_rio_poll_builder_poll(RIO_POLL_BUILDER *rpb, OSSL_TIME deadline); * it is currently not needed. */ +#ifndef OPENSSL_NO_QUIC +/* + * Test instrumentation only. If set, poll_translate() (see poll_immediate.c) + * calls this with the index of each item immediately before translating it, + * once all earlier items (if any) have finished translation. This lets + * tests inject a readiness change into the gap between translation of + * consecutive items, in order to deterministically exercise the + * abort-blocking path. Always NULL in production use. + */ +extern void (*ossl_quic_poll_translate_test_step_cb)(size_t idx, void *arg); +extern void *ossl_quic_poll_translate_test_step_cb_arg; +#endif + #endif diff --git a/ssl/rio/poll_immediate.c b/ssl/rio/poll_immediate.c index 24b82f3a6a438..95410df0d8f43 100644 --- a/ssl/rio/poll_immediate.c +++ b/ssl/rio/poll_immediate.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -49,6 +49,13 @@ } while (0) #ifndef OPENSSL_NO_QUIC +/* + * Test instrumentation only; see poll_builder.h. Always NULL in production + * use. + */ +void (*ossl_quic_poll_translate_test_step_cb)(size_t idx, void *arg) = NULL; +void *ossl_quic_poll_translate_test_step_cb_arg = NULL; + static int poll_translate_ssl_quic(SSL *ssl, QUIC_REACTOR_WAIT_CTX *wctx, RIO_POLL_BUILDER *rpb, @@ -216,6 +223,10 @@ static int poll_translate(SSL_POLL_ITEM *items, for (i = 0; i < num_items; ++i) { item = &ITEM_N(items, stride, i); + if (ossl_quic_poll_translate_test_step_cb != NULL) + ossl_quic_poll_translate_test_step_cb(i, + ossl_quic_poll_translate_test_step_cb_arg); + switch (item->desc.type) { case BIO_POLL_DESCRIPTOR_TYPE_SSL: ssl = item->desc.value.ssl; @@ -233,7 +244,7 @@ static int poll_translate(SSL_POLL_ITEM *items, FAIL_ITEM(i); if (*abort_blocking) - return 1; + goto out; if (!SSL_get_event_timeout(ssl, &timeout, &is_infinite)) FAIL_ITEM(i++); /* need to clean up this item too */ @@ -271,7 +282,12 @@ static int poll_translate(SSL_POLL_ITEM *items, } out: - if (!ok) + /* + * On abort_blocking, the item which triggered the abort has already + * balanced its own enter/leave of the blocking section (see + * poll_translate_ssl_quic()); only items 0..i-1 still need cleanup here. + */ + if (!ok || *abort_blocking) postpoll_translation_cleanup(items, i, stride, wctx); *p_earliest_wakeup_deadline = earliest_wakeup_deadline; @@ -320,8 +336,15 @@ static int poll_block(SSL_POLL_ITEM *items, p_result_count)) goto out; - if (abort_blocking) + if (abort_blocking) { + /* + * Nothing actually failed; we just shouldn't block because an item + * may have become ready while we were setting up. The caller's + * retry loop will call poll_readout() again to pick this up. + */ + ok = 1; goto out; + } earliest_wakeup_deadline = ossl_time_min(earliest_wakeup_deadline, user_deadline); diff --git a/ssl/rio/rio_notifier.c b/ssl/rio/rio_notifier.c index ea40790d627bd..abc1755dae029 100644 --- a/ssl/rio/rio_notifier.c +++ b/ssl/rio/rio_notifier.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -10,7 +10,6 @@ #include "internal/sockets.h" #include #include -#include "internal/thread_once.h" #include "internal/rio_notifier.h" /* @@ -28,32 +27,29 @@ static int set_cloexec(int fd) #if defined(OPENSSL_SYS_WINDOWS) -static CRYPTO_ONCE ensure_wsa_startup_once = CRYPTO_ONCE_STATIC_INIT; -static int wsa_started; - static void ossl_wsa_cleanup(void) { - if (wsa_started) { - wsa_started = 0; - WSACleanup(); - } + WSACleanup(); } -DEFINE_RUN_ONCE_STATIC(do_wsa_startup) +static int do_wsa_startup(void) { WORD versionreq = 0x0202; /* Version 2.2 */ WSADATA wsadata; if (WSAStartup(versionreq, &wsadata) != 0) return 0; - wsa_started = 1; - OPENSSL_atexit(ossl_wsa_cleanup); return 1; } static ossl_inline int ensure_wsa_startup(void) { - return RUN_ONCE(&ensure_wsa_startup_once, do_wsa_startup); + return do_wsa_startup(); +} + +static void wsa_done(void) +{ + ossl_wsa_cleanup(); } #endif diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index 213ec84b171d5..079a308f6ff1b 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -5223,8 +5223,10 @@ int ssl_generate_master_secret(SSL_CONNECTION *s, unsigned char *pms, pskpmslen = 4 + pmslen + psklen; pskpms = OPENSSL_malloc(pskpmslen); - if (pskpms == NULL) + if (pskpms == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_CRYPTO_LIB); goto err; + } t = pskpms; s2n(pmslen, t); if (alg_k & SSL_kPSK) @@ -5248,6 +5250,7 @@ int ssl_generate_master_secret(SSL_CONNECTION *s, unsigned char *pms, OPENSSL_clear_free(pskpms, pskpmslen); #else /* Should never happen */ + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); goto err; #endif } else { diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c index adc5bb3d35c3e..43d1191c6e2e7 100644 --- a/ssl/ssl_cert.c +++ b/ssl/ssl_cert.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved * * Licensed under the Apache License 2.0 (the "License"). You may not use @@ -306,7 +306,7 @@ int ssl_cert_set0_chain(SSL_CONNECTION *s, SSL_CTX *ctx, STACK_OF(X509) *chain) for (i = 0; i < sk_X509_num(chain); i++) { X509 *x = sk_X509_value(chain, i); - r = ssl_security_cert(s, ctx, x, 0, 0); + r = ssl_security_cert(s, ctx, x, 0); if (r != 1) { ERR_raise(ERR_LIB_SSL, r); return 0; @@ -340,7 +340,7 @@ int ssl_cert_add0_chain_cert(SSL_CONNECTION *s, SSL_CTX *ctx, X509 *x) if (!cpk) return 0; - r = ssl_security_cert(s, ctx, x, 0, 0); + r = ssl_security_cert(s, ctx, x, 0); if (r != 1) { ERR_raise(ERR_LIB_SSL, r); return 0; @@ -1149,7 +1149,7 @@ int ssl_build_cert_chain(SSL_CONNECTION *s, SSL_CTX *ctx, int flags) */ for (i = 0; i < sk_X509_num(chain); i++) { x = sk_X509_value(chain, i); - rv = ssl_security_cert(s, ctx, x, 0, 0); + rv = ssl_security_cert(s, ctx, x, 0); if (rv != 1) { ERR_raise(ERR_LIB_SSL, rv); OSSL_STACK_OF_X509_free(chain); diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 05b0209a76b32..ba494f5fc0d04 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -5226,6 +5226,31 @@ SSL *SSL_dup(SSL *s) || !dup_ca_names(&retsc->client_ca_names, sc->client_ca_names)) goto err; + if (sc->server_cert_type != NULL) { + OPENSSL_free(retsc->server_cert_type); + retsc->server_cert_type = OPENSSL_memdup(sc->server_cert_type, + sc->server_cert_type_len); + if (retsc->server_cert_type == NULL) + goto err; + retsc->server_cert_type_len = sc->server_cert_type_len; + } + + if (sc->client_cert_type != NULL) { + OPENSSL_free(retsc->client_cert_type); + retsc->client_cert_type = OPENSSL_memdup(sc->client_cert_type, + sc->client_cert_type_len); + if (retsc->client_cert_type == NULL) + goto err; + retsc->client_cert_type_len = sc->client_cert_type_len; + } + +#ifndef OPENSSL_NO_CT + retsc->ct_validation_callback = sc->ct_validation_callback; + retsc->ct_validation_callback_arg = sc->ct_validation_callback_arg; +#endif + + retsc->ext.status_type = sc->ext.status_type; + return ret; err: diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index 8fc8b64406153..d974ac6ecfe0b 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -1,5 +1,5 @@ /* - * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved * Copyright 2005 Nokia. All rights reserved. * @@ -2901,10 +2901,9 @@ __owur int ssl_validate_ct(SSL_CONNECTION *s); __owur EVP_PKEY *ssl_get_auto_dh(SSL_CONNECTION *s); -__owur int ssl_security_cert(SSL_CONNECTION *s, SSL_CTX *ctx, X509 *x, int vfy, - int is_ee); +__owur int ssl_security_cert(SSL_CONNECTION *s, SSL_CTX *ctx, X509 *x, int is_ee); __owur int ssl_security_cert_chain(SSL_CONNECTION *s, STACK_OF(X509) *sk, - X509 *ex, int vfy); + X509 *ex); int tls_choose_sigalg(SSL_CONNECTION *s, int fatalerrs); diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c index 740460f5c2e02..42958d9d0c2d1 100644 --- a/ssl/ssl_rsa.c +++ b/ssl/ssl_rsa.c @@ -42,7 +42,7 @@ int SSL_use_certificate(SSL *ssl, X509 *x) return 0; } - rv = ssl_security_cert(sc, NULL, x, 0, 1); + rv = ssl_security_cert(sc, NULL, x, 1); if (rv != 1) { ERR_raise(ERR_LIB_SSL, rv); return 0; @@ -247,7 +247,7 @@ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) return 0; } - rv = ssl_security_cert(NULL, ctx, x, 0, 1); + rv = ssl_security_cert(NULL, ctx, x, 1); if (rv != 1) { ERR_raise(ERR_LIB_SSL, rv); return 0; @@ -993,13 +993,13 @@ static int ssl_set_cert_and_key(SSL *ssl, SSL_CTX *ctx, X509 *x509, EVP_PKEY *pr c = sc != NULL ? sc->cert : ctx->cert; /* Do all security checks before anything else */ - rv = ssl_security_cert(sc, ctx, x509, 0, 1); + rv = ssl_security_cert(sc, ctx, x509, 1); if (rv != 1) { ERR_raise(ERR_LIB_SSL, rv); goto out; } for (j = 0; j < sk_X509_num(chain); j++) { - rv = ssl_security_cert(sc, ctx, sk_X509_value(chain, j), 0, 0); + rv = ssl_security_cert(sc, ctx, sk_X509_value(chain, j), 0); if (rv != 1) { ERR_raise(ERR_LIB_SSL, rv); goto out; diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index 2de540f828f03..13846bc115962 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -605,6 +605,11 @@ int tls_collect_extensions(SSL_CONNECTION *s, PACKET *packet, SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_EXTENSION); goto err; } + + /* The server must tolerate the unknown extension and complete. */ + if (thisex == NULL) + continue; + idx = thisex - raw_extensions; /*- * Check that we requested this extension (if appropriate). Requests can @@ -635,17 +640,15 @@ int tls_collect_extensions(SSL_CONNECTION *s, PACKET *packet, SSL_R_UNSOLICITED_EXTENSION); goto err; } - if (thisex != NULL) { - thisex->data = extension; - thisex->present = 1; - thisex->type = type; - thisex->received_order = i++; - if (s->ext.debug_cb) - s->ext.debug_cb(SSL_CONNECTION_GET_USER_SSL(s), !s->server, - thisex->type, PACKET_data(&thisex->data), - PACKET_remaining(&thisex->data), - s->ext.debug_arg); - } + thisex->data = extension; + thisex->present = 1; + thisex->type = type; + thisex->received_order = i++; + if (s->ext.debug_cb) + s->ext.debug_cb(SSL_CONNECTION_GET_USER_SSL(s), !s->server, + thisex->type, PACKET_data(&thisex->data), + (int)PACKET_remaining(&thisex->data), + s->ext.debug_arg); } if (init) { diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index b317b9392435a..0279a62abd2ef 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c @@ -2814,6 +2814,14 @@ MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL_CONNECTION *s, if (SSL_CONNECTION_IS_TLS13(s)) { PACKET extpkt; + /* + * Fulfilling RFC8446:4.6.1 requirement: Clients MUST NOT cache + * tickets for longer than 7 days. + */ + if (ticket_lifetime_hint > 604800) { + ticket_lifetime_hint = 604800; + } + if (!PACKET_as_length_prefixed_2(pkt, &extpkt) || PACKET_remaining(pkt) != 0) { SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH); diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c index 7e3be12f7a718..c690087081477 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -1071,7 +1071,7 @@ static int ssl_add_cert_chain(SSL_CONNECTION *s, WPACKET *pkt, CERT_PKEY *cpk, i /* Don't leave errors in the queue */ ERR_clear_error(); chain = X509_STORE_CTX_get0_chain(xs_ctx); - i = ssl_security_cert_chain(s, chain, NULL, 0); + i = ssl_security_cert_chain(s, chain, NULL); if (i != 1) { #if 0 /* Dummy error calls so mkerr generates them */ @@ -1096,7 +1096,7 @@ static int ssl_add_cert_chain(SSL_CONNECTION *s, WPACKET *pkt, CERT_PKEY *cpk, i } X509_STORE_CTX_free(xs_ctx); } else { - i = ssl_security_cert_chain(s, extra_certs, x, 0); + i = ssl_security_cert_chain(s, extra_certs, x); if (i != 1) { if (!for_comp) SSLfatal(s, SSL_AD_INTERNAL_ERROR, i); diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index b2f8a0ebc43d2..03fcc6eeac796 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -3921,8 +3921,10 @@ CON_FUNC_RETURN tls_construct_server_compressed_certificate(SSL_CONNECTION *sc, || !WPACKET_put_bytes_u24(pkt, cc->orig_len) || !WPACKET_start_sub_packet_u24(pkt) || !WPACKET_memcpy(pkt, cc->data, cc->len) - || !WPACKET_close(pkt)) + || !WPACKET_close(pkt)) { + SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return 0; + } sc->s3.tmp.cert->cert_comp_used++; return 1; @@ -4251,7 +4253,7 @@ CON_FUNC_RETURN tls_construct_new_session_ticket(SSL_CONNECTION *s, WPACKET *pkt SSL_SESSION *new_sess = ssl_session_dup(s->session, 0); if (new_sess == NULL) { - /* SSLfatal already called */ + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_SSL_LIB); goto err; } diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index e11fa8bc638ec..ef1114172a283 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -1817,53 +1817,6 @@ void tls1_get_formatlist(SSL_CONNECTION *s, const unsigned char **pformats, } } -/* Check a key is compatible with compression extension */ -static int tls1_check_pkey_comp(SSL_CONNECTION *s, EVP_PKEY *pkey) -{ - unsigned char comp_id; - size_t i; - int point_conv; - - /* If not an EC key nothing to check */ - if (!EVP_PKEY_is_a(pkey, "EC")) - return 1; - - /* Get required compression id */ - point_conv = EVP_PKEY_get_ec_point_conv_form(pkey); - if (point_conv == 0) - return 0; - if (point_conv == POINT_CONVERSION_UNCOMPRESSED) { - comp_id = TLSEXT_ECPOINTFORMAT_uncompressed; - } else if (SSL_CONNECTION_IS_TLS13(s)) { - /* - * ec_point_formats extension is not used in TLSv1.3 so we ignore - * this check. - */ - return 1; - } else { - int field_type = EVP_PKEY_get_field_type(pkey); - - if (field_type == NID_X9_62_prime_field) - comp_id = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime; - else if (field_type == NID_X9_62_characteristic_two_field) - comp_id = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2; - else - return 0; - } - /* - * If point formats extension present check it, otherwise everything is - * supported (see RFC4492). - */ - if (s->ext.peer_ecpointformats == NULL) - return 1; - - for (i = 0; i < s->ext.peer_ecpointformats_len; i++) { - if (s->ext.peer_ecpointformats[i] == comp_id) - return 1; - } - return 0; -} - /* Return group id of a key */ static uint16_t tls1_get_group_id(EVP_PKEY *pkey) { @@ -1888,9 +1841,6 @@ static int tls1_check_cert_param(SSL_CONNECTION *s, X509 *x, int check_ee_md) /* If not EC nothing to do */ if (!EVP_PKEY_is_a(pkey, "EC")) return 1; - /* Check compression */ - if (!tls1_check_pkey_comp(s, pkey)) - return 0; group_id = tls1_get_group_id(pkey); /* * For a server we allow the certificate to not be in our list of supported @@ -2788,13 +2738,6 @@ int tls12_check_peer_sigalg(SSL_CONNECTION *s, uint16_t sig, EVP_PKEY *pkey) if (pkeyid == EVP_PKEY_EC) { - /* Check point compression is permitted */ - if (!tls1_check_pkey_comp(s, pkey)) { - SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, - SSL_R_ILLEGAL_POINT_COMPRESSION); - return 0; - } - /* For TLS 1.3 or Suite B check curve matches signature algorithm */ if (SSL_CONNECTION_IS_TLS13(s) || tls1_suiteb(s)) { int curve = ssl_get_EC_curve_nid(pkey); @@ -4057,8 +4000,6 @@ int tls1_check_chain(SSL_CONNECTION *s, X509 *x, EVP_PKEY *pk, chain = cpk->chain; strict_mode = c->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT; if (tls12_rpk_and_privkey(s, idx)) { - if (EVP_PKEY_is_a(pk, "EC") && !tls1_check_pkey_comp(s, pk)) - return 0; *pvalid = rv = CERT_PKEY_RPK; return rv; } @@ -4401,51 +4342,29 @@ static int ssl_security_cert_key(SSL_CONNECTION *s, SSL_CTX *ctx, X509 *x, return ssl_ctx_security(ctx, op, secbits, 0, x); } -static int ssl_security_cert_sig(SSL_CONNECTION *s, SSL_CTX *ctx, X509 *x, - int op) +int ssl_security_cert(SSL_CONNECTION *s, SSL_CTX *ctx, X509 *x, int is_ee) { - /* Lookup signature algorithm digest */ - int secbits, nid, pknid; - - /* Don't check signature if self signed */ - if ((X509_get_extension_flags(x) & EXFLAG_SS) != 0) - return 1; - if (!X509_get_signature_info(x, &nid, &pknid, &secbits, NULL)) - secbits = -1; - /* If digest NID not defined use signature NID */ - if (nid == NID_undef) - nid = pknid; - if (s != NULL) - return ssl_security(s, op, secbits, nid, x); - else - return ssl_ctx_security(ctx, op, secbits, nid, x); -} - -int ssl_security_cert(SSL_CONNECTION *s, SSL_CTX *ctx, X509 *x, int vfy, - int is_ee) -{ - if (vfy) - vfy = SSL_SECOP_PEER; if (is_ee) { - if (!ssl_security_cert_key(s, ctx, x, SSL_SECOP_EE_KEY | vfy)) + if (!ssl_security_cert_key(s, ctx, x, SSL_SECOP_EE_KEY)) return SSL_R_EE_KEY_TOO_SMALL; } else { - if (!ssl_security_cert_key(s, ctx, x, SSL_SECOP_CA_KEY | vfy)) + if (!ssl_security_cert_key(s, ctx, x, SSL_SECOP_CA_KEY)) return SSL_R_CA_KEY_TOO_SMALL; } - if (!ssl_security_cert_sig(s, ctx, x, SSL_SECOP_CA_MD | vfy)) - return SSL_R_CA_MD_TOO_WEAK; return 1; } /* - * Check security of a chain, if |sk| includes the end entity certificate then - * |x| is NULL. If |vfy| is 1 then we are verifying a peer chain and not sending - * one to the peer. Return values: 1 if ok otherwise error code to use + * Call ssl_security_check() on all certificates in a stack. + * If |x| is non NULL it is checked first, before checking the + * certificates in the stack. + * + * Return values: 1 if ok otherwise the error code from the first + * failing ssl_security_check().; */ int ssl_security_cert_chain(SSL_CONNECTION *s, STACK_OF(X509) *sk, - X509 *x, int vfy) + X509 *x) { int rv, start_idx, i; @@ -4457,13 +4376,13 @@ int ssl_security_cert_chain(SSL_CONNECTION *s, STACK_OF(X509) *sk, } else start_idx = 0; - rv = ssl_security_cert(s, NULL, x, vfy, 1); + rv = ssl_security_cert(s, NULL, x, 1); if (rv != 1) return rv; for (i = start_idx; i < sk_X509_num(sk); i++) { x = sk_X509_value(sk, i); - rv = ssl_security_cert(s, NULL, x, vfy, 0); + rv = ssl_security_cert(s, NULL, x, 0); if (rv != 1) return rv; } @@ -4523,6 +4442,20 @@ static int check_cert_usable(SSL_CONNECTION *s, const SIGALG_LOOKUP *sig, if (supported <= 0) return 0; + /* + * When RPK is negotiated there are no certificate signatures to + * constrain, and there may not even be a certificate configured. + */ + if (TLSEXT_cert_type_rpk == (s->server ? s->ext.server_cert_type : s->ext.client_cert_type)) + return 1; + + /* + * RPK was enabled, adding candidate private-key-only slots, but was not + * negotiated, so the key-only slot is not usable. + */ + if (x == NULL) + return 0; + /* * The TLS 1.3 signature_algorithms_cert extension places restrictions * on the sigalg with which the certificate was signed (by its issuer). diff --git a/test/asn1_decode_test.c b/test/asn1_decode_test.c index 6e00d40896927..8a9629c21dc30 100644 --- a/test/asn1_decode_test.c +++ b/test/asn1_decode_test.c @@ -14,7 +14,11 @@ #include #include #include +#include +#include +#include #include "internal/numbers.h" +#include "internal/asn1.h" #include "testutil.h" #ifdef __GNUC__ @@ -266,6 +270,163 @@ static int test_reuse_asn1_object(void) return ret; } +/* + * A minimal, complete DER object: SEQUENCE { INTEGER 0 }. + * asn1_d2i_read_bio() should consume exactly these bytes. + */ +static const unsigned char one_obj[] = { + 0x30, 0x03, /* SEQUENCE, length 3 */ + 0x02, 0x01, 0x00 /* INTEGER 0 */ +}; + +/* + * Reading concatenated DER objects from a BIO must stop cleanly at EOF: + * once the input is exhausted on an object boundary, asn1_d2i_read_bio() + * returns < 0 and must NOT leave an error on the queue. Callers that loop + * over concatenated values (e.g. CPython's ssl module loading the Windows + * certificate store via d2i_X509_bio()) rely on this to detect end-of-input; + * a spurious ASN1_R_NOT_ENOUGH_DATA there is reported as a fatal error. + */ +static int test_d2i_read_bio_clean_eof(void) +{ + unsigned char two_objs[sizeof(one_obj) * 2]; + BIO *bio = NULL; + BUF_MEM *buf = NULL; + int ret = 0; + + memcpy(two_objs, one_obj, sizeof(one_obj)); + memcpy(two_objs + sizeof(one_obj), one_obj, sizeof(one_obj)); + + if (!TEST_ptr(bio = BIO_new_mem_buf(two_objs, sizeof(two_objs)))) + goto err; + ERR_clear_error(); + + /* Both complete objects are read, one per call. */ + if (!TEST_int_eq(asn1_d2i_read_bio(bio, &buf), (int)sizeof(one_obj))) + goto err; + BUF_MEM_free(buf); + buf = NULL; + if (!TEST_int_eq(asn1_d2i_read_bio(bio, &buf), (int)sizeof(one_obj))) + goto err; + BUF_MEM_free(buf); + buf = NULL; + + /* Clean EOF: failure return, but no error must be queued. */ + if (!TEST_int_lt(asn1_d2i_read_bio(bio, &buf), 0)) + goto err; + if (!TEST_ulong_eq(ERR_peek_error(), 0)) + goto err; + + ret = 1; +err: + BUF_MEM_free(buf); + BIO_free(bio); + return ret; +} + +/* + * In contrast, hitting EOF in the middle of an object is genuine truncation + * and must still be reported as ASN1_R_NOT_ENOUGH_DATA. + */ +static int test_d2i_read_bio_truncated(void) +{ + static const unsigned char truncated[] = { + 0x30, 0x05, /* SEQUENCE claims 5 content bytes ... */ + 0x02, 0x01 /* ... but only 2 are present */ + }; + BIO *bio = NULL; + BUF_MEM *buf = NULL; + unsigned long e; + int ret = 0; + + if (!TEST_ptr(bio = BIO_new_mem_buf(truncated, sizeof(truncated)))) + goto err; + ERR_clear_error(); + + if (!TEST_int_lt(asn1_d2i_read_bio(bio, &buf), 0)) + goto err; + e = ERR_peek_last_error(); + if (!TEST_int_eq(ERR_GET_LIB(e), ERR_LIB_ASN1) + || !TEST_int_eq(ERR_GET_REASON(e), ASN1_R_NOT_ENOUGH_DATA)) + goto err; + + ret = 1; +err: + BUF_MEM_free(buf); + BIO_free(bio); + return ret; +} + +/* + * An EOF reached while still inside an indefinite-length constructed value, + * before its end-of-contents octets, is truncation too (not a clean boundary), + * so it must also report ASN1_R_NOT_ENOUGH_DATA rather than an empty queue. + */ +static int test_d2i_read_bio_indefinite_truncated(void) +{ + /* SEQUENCE (indefinite) { INTEGER 0 } with the 00 00 EOC missing */ + static const unsigned char truncated_indefinite[] = { + 0x30, 0x80, /* SEQUENCE, indefinite length */ + 0x02, 0x01, 0x00 /* INTEGER 0; no end-of-contents octets follow */ + }; + BIO *bio = NULL; + BUF_MEM *buf = NULL; + unsigned long e; + int ret = 0; + + bio = BIO_new_mem_buf(truncated_indefinite, sizeof(truncated_indefinite)); + if (!TEST_ptr(bio)) + goto err; + ERR_clear_error(); + + if (!TEST_int_lt(asn1_d2i_read_bio(bio, &buf), 0)) + goto err; + e = ERR_peek_last_error(); + if (!TEST_int_eq(ERR_GET_LIB(e), ERR_LIB_ASN1) + || !TEST_int_eq(ERR_GET_REASON(e), ASN1_R_NOT_ENOUGH_DATA)) + goto err; + + ret = 1; +err: + BUF_MEM_free(buf); + BIO_free(bio); + return ret; +} + +/* + * An EOF reached part-way through an object's header, with some header bytes + * already buffered, is truncation as well. This exercises the "diff != 0" arm + * of the header-read check (distinct from the body read handled elsewhere). + */ +static int test_d2i_read_bio_partial_header(void) +{ + /* SEQUENCE with a 2-byte long-form length, but only one length byte given */ + static const unsigned char partial_header[] = { + 0x30, 0x82, 0x01 /* SEQUENCE, length declared as 2 bytes, 1 present */ + }; + BIO *bio = NULL; + BUF_MEM *buf = NULL; + unsigned long e; + int ret = 0; + + if (!TEST_ptr(bio = BIO_new_mem_buf(partial_header, sizeof(partial_header)))) + goto err; + ERR_clear_error(); + + if (!TEST_int_lt(asn1_d2i_read_bio(bio, &buf), 0)) + goto err; + e = ERR_peek_last_error(); + if (!TEST_int_eq(ERR_GET_LIB(e), ERR_LIB_ASN1) + || !TEST_int_eq(ERR_GET_REASON(e), ASN1_R_NOT_ENOUGH_DATA)) + goto err; + + ret = 1; +err: + BUF_MEM_free(buf); + BIO_free(bio); + return ret; +} + int setup_tests(void) { #ifndef OPENSSL_NO_DEPRECATED_3_0 @@ -279,5 +440,9 @@ int setup_tests(void) ADD_TEST(test_utctime); ADD_TEST(test_invalid_template); ADD_TEST(test_reuse_asn1_object); + ADD_TEST(test_d2i_read_bio_clean_eof); + ADD_TEST(test_d2i_read_bio_truncated); + ADD_TEST(test_d2i_read_bio_indefinite_truncated); + ADD_TEST(test_d2i_read_bio_partial_header); return 1; } diff --git a/test/build.info b/test/build.info index 99e06d3945309..03ce682e0279d 100644 --- a/test/build.info +++ b/test/build.info @@ -82,7 +82,8 @@ IF[{- !$disabled{tests} -}] IF[{- !$disabled{quic} -}] PROGRAMS{noinst}=priority_queue_test quicfaultstest quicapitest \ - quic_newcid_test quic_srt_gen_test + quic_newcid_test quic_srt_gen_test \ + rio_poll_builder_test ENDIF IF[{- !$disabled{qlog} -}] @@ -345,6 +346,10 @@ IF[{- !$disabled{tests} -}] DEPEND[packettest]=../libcrypto libtestutil.a IF[{- !$disabled{'quic'} -}] + SOURCE[rio_poll_builder_test]=rio_poll_builder_test.c + INCLUDE[rio_poll_builder_test]=.. ../include ../apps/include + DEPEND[rio_poll_builder_test]=../libcrypto.a ../libssl.a libtestutil.a + SOURCE[quic_wire_test]=quic_wire_test.c INCLUDE[quic_wire_test]=../include ../apps/include DEPEND[quic_wire_test]=../libcrypto.a ../libssl.a libtestutil.a @@ -763,7 +768,7 @@ IF[{- !$disabled{tests} -}] IF[{- !$disabled{cmp} -}] PROGRAMS{noinst}=cmp_asn_test cmp_ctx_test cmp_status_test cmp_hdr_test \ cmp_protect_test cmp_msg_test cmp_vfy_test \ - cmp_server_test cmp_client_test + cmp_server_test cmp_client_test cmp_extracerts_dos_test ENDIF SOURCE[cmp_asn_test]=cmp_asn_test.c helpers/cmp_testlib.c @@ -790,6 +795,10 @@ IF[{- !$disabled{tests} -}] INCLUDE[cmp_msg_test]=.. ../include ../apps/include DEPEND[cmp_msg_test]=../libcrypto.a libtestutil.a + SOURCE[cmp_extracerts_dos_test]=cmp_extracerts_dos_test.c helpers/cmp_testlib.c + INCLUDE[cmp_extracerts_dos_test]=.. ../include ../apps/include + DEPEND[cmp_extracerts_dos_test]=../libcrypto.a libtestutil.a + SOURCE[cmp_vfy_test]=cmp_vfy_test.c helpers/cmp_testlib.c INCLUDE[cmp_vfy_test]=.. ../include ../apps/include DEPEND[cmp_vfy_test]=../libcrypto.a libtestutil.a diff --git a/test/ca_internals_test.c b/test/ca_internals_test.c index 0b0b2f3b70976..94fd7b5f7aefe 100644 --- a/test/ca_internals_test.c +++ b/test/ca_internals_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2021-2024 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 @@ -48,13 +48,13 @@ static int test_do_updatedb(void) testdate = test_get_argument(2); testdateutc = test_asn1_string_to_time_t(testdate); - if (TEST_time_t_lt(testdateutc, 0)) { + if (!TEST_time_t_ge(testdateutc, 0)) { return 0; } indexfile = test_get_argument(1); db = load_index(indexfile, NULL); - if (TEST_ptr_null(db)) { + if (!TEST_ptr(db)) { return 0; } diff --git a/test/certs/delta-crl-as-complete-ca.pem b/test/certs/delta-crl-as-complete-ca.pem new file mode 100644 index 0000000000000..c7bade031a63e --- /dev/null +++ b/test/certs/delta-crl-as-complete-ca.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgIUP+A4l1Xr6j1/lQ/bRBdNebfmEHMwDQYJKoZIhvcNAQEL +BQAwKDEmMCQGA1UEAwwdRGVsdGEgQ1JMIGFzIENvbXBsZXRlIFRlc3QgQ0EwHhcN +MjYwNDMwMTQ0NjAyWhcNMzYwNDI3MTQ0NjAyWjAoMSYwJAYDVQQDDB1EZWx0YSBD +UkwgYXMgQ29tcGxldGUgVGVzdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAJ6Wr3/CguoFSKWbeAE2Czjp6qFRdZ3xhhz27NuSdnHpoZE7xgzbt3Z2 +cNt+szZXZIgOyMzSOu0r8q0fKp4VJmR9M5KoMduTHRJpwvT79VhJdZED/1akKhgJ +7WttsvK5kNc+1he7gELY3ssuzfw7MmZv+vMpykjNhSSBKpmUy2t9lX/b1mJ+LK6v +gHQ09ntxdIGniRauzf027ugG72oSydk80YG0EHBlI19eYVhBJEWjLq4afLUYRbfm +0OYHJGq5TE0VTww4xa1IzLFt4NpqveYztYN4ujKd95vbHB6EzCs3R15uJwwm/1px +PXFhwp4MF/W422/XxcadU3+0zHDgEScCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMIh2AkMIUaBjaMHDAOEBAv33XzE +MB8GA1UdIwQYMBaAFMIh2AkMIUaBjaMHDAOEBAv33XzEMA0GCSqGSIb3DQEBCwUA +A4IBAQA6yelNaY6aVomoTwmvNXdfNqlU96HGmEFfKMMFL1CgF5KsBaz4ARCJ+83s +/A0+HufwFYOwUx+dkklatp791leaFjxkFSHmKrE6WVBnOoss7M4a+Hwei13Qrirx +vKFhQde45OFqh8zpl0fru/KdCnbRoM05KVhFqnXR+vyDvghvlIWDFEFdX7KOdVXz +s9v5ECR4kftEalZVq7WNVBS9afVPoQvYj3dcebMH8l8RL5+adV2NRvBKgUKo2kwy +TG6nqWKRr4xqsARLPxYFk1tHbKfIVWy1FrABb5lW8iMA/RZCv6Qzyqbr4nT0WDTa +g3OUp6sSDEhnLYhnW3bsLUdpgRfy +-----END CERTIFICATE----- diff --git a/test/certs/delta-crl-as-complete-delta-reasons.pem b/test/certs/delta-crl-as-complete-delta-reasons.pem new file mode 100644 index 0000000000000..d20bc63f53b55 --- /dev/null +++ b/test/certs/delta-crl-as-complete-delta-reasons.pem @@ -0,0 +1,12 @@ +-----BEGIN X509 CRL----- +MIIBxDCBrQIBATANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQDDB1EZWx0YSBDUkwg +YXMgQ29tcGxldGUgVGVzdCBDQRcNMjYwNDMwMTQ0NjAzWhcNMzYwNDI3MTQ0NjAz +WqBRME8wHwYDVR0jBBgwFoAUwiHYCQwhRoGNowcMA4QEC/fdfMQwDQYDVR0bAQH/ +BAMCAQEwEAYDVR0cAQH/BAYwBIMCBWAwCwYDVR0UBAQCAjAAMA0GCSqGSIb3DQEB +CwUAA4IBAQB735x+EogYnkeL3DHwHBbTKXyWMp9UEdR9DVUVElNISNrLTuOy62Nr +N4OEWtDCESltII739hryz85lg0Jo1jBOYbRdGYIacRzm1WUvtk3aLfGt0gwifFtW +4AiiQZUz3jq0F2V9TythzE0nMQbIiXpG3ACc+HQ5/gwpFEvw9ABjXMp5SVU47fT5 +M2jRk12XR6N/MDJB13uh0EH814CD23Gqhvu2lVL3KSGiwImirbQX18egibBmIykR +jqwaH0giFa5ZbrMcOyBksyZJIZgAOpnzn4M5FlQb4s0AjxYSRjqQWV5qrBVfWT6b +Jy+lW3HgXMYyZt6Gqyayfu7N+6JbqhQ+ +-----END X509 CRL----- diff --git a/test/certs/delta-crl-as-complete-delta.pem b/test/certs/delta-crl-as-complete-delta.pem new file mode 100644 index 0000000000000..301a6b009a86e --- /dev/null +++ b/test/certs/delta-crl-as-complete-delta.pem @@ -0,0 +1,12 @@ +-----BEGIN X509 CRL----- +MIIBsjCBmwIBATANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQDDB1EZWx0YSBDUkwg +YXMgQ29tcGxldGUgVGVzdCBDQRcNMjYwNDMwMTQ0NjAzWhcNMzYwNDI3MTQ0NjAz +WqA/MD0wHwYDVR0jBBgwFoAUwiHYCQwhRoGNowcMA4QEC/fdfMQwDQYDVR0bAQH/ +BAMCAQEwCwYDVR0UBAQCAiAAMA0GCSqGSIb3DQEBCwUAA4IBAQADs08Ab6TRWijd +dOsW3wBCzWVi/GYlyPhMZjcPTDuM939rpL7yOONM7OIgekP3BYM7g4Dvp6Q4Caul +yZTtJ87dxqP56e11Q7h5eVcBBWxc1dM7FwMffqXXSEApuKdkRqKNAqtXugkgozdM +YBNIuSP+gyLNt4vrxtQS26pBMYJnbCf7ye5dyJFK3G58o97VknNMrYewPrzj6LVG +abS3eJnDaGtiGkQ16pOsKNRTlQYlXBk/9NMq8N8ntsm2ri3LJ/JQHRIHxxSsKl+f +ZgKmOa160pz+xWNq7edIM0RpwGjLVViE7F22y2JH/VJcqXimsl506QykD9COCzH6 +Lnv//55C +-----END X509 CRL----- diff --git a/test/certs/delta-crl-as-complete-leaf.pem b/test/certs/delta-crl-as-complete-leaf.pem new file mode 100644 index 0000000000000..c8ffebdb646b5 --- /dev/null +++ b/test/certs/delta-crl-as-complete-leaf.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDQDCCAiigAwIBAgIUXolrPqGDnGH9gUx2N5WFjfUkXHgwDQYJKoZIhvcNAQEL +BQAwKDEmMCQGA1UEAwwdRGVsdGEgQ1JMIGFzIENvbXBsZXRlIFRlc3QgQ0EwHhcN +MjYwNDMwMTQ0NjAzWhcNMzYwNDI3MTQ0NjAzWjAqMSgwJgYDVQQDDB9EZWx0YSBD +UkwgYXMgQ29tcGxldGUgVGVzdCBMZWFmMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA43iL7Otyb0SaPVDmOVBs39LnH9vlO2sV+ZPqV4o1a/JhCOzokMxg +NuPqCamMEufKctaKE8q/LKKEpu3QAG7H1vlsu2qfQLojFuHNKDnHM7RbsRNp9azE +DWpBWs0mXL96LUJzseioIIqFdSH9HkcTyrKXvr8iqaOUC96Vu9F03Ws59FmaTwK6 +JmKThfrIY2edSRyEO6tmVTh0XLW0PyNbSM/2eOKmh92RCbhKDjgCeNhPuJ0WRDAX +zNF+cgRO48epsl6ec03DdBSCFcwc5qL+TkzXjXIQbXhIsvl/OKNG0BUXDeYqH7ln +wEO6d556CF6wJlCd0DqzSzPsoVIo96asKwIDAQABo2AwXjAMBgNVHRMBAf8EAjAA +MA4GA1UdDwEB/wQEAwIHgDAdBgNVHQ4EFgQUFPI2A7WhMsPK15SsH1W+CiEKqA0w +HwYDVR0jBBgwFoAUwiHYCQwhRoGNowcMA4QEC/fdfMQwDQYJKoZIhvcNAQELBQAD +ggEBAGX7FpwNoq62mhlJbksgAJcaw5ci2m1CGFgNfh+f6pdA0mG3ywyM7eEZcr6h +GFslaDsG8m2O0l737Xs7mBpyq0ruxjpvk62VdgwTUkeZzz8gnuBIWg/+zrWyYCI7 +uDX4wKVMma9MF52YUHhNTdxvV0EE4wuUcYMAlWrCCzxkf4eNxyDJGBXli04xSpSj +cG9SsDRyjQKc9lFFqrQ9P/DVL4CDUSovE/2DWdZmS3RmsHjhNdGjpWtpoEsxBHdQ +5lyeGDp0fBf4RNWRsdr8RUsSiDFUproRibZ9/3uzH5yAfivZmWlVRUX/eyyjCrZD +VuW2H/npgPe+QSkwlUXYsZ1vqiM= +-----END CERTIFICATE----- diff --git a/test/certs/server-ec-compressed-cert.pem b/test/certs/server-ec-compressed-cert.pem new file mode 100644 index 0000000000000..4e97f49af2503 --- /dev/null +++ b/test/certs/server-ec-compressed-cert.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBrzCCATSgAwIBAgIBAjAKBggqhkjOPQQDAjAbMRkwFwYDVQQDDBBFQ0RTQSBQ +LTM4NCByb290MCAXDTI2MDYxOTE4MDA1OFoYDzIxMjYwNTI2MTgwMDU4WjAZMRcw +FQYDVQQDDA5zZXJ2ZXIuZXhhbXBsZTA5MBMGByqGSM49AgEGCCqGSM49AwEHAyIA +A4Mt9T6fKt3APp8/Frw65PDi2eMYdZK98nhBW9pA1Ccho4GIMIGFMB0GA1UdDgQW +BBTozN8kakexZEnc26PUo5K2W9ptbTAfBgNVHSMEGDAWgBQm0I8de1/cHn9BgH1j +yhx1gdaFaTAJBgNVHRMEAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD +AjAZBgNVHREEEjAQgg5zZXJ2ZXIuZXhhbXBsZTAKBggqhkjOPQQDAgNpADBmAjEA +hvcNLTyL7vamQEJet5uvOXH7NKPHlG8sbfPvGS/AQ0yk6ARdc1Y1gV6FAnmnQUhX +AjEA2HMTkh+h2ZDm68uRnhsNXIxI4dYF/nr5bdxw8XKN4P84Mg4gs37/IPoVN9jG +Y4yh +-----END CERTIFICATE----- diff --git a/test/certs/server-ec-compressed-key.pem b/test/certs/server-ec-compressed-key.pem new file mode 100644 index 0000000000000..98218fcb3cdee --- /dev/null +++ b/test/certs/server-ec-compressed-key.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MGcCAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcETTBLAgEBBCAb1VgxSUhJyh43soLb +FMsebjWSp/Hma3kSyw6lT4txDaEkAyIAA4Mt9T6fKt3APp8/Frw65PDi2eMYdZK9 +8nhBW9pA1Cch +-----END PRIVATE KEY----- diff --git a/test/cmp_client_test.c b/test/cmp_client_test.c index c2072c1be25c2..2dbe8fc9dacc9 100644 --- a/test/cmp_client_test.c +++ b/test/cmp_client_test.c @@ -239,7 +239,9 @@ static int test_exec_REQ_ses_poll(int req_type, int check_after, return result; } -static int checkAfter = 1; +static const int checkAfter = 1; +static const int pollCount = 3; + static int test_exec_IR_ses_poll_ok(void) { return test_exec_REQ_ses_poll(OSSL_CMP_PKIBODY_IR, checkAfter, 2, 0, @@ -256,8 +258,8 @@ static int test_exec_IR_ses_poll_no_timeout(void) static int test_exec_IR_ses_poll_total_timeout(void) { - return test_exec_REQ_ses_poll(OSSL_CMP_PKIBODY_IR, checkAfter + 1, - 3 /* pollCount */, checkAfter + 6, + return test_exec_REQ_ses_poll(OSSL_CMP_PKIBODY_IR, checkAfter, + pollCount, (pollCount - 1) * checkAfter, OSSL_CMP_PKISTATUS_trans); } @@ -466,8 +468,8 @@ static int test_exec_GENM_ses_poll_no_timeout(void) static int test_exec_GENM_ses_poll_total_timeout(void) { - return test_exec_REQ_ses_poll(OSSL_CMP_PKIBODY_GENM, checkAfter + 1, - 3 /* pollCount */, checkAfter + 2, + return test_exec_REQ_ses_poll(OSSL_CMP_PKIBODY_GENM, checkAfter, + pollCount, (pollCount - 1) * checkAfter, OSSL_CMP_PKISTATUS_trans); } diff --git a/test/cmp_extracerts_dos_test.c b/test/cmp_extracerts_dos_test.c new file mode 100644 index 0000000000000..273281c94376a --- /dev/null +++ b/test/cmp_extracerts_dos_test.c @@ -0,0 +1,338 @@ +/* + * 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 + */ + +/* + * Regression test for: CMP server unauthenticated memory/CPU DoS via + * cached extraCerts on failed protection checks. + * + * Root cause (crypto/cmp/cmp_vfy.c, ossl_cmp_msg_check_update(), current + * master as of this writing): + * + * res = ossl_x509_add_certs_new(&ctx->untrusted, msg->extraCerts, ...); + * ... + * res = OSSL_CMP_validate_msg(ctx, msg) || (cb...); // may be 0 (rejected) + * + * if (ctx->noCacheExtraCerts) // <-- rollback is + * while (num_added-- > 0) // gated on this + * X509_free(sk_X509_shift(ctx->untrusted)); // flag only, NOT + * // on the + * // validation + * // result (res) + * + * if (!res) { ...; return 0; } // certs from a REJECTED msg are kept + * + * This test exercises ossl_cmp_msg_check_update() directly -- no sockets, + * no HTTP server, no apps/cmp.c -- and asserts on the resulting size of + * ctx->untrusted. It builds a genuinely PBM-protected OSSL_CMP_MSG using + * the project's own internal message-creation function + * (ossl_cmp_genm_new(), same one exercised in test/cmp_msg_test.c) so the + * message is not hand-crafted to "look" rejectable -- it is rejected for a + * real reason (the receiving ctx has no matching secret configured), the + * same way OSSL_CMP_validate_msg() would reject any unauthenticated CMP + * request in the field. + * + * Expected results: + * - BEFORE the fix: untrusted_count_after == untrusted_count_before + N + * (every rejected message's extraCerts persist) + * - AFTER the fix: untrusted_count_after == untrusted_count_before + * (rejected messages leave no residue) + */ + +#include "helpers/cmp_testlib.h" + +#define NUM_REJECTED_REQUESTS 25 /* "attacker" sends this many distinct certs */ + +typedef struct test_fixture { + const char *test_case_name; + OSSL_CMP_CTX *server_ctx; /* long-lived ctx under test, mirrors srv_ctx->ctx */ +} CMP_DOS_TEST_FIXTURE; + +static OSSL_LIB_CTX *libctx = NULL; + +static CMP_DOS_TEST_FIXTURE *set_up(const char *const test_case_name) +{ + CMP_DOS_TEST_FIXTURE *fixture; + + if (!TEST_ptr(fixture = OPENSSL_zalloc(sizeof(*fixture)))) + return NULL; + fixture->test_case_name = test_case_name; + + if (!TEST_ptr(fixture->server_ctx = OSSL_CMP_CTX_new(libctx, NULL))) { + OPENSSL_free(fixture); + return NULL; + } + /* + * Deliberately do NOT call OSSL_CMP_CTX_set1_secretValue() on the + * server ctx. Per OSSL_CMP_validate_msg() (crypto/cmp/cmp_vfy.c): + * case NID_id_PasswordBasedMAC: + * if (ctx->secretValue == NULL) { + * ossl_cmp_info(ctx, "no secret available for verifying.."); + * ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_VALIDATING_PROTECTION); + * return 0; + * } + * so every PBM-protected message this ctx receives is unconditionally + * rejected -- a deterministic, content-independent rejection path that + * models "missing or invalid protection" from the report's repro + * steps, without needing to forge a bad MAC by hand. + * ctx->noCacheExtraCerts is left at its default (0), exactly as in the + * vulnerable deployment ("not setting -no_cache_extracerts"). + */ + return fixture; +} + +static void tear_down(CMP_DOS_TEST_FIXTURE *fixture) +{ + if (fixture == NULL) + return; + OSSL_CMP_CTX_free(fixture->server_ctx); + OPENSSL_free(fixture); +} + +/* Generates a throwaway EC P-256 keypair; cheap, and key strength is + * irrelevant to this test. */ +static EVP_PKEY *generate_throwaway_keypair(void) +{ + EVP_PKEY_CTX *pctx = NULL; + EVP_PKEY *pkey = NULL; + + if (!TEST_ptr(pctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", NULL))) + return NULL; + if (!TEST_int_gt(EVP_PKEY_keygen_init(pctx), 0) + || !TEST_int_gt(EVP_PKEY_CTX_set_group_name(pctx, "P-256"), 0) + || !TEST_int_gt(EVP_PKEY_generate(pctx, &pkey), 0)) + pkey = NULL; + EVP_PKEY_CTX_free(pctx); + return pkey; +} + +/* + * Builds a minimal, self-signed, syntactically valid X509 with a unique + * subject/issuer per index, so X509_ADD_FLAG_NO_DUP cannot collapse it + * with any other generated cert (matching the report's exploitation + * requirement of "unique certificates across requests"). + */ +static X509 *generate_unique_self_signed_cert(EVP_PKEY *pkey, int index) +{ + X509 *cert = NULL; + X509_NAME *name = NULL; + ASN1_INTEGER *serial = NULL; + char cn[64]; + + BIO_snprintf(cn, sizeof(cn), "attacker-cert-%d", index); + + if (!TEST_ptr(cert = X509_new()) + || !TEST_true(X509_set_version(cert, X509_VERSION_3))) + goto err; + + if (!TEST_ptr(serial = ASN1_INTEGER_new()) + || !TEST_true(ASN1_INTEGER_set(serial, 1000L + index)) + || !TEST_true(X509_set_serialNumber(cert, serial))) + goto err; + + if (!TEST_ptr(X509_gmtime_adj(X509_getm_notBefore(cert), 0)) + || !TEST_ptr(X509_gmtime_adj(X509_getm_notAfter(cert), + 60L * 60L * 24L * 365L))) + goto err; + + if (!TEST_true(X509_set_pubkey(cert, pkey))) + goto err; + + if (!TEST_ptr(name = X509_NAME_new()) + || !TEST_true(X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, + (unsigned char *)"cmp-dos-test", + -1, -1, 0)) + || !TEST_true(X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, + (unsigned char *)cn, + -1, -1, 0)) + || !TEST_true(X509_set_subject_name(cert, name)) + || !TEST_true(X509_set_issuer_name(cert, name))) + goto err; + + if (!TEST_int_gt(X509_sign(cert, pkey, EVP_sha256()), 0)) + goto err; + + X509_NAME_free(name); + ASN1_INTEGER_free(serial); + return cert; + +err: + X509_NAME_free(name); + ASN1_INTEGER_free(serial); + X509_free(cert); + return NULL; +} + +/* + * Builds a real, internally consistent, PBM-protected CMP GenMsg carrying + * exactly one never-before-seen self-signed cert as its sole extraCert. + * Uses a throwaway *client*-side OSSL_CMP_CTX purely to drive message + * creation/protection (ossl_cmp_genm_new() both builds the body and calls + * ossl_cmp_msg_protect() internally, same as in test/cmp_msg_test.c). The + * client ctx's secret is intentionally never shared with the server ctx + * under test, so the message is protected (syntactically well-formed, + * non-empty protection field) but NOT verifiable by the receiver -- this + * is what "missing or invalid protection" means for a real attacker who + * has no credentials, not an empty/garbage protection field. + */ +static OSSL_CMP_MSG *build_rejectable_msg_with_unique_cert(int index) +{ + OSSL_CMP_CTX *client_ctx = NULL; + OSSL_CMP_MSG *msg = NULL; + EVP_PKEY *pkey = NULL; + X509 *fresh_cert = NULL; + STACK_OF(X509) *extra = NULL; + unsigned char ref[16], secret[16]; + + if (!TEST_ptr(client_ctx = OSSL_CMP_CTX_new(libctx, NULL))) + goto err; + + if (!TEST_ptr(pkey = generate_throwaway_keypair()) + || !TEST_ptr(fresh_cert = generate_unique_self_signed_cert(pkey, index))) + goto err; + + if (!TEST_ptr(extra = sk_X509_new_null()) + || !TEST_true(sk_X509_push(extra, fresh_cert))) + goto err; + fresh_cert = NULL; /* ownership now with the stack */ + + if (!TEST_true(OSSL_CMP_CTX_set1_extraCertsOut(client_ctx, extra))) + goto err; + + /* PBM protection with a secret the server ctx will never be given */ + memset(ref, (unsigned char)(0xA0 + (index & 0x0F)), sizeof(ref)); + memset(secret, (unsigned char)(0x50 + (index & 0x0F)), sizeof(secret)); + if (!TEST_true(OSSL_CMP_CTX_set_option(client_ctx, + OSSL_CMP_OPT_UNPROTECTED_SEND, 0)) + || !TEST_true(OSSL_CMP_CTX_set1_referenceValue(client_ctx, ref, + sizeof(ref))) + || !TEST_true(OSSL_CMP_CTX_set1_secretValue(client_ctx, secret, + sizeof(secret)))) + goto err; + + /* GenMsg is the lightest standard body type for this purpose */ + if (!TEST_ptr(msg = ossl_cmp_genm_new(client_ctx))) + goto err; + + sk_X509_pop_free(extra, X509_free); + X509_free(fresh_cert); + EVP_PKEY_free(pkey); + OSSL_CMP_CTX_free(client_ctx); + return msg; + +err: + sk_X509_pop_free(extra, X509_free); + X509_free(fresh_cert); + EVP_PKEY_free(pkey); + OSSL_CMP_CTX_free(client_ctx); + OSSL_CMP_MSG_free(msg); + return NULL; +} + +/* + * Core assertion: N distinct rejected requests must not grow + * server_ctx->untrusted at all. + * + * Before the fix this fails with e.g.: + * ERROR: untrusted count after (25) != count before (0) + */ +static int execute_no_unbounded_growth_test(CMP_DOS_TEST_FIXTURE *fixture) +{ + OSSL_CMP_CTX *server_ctx = fixture->server_ctx; + int count_before, count_after, i; + + count_before = sk_X509_num(OSSL_CMP_CTX_get0_untrusted(server_ctx)); + if (count_before < 0) + count_before = 0; + + for (i = 0; i < NUM_REJECTED_REQUESTS; i++) { + OSSL_CMP_MSG *msg = build_rejectable_msg_with_unique_cert(i); + int check_result; + + if (!TEST_ptr(msg)) + return 0; + + check_result = ossl_cmp_msg_check_update(server_ctx, msg, NULL, 0); + OSSL_CMP_MSG_free(msg); + + if (!TEST_int_eq(check_result, 0)) { + TEST_note("expected request #%d to be rejected (server ctx has" + " no matching PBM secret) but it was accepted -- test" + " setup is wrong, not exercising the rejection path", + i); + return 0; + } + } + + count_after = sk_X509_num(OSSL_CMP_CTX_get0_untrusted(server_ctx)); + if (count_after < 0) + count_after = 0; + + if (!TEST_int_eq(count_after, count_before)) { + TEST_note("server_ctx->untrusted grew from %d to %d after %d" + " rejected requests -- failed-request extraCerts caching" + " bug is present (see ossl_cmp_msg_check_update() in" + " crypto/cmp/cmp_vfy.c)", + count_before, count_after, + NUM_REJECTED_REQUESTS); + return 0; + } + return 1; +} + +/* + * Single-request variant of the same check, useful in isolation since it + * pins down that even ONE rejected request leaves no residue -- ruling out + * X509_ADD_FLAG_NO_DUP coincidentally masking the bug in the N-request test. + */ +static int execute_single_rejected_request_test(CMP_DOS_TEST_FIXTURE *fixture) +{ + OSSL_CMP_CTX *server_ctx = fixture->server_ctx; + OSSL_CMP_MSG *msg = build_rejectable_msg_with_unique_cert(999); + int count_before, count_after; + + if (!TEST_ptr(msg)) + return 0; + + count_before = sk_X509_num(OSSL_CMP_CTX_get0_untrusted(server_ctx)); + if (count_before < 0) + count_before = 0; + + if (!TEST_int_eq(ossl_cmp_msg_check_update(server_ctx, msg, NULL, 0), 0)) { + OSSL_CMP_MSG_free(msg); + return 0; + } + OSSL_CMP_MSG_free(msg); + + count_after = sk_X509_num(OSSL_CMP_CTX_get0_untrusted(server_ctx)); + if (count_after < 0) + count_after = 0; + + return TEST_int_eq(count_after, count_before); +} + +static int test_single_rejected_request_leaves_no_residue(void) +{ + SETUP_TEST_FIXTURE(CMP_DOS_TEST_FIXTURE, set_up); + EXECUTE_TEST(execute_single_rejected_request_test, tear_down); + return result; +} + +static int test_no_unbounded_growth_on_rejected_requests(void) +{ + SETUP_TEST_FIXTURE(CMP_DOS_TEST_FIXTURE, set_up); + EXECUTE_TEST(execute_no_unbounded_growth_test, tear_down); + return result; +} + +int setup_tests(void) +{ + ADD_TEST(test_single_rejected_request_leaves_no_residue); + ADD_TEST(test_no_unbounded_growth_on_rejected_requests); + return 1; +} diff --git a/test/cmp_protect_test.c b/test/cmp_protect_test.c index 3bbdc095199b4..dce083714393f 100644 --- a/test/cmp_protect_test.c +++ b/test/cmp_protect_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2007-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2007-2026 The OpenSSL Project Authors. All Rights Reserved. * Copyright Nokia 2007-2019 * Copyright Siemens AG 2015-2019 * @@ -185,6 +185,38 @@ static int test_cmp_calc_protection_pbmac(void) EXECUTE_TEST(execute_calc_protection_pbmac_test, tear_down); return result; } + +/* + * Regression test for the ossl_cmp_calc_protection() protectionAlg + * type-confusion DoS: a PKIMessage whose protectionAlg has the + * id-PasswordBasedMAC OID but carries a BOOLEAN parameter instead of the + * expected PBMParameter SEQUENCE. X509_ALGOR_get0() then returns the boolean's + * union member (0xff) via ppval; the unpatched code took the non-NULL ppval as + * a valid ASN1_STRING * and dereferenced 0xff, crashing with a near-NULL + * access. The fixed code must reject the malformed parameter and return NULL. + */ +static int test_cmp_calc_protection_pbmac_bad_alg_param(void) +{ + unsigned char sec_insta[] = { 'i', 'n', 's', 't', 'a' }; + X509_ALGOR *alg = NULL; + + SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up); + if (!TEST_true(OSSL_CMP_CTX_set1_secretValue(fixture->cmp_ctx, + sec_insta, sizeof(sec_insta))) + || !TEST_ptr(fixture->msg = load_pkimsg(ip_PBM_f, libctx)) + || !TEST_ptr(alg = X509_ALGOR_new()) + || !TEST_true(X509_ALGOR_set0(alg, OBJ_nid2obj(NID_id_PasswordBasedMAC), + V_ASN1_BOOLEAN, (void *)1))) { + X509_ALGOR_free(alg); + tear_down(fixture); + fixture = NULL; + } else { + X509_ALGOR_free(fixture->msg->header->protectionAlg); + fixture->msg->header->protectionAlg = alg; + } + EXECUTE_TEST(execute_calc_protection_fails_test, tear_down); + return result; +} static int execute_MSG_protect_test(CMP_PROTECT_TEST_FIXTURE *fixture) { return TEST_int_eq(fixture->expected, @@ -609,6 +641,7 @@ int setup_tests(void) ADD_TEST(test_cmp_calc_protection_pkey_Ed); #endif ADD_TEST(test_cmp_calc_protection_pbmac); + ADD_TEST(test_cmp_calc_protection_pbmac_bad_alg_param); ADD_TEST(test_MSG_protect_with_msg_sig_alg_protection_plus_rsa_key); ADD_TEST(test_MSG_protect_with_certificate_and_key); diff --git a/test/cmp_vfy_test.c b/test/cmp_vfy_test.c index 70d776c0f572e..d18e2eb533ead 100644 --- a/test/cmp_vfy_test.c +++ b/test/cmp_vfy_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2007-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2007-2026 The OpenSSL Project Authors. All Rights Reserved. * Copyright Nokia 2007-2019 * Copyright Siemens AG 2015-2019 * @@ -572,6 +572,55 @@ static int test_msg_check_recipient_nonce_bad(void) } #endif +/* Regression test for CVE-2026-63073 */ +static int execute_msg_check_update_malicious_sender(CMP_VFY_TEST_FIXTURE *fixture) +{ + const char *data = NULL; + unsigned long err; + + if (!TEST_int_eq(ossl_cmp_msg_check_update(fixture->cmp_ctx, fixture->msg, NULL, 0), 0) + || !TEST_int_ne((err = ERR_peek_last_error_all(NULL, NULL, NULL, &data, NULL)), 0) + || !TEST_int_eq(ERR_GET_LIB(err), ERR_LIB_CMP) + || !TEST_int_eq(ERR_GET_REASON(err), CMP_R_UNEXPECTED_SENDER) + || !TEST_ptr(data) + || !TEST_str_eq(data, "/CN=%n")) + return 0; + return 1; +} + +static int test_msg_check_update_malicious_sender(void) +{ + OSSL_CMP_PKIHEADER *hdr; + X509_NAME *expected = X509_NAME_new(); + X509_NAME *actual = X509_NAME_new(); + + if (expected == NULL || actual == NULL) { + X509_NAME_free(expected); + return 0; + } + + SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up); + if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_f, libctx)) + || !TEST_ptr(hdr = OSSL_CMP_MSG_get0_header(fixture->msg)) + || !TEST_int_eq(X509_NAME_add_entry_by_txt(expected, "CN", MBSTRING_ASC, + (unsigned char *)"%n", -1, -1, 0), + 1) + || !TEST_int_eq(X509_NAME_add_entry_by_txt(actual, "CN", MBSTRING_ASC, + (unsigned char *)"actual", -1, -1, 0), + 1) + || !TEST_int_eq(ossl_cmp_hdr_set1_sender(hdr, expected), 1) + || !TEST_int_eq(OSSL_CMP_CTX_set1_expected_sender(fixture->cmp_ctx, actual), 1)) { + X509_NAME_free(expected); + X509_NAME_free(actual); + tear_down(fixture); + return 0; + } + EXECUTE_TEST(execute_msg_check_update_malicious_sender, tear_down); + X509_NAME_free(expected); + X509_NAME_free(actual); + return result; +} + void cleanup_tests(void) { X509_free(srvcert); @@ -712,6 +761,7 @@ int setup_tests(void) #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION ADD_TEST(test_msg_check_recipient_nonce_bad); #endif + ADD_TEST(test_msg_check_update_malicious_sender); return 1; diff --git a/test/cmsapitest.c b/test/cmsapitest.c index 2b5d08329ba68..cc58641e89a34 100644 --- a/test/cmsapitest.c +++ b/test/cmsapitest.c @@ -22,6 +22,7 @@ static EVP_PKEY *privkey = NULL; static char *derin = NULL; static char *too_long_iv_cms_in = NULL; static char *pwri_kek_oob_der_in = NULL; +static char *ec_recip_in = NULL; /* * This is our bad cms data, it contains an AuthEnvelopedData field @@ -739,7 +740,100 @@ static int test_pwri_kek_unwrap_short_encrypted_key(void) return ret; } -OPT_TEST_DECLARE_USAGE("certfile privkeyfile derfile tooLongIVpem pwriKekOobDer\n") +#ifndef OPENSSL_NO_EC + +/* + * Regression test for CVE-2026-63072: an 8-byte out-of-bounds heap write + * reachable through CMS_decrypt() when a KeyAgreeRecipientInfo names an + * id-aesNNN-wrap-pad key-wrap OID. CMS sizes the unwrap output buffer from + * the cipher's length query (inlen - 8), but AES-WRAP-PAD unwrap cleanses + * inlen bytes of it on every RFC 5649 integrity-failure path. + * + * We build a valid ECDH KARI message (which uses non-padded id-aes256-wrap), + * flip the single OID byte an attacker would flip on the wire to turn it into + * id-aes256-wrap-pad (key length unchanged), and decrypt with the matching + * private key. The unwrap must fail its integrity check without writing past + * the CMS-allocated buffer; CMS_decrypt() must fail cleanly. Under a + * memory-checking build (e.g. valgrind) the overflow is flagged directly. + */ +static int test_kari_wrap_pad_unwrap_overflow(void) +{ + /* DER encoding of the id-aes256-wrap OID (2.16.840.1.101.3.4.1.45). */ + static const unsigned char aes256_wrap_oid[] = { + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2d + }; + int ret = 0; + X509 *eccert = NULL; + EVP_PKEY *eckey = NULL; + BIO *certbio = NULL, *keybio = NULL, *msgbio = NULL, *outbio = NULL; + STACK_OF(X509) *recips = NULL; + CMS_ContentInfo *cms = NULL, *cms2 = NULL; + unsigned char *der = NULL; + const unsigned char *p; + int derlen, i, patched = 0; + const char *msg = "secret content for kari"; + + if ((certbio = BIO_new_file(ec_recip_in, "r")) == NULL + || PEM_read_bio_X509(certbio, &eccert, NULL, NULL) == NULL + || (keybio = BIO_new_file(ec_recip_in, "r")) == NULL + || PEM_read_bio_PrivateKey(keybio, &eckey, NULL, NULL) == NULL) { + goto end; + } + + if (!TEST_ptr(recips = sk_X509_new_null()) + || !TEST_int_gt(sk_X509_push(recips, eccert), 0)) + goto end; + + /* Build a normal ECDH KARI message; it uses non-padded id-aes256-wrap. */ + if (!TEST_ptr(msgbio = BIO_new_mem_buf(msg, (int)strlen(msg))) + || !TEST_ptr(cms = CMS_encrypt(recips, msgbio, EVP_aes_256_cbc(), + CMS_BINARY))) + goto end; + + if (!TEST_int_gt(derlen = i2d_CMS_ContentInfo(cms, &der), 0)) + goto end; + + /* Swap id-aes256-wrap -> id-aes256-wrap-pad (0x2d -> 0x30). */ + for (i = 0; i + (int)sizeof(aes256_wrap_oid) <= derlen; i++) { + if (memcmp(der + i, aes256_wrap_oid, sizeof(aes256_wrap_oid)) == 0) { + der[i + sizeof(aes256_wrap_oid) - 1] = 0x30; + patched = 1; + break; + } + } + if (!TEST_true(patched)) + goto end; + + p = der; + if (!TEST_ptr(cms2 = d2i_CMS_ContentInfo(NULL, &p, derlen))) + goto end; + + /* + * The wrap-pad unwrap fails the AIV check; with the fix it does so without + * writing past the CMS-allocated buffer. CMS_decrypt() must fail cleanly. + */ + if (!TEST_ptr(outbio = BIO_new(BIO_s_mem())) + || !TEST_false(CMS_decrypt(cms2, eckey, eccert, NULL, outbio, 0))) + goto end; + + ret = 1; +end: + ERR_clear_error(); + OPENSSL_free(der); + sk_X509_free(recips); + CMS_ContentInfo_free(cms); + CMS_ContentInfo_free(cms2); + BIO_free(certbio); + BIO_free(keybio); + BIO_free(msgbio); + BIO_free(outbio); + X509_free(eccert); + EVP_PKEY_free(eckey); + return ret; +} +#endif + +OPT_TEST_DECLARE_USAGE("certfile privkeyfile derfile tooLongIVpem pwriKekOobDer ecrecip\n") int setup_tests(void) { @@ -755,7 +849,8 @@ int setup_tests(void) || !TEST_ptr(privkeyin = test_get_argument(1)) || !TEST_ptr(derin = test_get_argument(2)) || !TEST_ptr(too_long_iv_cms_in = test_get_argument(3)) - || !TEST_ptr(pwri_kek_oob_der_in = test_get_argument(4))) + || !TEST_ptr(pwri_kek_oob_der_in = test_get_argument(4)) + || !TEST_ptr(ec_recip_in = test_get_argument(5))) return 0; certbio = BIO_new_file(certin, "r"); @@ -796,6 +891,10 @@ int setup_tests(void) ADD_ALL_TESTS(test_d2i_CMS_decode, 2); ADD_TEST(test_cms_aesgcm_iv_too_long); ADD_TEST(test_pwri_kek_unwrap_short_encrypted_key); + +#ifndef OPENSSL_NO_EC + ADD_TEST(test_kari_wrap_pad_unwrap_overflow); +#endif return 1; } diff --git a/test/crltest.c b/test/crltest.c index b89bef9c67357..c4419e299b7b3 100644 --- a/test/crltest.c +++ b/test/crltest.c @@ -1,5 +1,5 @@ /* - * Copyright 2015-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2015-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -26,6 +26,34 @@ * https://github.com/openssl/openssl/issues/27506 are used. */ +static const char *kRoot[] = { + "-----BEGIN CERTIFICATE-----\n", + "MIIEFjCCAv6gAwIBAgIUQR1kHB+/IzJcfAT/HHVPp+wPmxwwDQYJKoZIhvcNAQEL\n", + "BQAwgZAxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH\n", + "DA1TYW4gRnJhbmNpc2NvMRUwEwYDVQQKDAxFeGFtcGxlIENvcnAxHjAcBgNVBAsM\n", + "FUNlcnRpZmljYXRlIEF1dGhvcml0eTEdMBsGA1UEAwwURXhhbXBsZSBDb3JwIFJv\n", + "b3QgQ0EwHhcNMjYwMzEwMTEzMDUzWhcNMzYwMzA3MTEzMDUzWjCBkDELMAkGA1UE\n", + "BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lz\n", + "Y28xFTATBgNVBAoMDEV4YW1wbGUgQ29ycDEeMBwGA1UECwwVQ2VydGlmaWNhdGUg\n", + "QXV0aG9yaXR5MR0wGwYDVQQDDBRFeGFtcGxlIENvcnAgUm9vdCBDQTCCASIwDQYJ\n", + "KoZIhvcNAQEBBQADggEPADCCAQoCggEBALm21ITU+2o6ZHWukCyBw9H270fSABYT\n", + "rl8lhPCcTXynW9tBeHAaV50WMiOxBl+thfv1fGS3t8BbyjEjP3I5LAkBS9dTUI7F\n", + "PSQnngBgKvKrpsnsiJXVhNOISm6GfT/EXj1NWKLXR3MXGIGfiVud5ln9CQxzaq3e\n", + "TzW8X8zsdv6WGaeRIBm48QYe8TkK/TDmvoYZ7fD9lPMk3AUoNasZfuPeGpzh1cBR\n", + "bfvOYEHJQ31+GFzrJFldqoaq/k0If/khwVgjOdmF+R25OCF0jsrMjmZ42Qr2cNrd\n", + "VYEIjQL2R1grCVCGaIagzQuyN0Qvvl5BXsHKI51TpDQlq9SFkCOvRckCAwEAAaNm\n", + "MGQwHQYDVR0OBBYEFP4UDhMbCWfLSg1L2k/z75C1Q9szMB8GA1UdIwQYMBaAFP4U\n", + "DhMbCWfLSg1L2k/z75C1Q9szMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/\n", + "BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQBcYi8b4tetG18ElSqF/CJkjm93xS6k\n", + "tk4jia0k+79FSAvy/TlcarBAe3PwlLA7GcLYDUmmM7GCiEMf91+c6dOmKkIdbw1B\n", + "FILQBnghZ9s+xl0+n1P0775dDWc0msXhXci/wcRK3HFqxEOXQUkDYZwrq1gXBESr\n", + "6yjpYe2RFKQUdnW+yrMlY1QyGNhelV7//BbSG8fD1esU7VaBE0wF/b8Ly2ykK5QE\n", + "d6XUwqTT6sIlcyxVGUgEMVj7kSZUQJ2LS/ze/r+a1FeC2I0UljD78UB+I40FafZe\n", + "pLLvkABIXRqtOiZ5YkdEK3Z4xI0yqSZC3og4jHsoCrfWbXasRieYR7dT\n", + "-----END CERTIFICATE-----\n", + NULL +}; + #define PARAM_TIME 1474934400 /* Sep 27th, 2016 */ #define PARAM_TIME2 1753284700 /* July 23th, 2025 */ @@ -329,6 +357,52 @@ static X509 *X509_from_strings(const char **pem) return x; } +/* + * A well-formed CRL issued by kRoot (sha256WithRSAEncryption, inner and + * outer signatureAlgorithm identical), used as the positive test case in + * test_crl_sigalg_mismatch. + */ +static const char *kCrlRootCA[] = { + "-----BEGIN X509 CRL-----\n", + "MIIB2jCBwwIBATANBgkqhkiG9w0BAQsFADCBkDELMAkGA1UEBhMCVVMxEzARBgNV\n", + "BAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xFTATBgNVBAoM\n", + "DEV4YW1wbGUgQ29ycDEeMBwGA1UECwwVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR0w\n", + "GwYDVQQDDBRFeGFtcGxlIENvcnAgUm9vdCBDQRcNMjYwMTAxMDAwMDAwWhcNMjcw\n", + "MTAxMDAwMDAwWjANBgkqhkiG9w0BAQsFAAOCAQEAjLDGYBswRZpuaRh9qVXrP4i0\n", + "wttPikYZkkUk07/KU1zN6pS21Dqx1sEofrkqwRnKXq/hsoCz3sd7QFIv30v2iZwM\n", + "ioaksAjcGnaLqe8vuKVtIyiOpDSJR89l84BZr2I9+6osTYnPgroMHQ/7OUt+PKdE\n", + "1VAkA137tLMRw2qGPELdCyHA7LXr0gI6jeyLPLtb1blQrMzznp3y/trNWa+DKq6h\n", + "SflQrixmLeXTMBD/DDUd8Kj9HHmejbJNAsgaNHv9mtIhUVEspRM0020b3AeJyfTP\n", + "3oN/y4fgQ8q5v9i8lDbe8moCo+W0rS4ksWvB6SuYYj/NkUE4EtoIreSVtcz8JA==\n", + "-----END X509 CRL-----\n", + NULL +}; + +/* + * kCrlMismatchedSigAlg is issued by kRoot with a deliberately inconsistent + * pair of signatureAlgorithm fields: the inner (signed) copy inside + * TBSCertList claims ecdsaWithSHA256, while the outer wrapper carries + * sha256WithRSAEncryption -- and the actual signature is a valid RSA-SHA256 + * signature over that TBSCertList. Without the inner/outer comparison, + * X509_CRL_verify() would accept this CRL because the RSA signature checks + * out. RFC 5280 section 5.1.1.2 requires the two fields to be identical. + */ +static const char *kCrlMismatchedSigAlg[] = { + "-----BEGIN X509 CRL-----\n", + "MIIB1zCBwAIBATAKBggqhkjOPQQDAjCBkDELMAkGA1UEBhMCVVMxEzARBgNVBAgM\n", + "CkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xFTATBgNVBAoMDEV4\n", + "YW1wbGUgQ29ycDEeMBwGA1UECwwVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR0wGwYD\n", + "VQQDDBRFeGFtcGxlIENvcnAgUm9vdCBDQRcNMjYwMTAxMDAwMDAwWhcNMjcwMTAx\n", + "MDAwMDAwWjANBgkqhkiG9w0BAQsFAAOCAQEAcle5SUuN1XIx5amjddTqDPyEm9pP\n", + "sNeBwR+TQi19pWHtQ5anr6PBIAxHC5uxhVpZDScZu0TlodWigo+1bfAJRyrIm/6+\n", + "AbmAyNC4txpNsOHgCFGW7q9T8OutaOhUw+jC6i3bxUQZ64L1sXuy2nZMzU19+Aro\n", + "TxSWYkIJg65SKwM/8ggyd5G7TXkv7w19+W/7Y9JV0c+kPueUZSgEGUG/GJF/Nrrc\n", + "TRfvqz7Qs9H9+hUiQl5K7tF9gj6aU3p1s1IZKR2x0lv4wDRUUgIjrvRzfQSGjhgf\n", + "6rBILI3EIxPN/PoZ3mHLYkhH5IyNj9R2GlMle52isNdW8BiNlePLx0/Jzg==\n", + "-----END X509 CRL-----\n", + NULL +}; + /* * Verify |leaf| certificate (chained up to |root|). |crls| if * not NULL, is a list of CRLs to include in the verification. It is @@ -615,6 +689,53 @@ static int test_get_crl_fn_score(void) return status == X509_V_OK; } +/* + * Check that X509_CRL_verify() rejects a CRL where the outer + * signatureAlgorithm does not match the inner copy inside TBSCertList. + * RFC 5280 section 5.1.1.2 requires the two to be identical; X509_verify() + * and X509_ACERT_verify() enforce this, and so must X509_CRL_verify(). + * + * Both CRLs are issued by kRoot (RSA-2048). kCrlMismatchedSigAlg carries a + * valid RSA-SHA256 signature over a TBSCertList whose inner signatureAlgorithm + * claims ecdsaWithSHA256, while the outer wrapper carries the correct + * sha256WithRSAEncryption. Without the inner/outer comparison the signature + * would verify and the CRL would be accepted. + */ +static int test_crl_sigalg_mismatch(void) +{ + X509 *root = X509_from_strings(kRoot); + X509_CRL *good = CRL_from_strings(kCrlRootCA); + X509_CRL *bad = CRL_from_strings(kCrlMismatchedSigAlg); + EVP_PKEY *pkey = NULL; + int ret = 0; + + if (!TEST_ptr(root) || !TEST_ptr(good) || !TEST_ptr(bad)) + goto end; + + pkey = X509_get0_pubkey(root); + if (!TEST_ptr(pkey)) + goto end; + + /* Well-formed CRL: inner and outer algorithms match; verify succeeds. */ + if (!TEST_int_eq(X509_CRL_verify(good, pkey), 1)) + goto end; + + /* + * Mismatched CRL: inner signatureAlgorithm is ecdsaWithSHA256, outer is + * sha256WithRSAEncryption, RSA signature is valid. X509_ALGOR_cmp() + * must catch the mismatch before the signature is checked. + */ + if (!TEST_int_eq(X509_CRL_verify(bad, pkey), 0)) + goto end; + + ret = 1; +end: + X509_CRL_free(good); + X509_CRL_free(bad); + X509_free(root); + return ret; +} + int setup_tests(void) { if (!TEST_ptr(test_root = X509_from_strings(kCRLTestRoot)) @@ -631,6 +752,8 @@ int setup_tests(void) ADD_TEST(test_get_crl_fn_score); ADD_ALL_TESTS(test_unknown_critical_crl, OSSL_NELEM(unknown_critical_crls)); ADD_ALL_TESTS(test_reuse_crl, 6); + ADD_TEST(test_crl_sigalg_mismatch); + return 1; } diff --git a/test/endecode_test.c b/test/endecode_test.c index bd068b208a912..64701d32b86f8 100644 --- a/test/endecode_test.c +++ b/test/endecode_test.c @@ -60,6 +60,7 @@ static OSSL_PROVIDER *keyprov = NULL; #ifndef OPENSSL_NO_EC static BN_CTX *bnctx = NULL; +#ifndef OPENSSL_NO_EC_EXPLICIT_CURVES static OSSL_PARAM_BLD *bld_prime_nc = NULL; static OSSL_PARAM_BLD *bld_prime = NULL; static OSSL_PARAM *ec_explicit_prime_params_nc = NULL; @@ -72,6 +73,7 @@ static OSSL_PARAM *ec_explicit_tri_params_nc = NULL; static OSSL_PARAM *ec_explicit_tri_params_explicit = NULL; #endif #endif +#endif #ifndef OPENSSL_NO_KEYPARAMS static EVP_PKEY *make_template(const char *type, OSSL_PARAM *genparams) @@ -870,21 +872,403 @@ static int test_public_via_MSBLOB(const char *type, EVP_PKEY *key) test_mem, check_public_MSBLOB, dump_der, 0); } +/* + * Build a public-only EVP_PKEY of the same algorithm as |src| by + * round-tripping the public component through OSSL_PARAMs. + */ +static EVP_PKEY *make_public_only_copy(EVP_PKEY *src) +{ + OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *cctx = NULL; + EVP_PKEY *pub = NULL; + + if (!EVP_PKEY_todata(src, EVP_PKEY_PUBLIC_KEY, ¶ms)) + goto end; + if ((cctx = EVP_PKEY_CTX_new_from_pkey(NULL, src, NULL)) == NULL + || EVP_PKEY_fromdata_init(cctx) <= 0 + || EVP_PKEY_fromdata(cctx, &pub, EVP_PKEY_PUBLIC_KEY, params) <= 0) { + EVP_PKEY_free(pub); + pub = NULL; + } +end: + OSSL_PARAM_free(params); + EVP_PKEY_CTX_free(cctx); + return pub; +} + +/* + * Build an "embryonic" EVP_PKEY of the same algorithm as |src|: just + * the keymgmt-bound type and (where applicable) domain parameters, + * with no key material. Mirrors the idiom used in + * test/ml_kem_evp_extra_test.c. + */ +static EVP_PKEY *make_embryonic_copy(EVP_PKEY *src) +{ + EVP_PKEY *embryo = EVP_PKEY_new(); + + if (embryo == NULL) + return NULL; + if (EVP_PKEY_copy_parameters(embryo, src) <= 0) { + EVP_PKEY_free(embryo); + return NULL; + } + return embryo; +} + +/* + * Check that EVP_PKEY_dup() works for every supported provider-backed + * key type, and that the duplicate compares equal to the original. + * + * Exercised in three shapes: + * 1. The full keypair |key| (typically pub + priv). + * 2. A public-only key derived from |key|. + * 3. An "embryonic" key (algorithm + domain parameters only, no key + * material) produced with EVP_PKEY_copy_parameters(). Not every + * keymgmt allows building such a key (RSA's dup refuses any + * selection without keypair bits); when EVP_PKEY_copy_parameters + * fails we skip this arm with a TEST_info(). + */ +static int test_dup(const char *type, EVP_PKEY *key) +{ + EVP_PKEY *dup = NULL; + EVP_PKEY *pub_only = NULL; + EVP_PKEY *embryo = NULL; + int ok = 0; + + if (!TEST_ptr(key)) { + TEST_info("%s: no source key", type); + return 0; + } + + /* 1. Dup the full keypair. */ + if (!TEST_ptr(dup = EVP_PKEY_dup(key))) { + TEST_info("%s: EVP_PKEY_dup of keypair returned NULL", type); + goto end; + } + if (!TEST_int_eq(EVP_PKEY_eq(key, dup), 1)) { + TEST_info("%s: keypair dup does not compare equal to original", type); + goto end; + } + EVP_PKEY_free(dup); + dup = NULL; + + /* 2. Dup a public-only copy of the same key. */ + if (!TEST_ptr(pub_only = make_public_only_copy(key))) { + TEST_info("%s: could not derive a public-only key", type); + goto end; + } + if (!TEST_ptr(dup = EVP_PKEY_dup(pub_only))) { + TEST_info("%s: EVP_PKEY_dup of public-only key returned NULL", type); + goto end; + } + if (!TEST_int_eq(EVP_PKEY_eq(pub_only, dup), 1)) { + TEST_info("%s: public-only dup does not compare equal to original", + type); + goto end; + } + EVP_PKEY_free(dup); + dup = NULL; + + /* + * 3. Dup an embryonic key. EVP_PKEY_parameters_eq() answers 1 for + * algorithms with real domain parameters and may answer -2 ("nothing + * to compare") for those without. We only reject 0 (definitively + * unequal) and -1 (different keymgmts). + */ + embryo = make_embryonic_copy(key); + if (embryo != NULL) { + if (!TEST_ptr(dup = EVP_PKEY_dup(embryo))) { + TEST_info("%s: EVP_PKEY_dup of embryonic key returned NULL", + type); + goto end; + } + { + int eq = EVP_PKEY_parameters_eq(embryo, dup); + + if (!TEST_true(eq == 1 || eq == -2)) { + TEST_info("%s: embryonic dup parameters_eq %d (want 1 or -2)", + type, eq); + goto end; + } + } + } else { + TEST_info("%s: skipping embryonic dup (no params-only key shape)", + type); + } + + ok = 1; +end: + EVP_PKEY_free(dup); + EVP_PKEY_free(pub_only); + EVP_PKEY_free(embryo); + return ok; +} + +/* + * Drive EVP_PKEY_fromdata with the supplied OSSL_PARAM[] (NULL = + * empty array) for the given selection. Either outcome is accepted: + * fromdata may reject the input, or it may succeed and yield a key + * with at most algorithm-bound parameters. In the success case a + * battery of common consumer ops must not crash on the resulting + * key; their return values are not asserted. + */ +static int run_empty_fromdata_probe(const char *type, EVP_PKEY_CTX *cctx, + int selection, OSSL_PARAM *params, const char *selname) +{ + EVP_PKEY *pkey = NULL; + OSSL_PARAM empty[1]; + int r; + int ok = 0; + + if (params == NULL) { + empty[0] = OSSL_PARAM_construct_end(); + params = empty; + } + + if (!TEST_int_gt(EVP_PKEY_fromdata_init(cctx), 0)) { + TEST_info("%s: fromdata_init failed (%s)", type, selname); + goto end; + } + r = EVP_PKEY_fromdata(cctx, &pkey, selection, params); + if (r <= 0) { + /* Rejection is fine, but the out-pointer must remain NULL. */ + if (!TEST_ptr_null(pkey)) { + TEST_info("%s: fromdata returned %d but pkey != NULL (%s)", + type, r, selname); + goto end; + } + ok = 1; + goto end; + } + if (!TEST_ptr(pkey)) { + TEST_info("%s: fromdata returned %d but pkey == NULL (%s)", + type, r, selname); + goto end; + } + /* + * Walk a battery of common consumer ops on the resulting key. + * Their return values are not asserted - a contentless key may + * fail every op - only crashing is forbidden. + */ + (void)EVP_PKEY_get_bits(pkey); + (void)EVP_PKEY_get_security_bits(pkey); + (void)EVP_PKEY_get_size(pkey); + (void)EVP_PKEY_eq(pkey, pkey); + (void)EVP_PKEY_parameters_eq(pkey, pkey); + { + OSSL_PARAM *out = NULL; + + if (EVP_PKEY_todata(pkey, selection, &out) > 0) + OSSL_PARAM_free(out); + } + { + EVP_PKEY *clone = EVP_PKEY_dup(pkey); + + EVP_PKEY_free(clone); + } + { + BIO *bio = BIO_new(BIO_s_null()); + + if (bio != NULL) { + (void)EVP_PKEY_print_public(bio, pkey, 0, NULL); + (void)EVP_PKEY_print_private(bio, pkey, 0, NULL); + (void)EVP_PKEY_print_params(bio, pkey, 0, NULL); + BIO_free(bio); + } + } + { + /* The param/public/private/pairwise check family. */ + EVP_PKEY_CTX *vctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); + + if (vctx != NULL) { + (void)EVP_PKEY_param_check(vctx); + (void)EVP_PKEY_param_check_quick(vctx); + (void)EVP_PKEY_public_check(vctx); + (void)EVP_PKEY_public_check_quick(vctx); + (void)EVP_PKEY_private_check(vctx); + (void)EVP_PKEY_pairwise_check(vctx); + EVP_PKEY_CTX_free(vctx); + } + } + ok = 1; +end: + EVP_PKEY_free(pkey); + return ok; +} + +static int probe_empty_fromdata(const char *type, EVP_PKEY *prototype, + int selection, const char *selname) +{ + EVP_PKEY_CTX *cctx = NULL; + int ok = 0; + + if (!TEST_ptr(cctx = EVP_PKEY_CTX_new_from_pkey(NULL, prototype, NULL))) { + TEST_info("%s: CTX alloc failed for empty fromdata (%s)", + type, selname); + goto end; + } + ok = run_empty_fromdata_probe(type, cctx, selection, NULL, selname); +end: + EVP_PKEY_CTX_free(cctx); + return ok; +} + +/* + * Drive EVP_PKEY_fromdata with an empty OSSL_PARAM[] for both + * EVP_PKEY_PUBLIC_KEY and EVP_PKEY_KEYPAIR selections. Either + * outcome is acceptable: fromdata rejects, or it succeeds and the + * resulting key survives the consumer-op battery without crashing. + */ +static int test_fromdata(const char *type, EVP_PKEY *prototype) +{ + if (!TEST_ptr(prototype)) { + TEST_info("%s: no prototype key", type); + return 0; + } + if (!probe_empty_fromdata(type, prototype, EVP_PKEY_PUBLIC_KEY, + "EVP_PKEY_PUBLIC_KEY")) + return 0; + if (!probe_empty_fromdata(type, prototype, EVP_PKEY_KEYPAIR, + "EVP_PKEY_KEYPAIR")) + return 0; + return 1; +} + +/* + * Named-group-only partial-shape variants for prototype-matrix + * algorithms, plus any keymgmts without a keygen path. Each entry + * is one (name, selection, params-builder) shape; a NULL builder + * means "use an empty OSSL_PARAM[]". Algorithms not loadable under + * the active provider set are silently skipped. + */ +typedef int (*fromdata_shape_build_fn)(OSSL_PARAM_BLD *bld); + +struct fromdata_shape { + const char *name; /* keymgmt algorithm name */ + int selection; /* EVP_PKEY_PUBLIC_KEY / KEYPAIR / etc. */ + fromdata_shape_build_fn build; /* NULL -> empty OSSL_PARAM[] */ + const char *label; /* diagnostic label */ +}; + +#ifndef OPENSSL_NO_DH +static int build_dh_named_group(OSSL_PARAM_BLD *bld) +{ + return OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME, + "ffdhe2048", 0); +} +#endif + +#ifndef OPENSSL_NO_EC +static int build_ec_named_group(OSSL_PARAM_BLD *bld) +{ + return OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME, + "P-256", 0); +} +#ifndef OPENSSL_NO_SM2 +static int build_sm2_named_group(OSSL_PARAM_BLD *bld) +{ + return OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME, + "SM2", 0); +} +#endif +#endif + +#if defined(OPENSSL_NO_DH) && defined(OPENSSL_NO_EC) && defined(OPENSSL_NO_SM2) +#undef TEST_FROMDATA_NO_KEYGEN +#else +#define TEST_FROMDATA_NO_KEYGEN + +static const struct fromdata_shape no_keygen_shapes[] = { +/* Named-group-only partial shapes. */ +#ifndef OPENSSL_NO_DH + { "DH", EVP_PKEY_KEYPAIR, build_dh_named_group, + "DH / named group only / KEYPAIR" }, + { "DH", EVP_PKEY_PUBLIC_KEY, build_dh_named_group, + "DH / named group only / PUBLIC_KEY" }, +#endif +#ifndef OPENSSL_NO_EC + { "EC", EVP_PKEY_KEYPAIR, build_ec_named_group, + "EC / group only / KEYPAIR" }, + { "EC", EVP_PKEY_PUBLIC_KEY, build_ec_named_group, + "EC / group only / PUBLIC_KEY" }, +#ifndef OPENSSL_NO_SM2 + { "SM2", EVP_PKEY_KEYPAIR, build_sm2_named_group, + "SM2 / group only / KEYPAIR" }, +#endif +#endif +}; + +/* + * Probe an algorithm by name rather than a prototype key, for keymgmts without + * a keygen path. Algorithms not loadable under the active provider set are + * silently skipped. |params| may be NULL (= empty OSSL_PARAM[]) or a + * caller-built partial array. + */ +static int probe_fromdata_by_name(const char *name, int selection, + OSSL_PARAM *params, const char *selname) +{ + EVP_PKEY_CTX *cctx = NULL; + int ok = 1; + + cctx = EVP_PKEY_CTX_new_from_name(NULL, name, NULL); + if (cctx == NULL) + return 1; + ok = run_empty_fromdata_probe(name, cctx, selection, params, selname); + EVP_PKEY_CTX_free(cctx); + return ok; +} + +static int test_fromdata_no_keygen(void) +{ + size_t i; + + for (i = 0; i < OSSL_NELEM(no_keygen_shapes); i++) { + const struct fromdata_shape *s = &no_keygen_shapes[i]; + OSSL_PARAM_BLD *bld = NULL; + OSSL_PARAM *params = NULL; + int ok; + + if (s->build != NULL) { + if (!TEST_ptr(bld = OSSL_PARAM_BLD_new())) + return 0; + if (!s->build(bld)) { + TEST_info("%s: builder failed", s->label); + OSSL_PARAM_BLD_free(bld); + return 0; + } + params = OSSL_PARAM_BLD_to_param(bld); + if (!TEST_ptr(params)) { + OSSL_PARAM_BLD_free(bld); + return 0; + } + } + ok = probe_fromdata_by_name(s->name, s->selection, params, s->label); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(bld); + if (!ok) + return 0; + } + return 1; +} +#endif + #define KEYS(KEYTYPE) \ static EVP_PKEY *key_##KEYTYPE = NULL #define MAKE_KEYS(KEYTYPE, KEYTYPEstr, params) \ - ok = ok \ - && TEST_ptr(key_##KEYTYPE = make_key(KEYTYPEstr, NULL, params)) + ok &= TEST_ptr(key_##KEYTYPE = make_key(KEYTYPEstr, NULL, params)) #define FREE_KEYS(KEYTYPE) \ EVP_PKEY_free(key_##KEYTYPE); #define DOMAIN_KEYS(KEYTYPE) \ static EVP_PKEY *template_##KEYTYPE = NULL; \ static EVP_PKEY *key_##KEYTYPE = NULL -#define MAKE_DOMAIN_KEYS(KEYTYPE, KEYTYPEstr, params) \ - ok = ok \ - && TEST_ptr(template_##KEYTYPE = make_template(KEYTYPEstr, params)) \ - && TEST_ptr(key_##KEYTYPE = make_key(KEYTYPEstr, template_##KEYTYPE, NULL)) +#define MAKE_DOMAIN_KEYS(KEYTYPE, KEYTYPEstr, params) \ + do { \ + ok &= TEST_ptr(template_##KEYTYPE = make_template(KEYTYPEstr, \ + params)); \ + ok &= TEST_ptr(key_##KEYTYPE = make_key(KEYTYPEstr, \ + template_##KEYTYPE, NULL)); \ + } while (0) #define FREE_DOMAIN_KEYS(KEYTYPE) \ EVP_PKEY_free(template_##KEYTYPE); \ EVP_PKEY_free(key_##KEYTYPE) @@ -913,15 +1297,29 @@ static int test_public_via_MSBLOB(const char *type, EVP_PKEY *key) static int test_public_##KEYTYPE##_via_PEM(void) \ { \ return test_public_via_PEM(KEYTYPEstr, key_##KEYTYPE, fips); \ + } \ + static int test_dup_##KEYTYPE(void) \ + { \ + return test_dup(KEYTYPEstr, key_##KEYTYPE); \ + } \ + static int test_fromdata_##KEYTYPE(void) \ + { \ + return test_fromdata(KEYTYPEstr, key_##KEYTYPE); \ } -#define ADD_TEST_SUITE(KEYTYPE) \ - ADD_TEST(test_unprotected_##KEYTYPE##_via_DER); \ - ADD_TEST(test_unprotected_##KEYTYPE##_via_PEM); \ - ADD_TEST(test_protected_##KEYTYPE##_via_DER); \ - ADD_TEST(test_protected_##KEYTYPE##_via_PEM); \ - ADD_TEST(test_public_##KEYTYPE##_via_DER); \ - ADD_TEST(test_public_##KEYTYPE##_via_PEM) +#define ADD_TEST_SUITE(KEYTYPE) \ + do { \ + if (key_##KEYTYPE != NULL) { \ + ADD_TEST(test_unprotected_##KEYTYPE##_via_DER); \ + ADD_TEST(test_unprotected_##KEYTYPE##_via_PEM); \ + ADD_TEST(test_protected_##KEYTYPE##_via_DER); \ + ADD_TEST(test_protected_##KEYTYPE##_via_PEM); \ + ADD_TEST(test_public_##KEYTYPE##_via_DER); \ + ADD_TEST(test_public_##KEYTYPE##_via_PEM); \ + ADD_TEST(test_dup_##KEYTYPE); \ + ADD_TEST(test_fromdata_##KEYTYPE); \ + } \ + } while (0) #define IMPLEMENT_TEST_SUITE_PARAMS(KEYTYPE, KEYTYPEstr) \ static int test_params_##KEYTYPE##_via_DER(void) \ @@ -933,9 +1331,13 @@ static int test_public_via_MSBLOB(const char *type, EVP_PKEY *key) return test_params_via_PEM(KEYTYPEstr, key_##KEYTYPE); \ } -#define ADD_TEST_SUITE_PARAMS(KEYTYPE) \ - ADD_TEST(test_params_##KEYTYPE##_via_DER); \ - ADD_TEST(test_params_##KEYTYPE##_via_PEM) +#define ADD_TEST_SUITE_PARAMS(KEYTYPE) \ + do { \ + if (key_##KEYTYPE != NULL) { \ + ADD_TEST(test_params_##KEYTYPE##_via_DER); \ + ADD_TEST(test_params_##KEYTYPE##_via_PEM); \ + } \ + } while (0) #define IMPLEMENT_TEST_SUITE_LEGACY(KEYTYPE, KEYTYPEstr) \ static int test_unprotected_##KEYTYPE##_via_legacy_PEM(void) \ @@ -947,9 +1349,13 @@ static int test_public_via_MSBLOB(const char *type, EVP_PKEY *key) return test_protected_via_legacy_PEM(KEYTYPEstr, key_##KEYTYPE); \ } -#define ADD_TEST_SUITE_LEGACY(KEYTYPE) \ - ADD_TEST(test_unprotected_##KEYTYPE##_via_legacy_PEM); \ - ADD_TEST(test_protected_##KEYTYPE##_via_legacy_PEM) +#define ADD_TEST_SUITE_LEGACY(KEYTYPE) \ + do { \ + if (key_##KEYTYPE != NULL) { \ + ADD_TEST(test_unprotected_##KEYTYPE##_via_legacy_PEM); \ + ADD_TEST(test_protected_##KEYTYPE##_via_legacy_PEM); \ + } \ + } while (0) #define IMPLEMENT_TEST_SUITE_MSBLOB(KEYTYPE, KEYTYPEstr) \ static int test_unprotected_##KEYTYPE##_via_MSBLOB(void) \ @@ -961,25 +1367,35 @@ static int test_public_via_MSBLOB(const char *type, EVP_PKEY *key) return test_public_via_MSBLOB(KEYTYPEstr, key_##KEYTYPE); \ } -#define ADD_TEST_SUITE_MSBLOB(KEYTYPE) \ - ADD_TEST(test_unprotected_##KEYTYPE##_via_MSBLOB); \ - ADD_TEST(test_public_##KEYTYPE##_via_MSBLOB) +#define ADD_TEST_SUITE_MSBLOB(KEYTYPE) \ + do { \ + if (key_##KEYTYPE != NULL) { \ + ADD_TEST(test_unprotected_##KEYTYPE##_via_MSBLOB); \ + ADD_TEST(test_public_##KEYTYPE##_via_MSBLOB); \ + } \ + } while (0) #define IMPLEMENT_TEST_SUITE_UNPROTECTED_PVK(KEYTYPE, KEYTYPEstr) \ static int test_unprotected_##KEYTYPE##_via_PVK(void) \ { \ return test_unprotected_via_PVK(KEYTYPEstr, key_##KEYTYPE); \ } -#define ADD_TEST_SUITE_UNPROTECTED_PVK(KEYTYPE) \ - ADD_TEST(test_unprotected_##KEYTYPE##_via_PVK) +#define ADD_TEST_SUITE_UNPROTECTED_PVK(KEYTYPE) \ + do { \ + if (key_##KEYTYPE != NULL) \ + ADD_TEST(test_unprotected_##KEYTYPE##_via_PVK); \ + } while (0) #ifndef OPENSSL_NO_RC4 #define IMPLEMENT_TEST_SUITE_PROTECTED_PVK(KEYTYPE, KEYTYPEstr) \ static int test_protected_##KEYTYPE##_via_PVK(void) \ { \ return test_protected_via_PVK(KEYTYPEstr, key_##KEYTYPE); \ } -#define ADD_TEST_SUITE_PROTECTED_PVK(KEYTYPE) \ - ADD_TEST(test_protected_##KEYTYPE##_via_PVK) +#define ADD_TEST_SUITE_PROTECTED_PVK(KEYTYPE) \ + do { \ + if (key_##KEYTYPE != NULL) \ + ADD_TEST(test_protected_##KEYTYPE##_via_PVK); \ + } while (0) #endif #ifndef OPENSSL_NO_DH @@ -1010,6 +1426,7 @@ DOMAIN_KEYS(EC); IMPLEMENT_TEST_SUITE(EC, "EC", 1) IMPLEMENT_TEST_SUITE_PARAMS(EC, "EC") IMPLEMENT_TEST_SUITE_LEGACY(EC, "EC") +#ifndef OPENSSL_NO_EC_EXPLICIT_CURVES DOMAIN_KEYS(ECExplicitPrimeNamedCurve); IMPLEMENT_TEST_SUITE(ECExplicitPrimeNamedCurve, "EC", 1) IMPLEMENT_TEST_SUITE_LEGACY(ECExplicitPrimeNamedCurve, "EC") @@ -1024,6 +1441,7 @@ DOMAIN_KEYS(ECExplicitTri2G); IMPLEMENT_TEST_SUITE(ECExplicitTri2G, "EC", 0) IMPLEMENT_TEST_SUITE_LEGACY(ECExplicitTri2G, "EC") #endif +#endif /* OPENSSL_NO_EC_EXPLICIT_CURVES */ #ifndef OPENSSL_NO_SM2 KEYS(SM2); IMPLEMENT_TEST_SUITE(SM2, "SM2", 0) @@ -1106,6 +1524,7 @@ IMPLEMENT_TEST_SUITE(ML_DSA_87, "ML-DSA-87", 1) #endif /* OPENSSL_NO_ML_DSA */ #ifndef OPENSSL_NO_EC +#ifndef OPENSSL_NO_EC_EXPLICIT_CURVES /* Explicit parameters that match a named curve */ static int do_create_ec_explicit_prime_params(OSSL_PARAM_BLD *bld, const unsigned char *gen, @@ -1286,6 +1705,7 @@ static int create_ec_explicit_trinomial_params(OSSL_PARAM_BLD *bld) return do_create_ec_explicit_trinomial_params(bld, gen2, sizeof(gen2)); } #endif /* OPENSSL_NO_EC2M */ +#endif /* OPENSSL_NO_EC_EXPLICIT_CURVES */ /* * Test that multiple calls to OSSL_ENCODER_to_data() do not cause side effects @@ -1425,8 +1845,10 @@ int setup_tests(void) return 0; #ifndef OPENSSL_NO_EC - if (!TEST_ptr(bnctx = BN_CTX_new_ex(testctx)) - || !TEST_ptr(bld_prime_nc = OSSL_PARAM_BLD_new()) + if (!TEST_ptr(bnctx = BN_CTX_new_ex(testctx))) + return 0; +#ifndef OPENSSL_NO_EC_EXPLICIT_CURVES + if (!TEST_ptr(bld_prime_nc = OSSL_PARAM_BLD_new()) || !TEST_ptr(bld_prime = OSSL_PARAM_BLD_new()) || !create_ec_explicit_prime_params_namedcurve(bld_prime_nc) || !create_ec_explicit_prime_params(bld_prime) @@ -1442,6 +1864,7 @@ int setup_tests(void) #endif ) return 0; +#endif /* OPENSSL_NO_EC_EXPLICIT_CURVES */ #endif TEST_info("Generating keys..."); @@ -1458,12 +1881,14 @@ int setup_tests(void) #ifndef OPENSSL_NO_EC TEST_info("Generating EC keys..."); MAKE_DOMAIN_KEYS(EC, "EC", EC_params); +#ifndef OPENSSL_NO_EC_EXPLICIT_CURVES MAKE_DOMAIN_KEYS(ECExplicitPrimeNamedCurve, "EC", ec_explicit_prime_params_nc); MAKE_DOMAIN_KEYS(ECExplicitPrime2G, "EC", ec_explicit_prime_params_explicit); #ifndef OPENSSL_NO_EC2M MAKE_DOMAIN_KEYS(ECExplicitTriNamedCurve, "EC", ec_explicit_tri_params_nc); MAKE_DOMAIN_KEYS(ECExplicitTri2G, "EC", ec_explicit_tri_params_explicit); #endif +#endif /* OPENSSL_NO_EC_EXPLICIT_CURVES */ #ifndef OPENSSL_NO_SM2 MAKE_KEYS(SM2, "SM2", NULL); #endif @@ -1506,12 +1931,17 @@ int setup_tests(void) #endif /* OPENSSL_NO_SLH_DSA */ TEST_info("Loading RSA key..."); - ok = ok && TEST_ptr(key_RSA = load_pkey_pem(rsa_file, keyctx)); + ok &= TEST_ptr(key_RSA = load_pkey_pem(rsa_file, keyctx)); TEST_info("Loading RSA_PSS key..."); - ok = ok && TEST_ptr(key_RSA_PSS = load_pkey_pem(rsa_pss_file, keyctx)); + ok &= TEST_ptr(key_RSA_PSS = load_pkey_pem(rsa_pss_file, keyctx)); TEST_info("Generating keys done"); - if (ok) { + /* + * Register every test whose key was successfully generated. The + * per-algorithm key_##KEYTYPE != NULL guard inside each + * ADD_TEST_SUITE* macro keeps us from referencing missing keys. + */ + { #ifndef OPENSSL_NO_DH ADD_TEST_SUITE(DH); ADD_TEST_SUITE_PARAMS(DH); @@ -1537,6 +1967,7 @@ int setup_tests(void) ADD_TEST_SUITE(EC); ADD_TEST_SUITE_PARAMS(EC); ADD_TEST_SUITE_LEGACY(EC); +#ifndef OPENSSL_NO_EC_EXPLICIT_CURVES ADD_TEST_SUITE(ECExplicitPrimeNamedCurve); ADD_TEST_SUITE_LEGACY(ECExplicitPrimeNamedCurve); ADD_TEST_SUITE(ECExplicitPrime2G); @@ -1547,6 +1978,7 @@ int setup_tests(void) ADD_TEST_SUITE(ECExplicitTri2G); ADD_TEST_SUITE_LEGACY(ECExplicitTri2G); #endif +#endif /* OPENSSL_NO_EC_EXPLICIT_CURVES */ #ifndef OPENSSL_NO_SM2 if (!is_fips_3_0_0) { /* 3.0.0 FIPS provider imports explicit EC params and then fails. */ @@ -1608,14 +2040,23 @@ int setup_tests(void) ADD_TEST_SUITE(SLH_DSA_SHAKE_256f); } #endif /* OPENSSL_NO_SLH_DSA */ + + /* + * Named-group-only partial shapes for DH and EC/SM2. Each + * shape is silently skipped if the algorithm is not loadable. + */ +#ifdef TEST_FROMDATA_NO_KEYGEN + ADD_TEST(test_fromdata_no_keygen); +#endif } - return 1; + return ok; } void cleanup_tests(void) { #ifndef OPENSSL_NO_EC +#ifndef OPENSSL_NO_EC_EXPLICIT_CURVES OSSL_PARAM_free(ec_explicit_prime_params_nc); OSSL_PARAM_free(ec_explicit_prime_params_explicit); OSSL_PARAM_BLD_free(bld_prime_nc); @@ -1626,6 +2067,7 @@ void cleanup_tests(void) OSSL_PARAM_BLD_free(bld_tri_nc); OSSL_PARAM_BLD_free(bld_tri); #endif +#endif /* OPENSSL_NO_EC_EXPLICIT_CURVES */ BN_CTX_free(bnctx); #endif /* OPENSSL_NO_EC */ @@ -1638,12 +2080,14 @@ void cleanup_tests(void) #endif #ifndef OPENSSL_NO_EC FREE_DOMAIN_KEYS(EC); +#ifndef OPENSSL_NO_EC_EXPLICIT_CURVES FREE_DOMAIN_KEYS(ECExplicitPrimeNamedCurve); FREE_DOMAIN_KEYS(ECExplicitPrime2G); #ifndef OPENSSL_NO_EC2M FREE_DOMAIN_KEYS(ECExplicitTriNamedCurve); FREE_DOMAIN_KEYS(ECExplicitTri2G); #endif +#endif /* OPENSSL_NO_EC_EXPLICIT_CURVES */ #ifndef OPENSSL_NO_SM2 FREE_KEYS(SM2); #endif diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c index 80a133dd7f1d7..73d66a2f44df9 100644 --- a/test/evp_extra_test.c +++ b/test/evp_extra_test.c @@ -1125,6 +1125,135 @@ static int test_selection(EVP_PKEY *pkey, int selection) } #endif /* !OPENSSL_NO_DH || !OPENSSL_NO_DSA || !OPENSSL_NO_EC */ +/* + * RSASVE (SP 800-56B 7.2) must reject mathematically degenerate inputs: + * a public exponent e <= 1, and a ciphertext c in {0, 1, n - 1}. Outside + * the FIPS module these were previously accepted; the checks now apply to + * every build, so exercise them in the default provider. + */ + +/* + * With e <= 1 the RSA public operation is the identity (or worse), so + * encapsulation setup must reject the key with PROV_R_INVALID_KEY. idx + * selects the exponent: 0 or 1. + */ +static int test_rsasve_degenerate_exponent(int idx) +{ + EVP_PKEY *rsakey = NULL; + EVP_PKEY *pubkey = NULL; + EVP_PKEY_CTX *genctx = NULL; + EVP_PKEY_CTX *ctx = NULL; + OSSL_PARAM_BLD *bld = NULL; + OSSL_PARAM *params = NULL; + BIGNUM *n = NULL; + BIGNUM *e = NULL; + int testresult = 0; + + /* Borrow a real modulus; only the exponent is degenerate. */ + if (!TEST_ptr(rsakey = load_example_rsa_key()) + || !TEST_true(EVP_PKEY_get_bn_param(rsakey, OSSL_PKEY_PARAM_RSA_N, &n))) + goto err; + + if (!TEST_ptr(e = BN_new()) + || !TEST_true(BN_set_word(e, (BN_ULONG)idx))) /* idx is 0 or 1 */ + goto err; + + if (!TEST_ptr(bld = OSSL_PARAM_BLD_new()) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, n)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, e)) + || !TEST_ptr(params = OSSL_PARAM_BLD_to_param(bld))) + goto err; + + if (!TEST_ptr(genctx = EVP_PKEY_CTX_new_from_name(testctx, "RSA", NULL)) + || !TEST_int_gt(EVP_PKEY_fromdata_init(genctx), 0) + || !TEST_int_gt(EVP_PKEY_fromdata(genctx, &pubkey, EVP_PKEY_PUBLIC_KEY, + params), + 0)) + goto err; + + ERR_clear_error(); + if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(testctx, pubkey, NULL)) + || !TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, NULL), 0) + || !TEST_int_eq(ERR_GET_REASON(ERR_get_error()), PROV_R_INVALID_KEY)) + goto err; + + testresult = 1; +err: + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_CTX_free(genctx); + EVP_PKEY_free(pubkey); + EVP_PKEY_free(rsakey); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(bld); + BN_free(e); + BN_free(n); + return testresult; +} + +/* + * A ciphertext c in {0, 1, n - 1} is a fixed point or trivial case of RSADP, + * so RSASVE recovery must reject it. idx selects the ciphertext: 0, 1, or + * n - 1. The ciphertext length must equal the modulus length. + */ +static int test_rsasve_degenerate_ciphertext(int idx) +{ + EVP_PKEY *rsakey = NULL; + EVP_PKEY_CTX *ctx = NULL; + BIGNUM *n = NULL; + unsigned char *ct = NULL; + unsigned char *secret = NULL; + size_t ctlen = 0; + size_t secretlen = 0; + int expected_reason = 0; + int testresult = 0; + + if (!TEST_ptr(rsakey = load_example_rsa_key()) + || !TEST_true(EVP_PKEY_get_bn_param(rsakey, OSSL_PKEY_PARAM_RSA_N, &n))) + goto err; + + ctlen = secretlen = (size_t)EVP_PKEY_get_size(rsakey); + if (!TEST_ptr(ct = OPENSSL_zalloc(ctlen)) + || !TEST_ptr(secret = OPENSSL_malloc(secretlen))) + goto err; + + switch (idx) { + case 0: /* c = 0 */ + expected_reason = RSA_R_DATA_TOO_SMALL; + break; + case 1: /* c = 1 */ + ct[ctlen - 1] = 1; + expected_reason = RSA_R_DATA_TOO_SMALL; + break; + case 2: /* c = n - 1 */ + if (!TEST_true(BN_sub_word(n, 1)) + || !TEST_int_eq(BN_bn2binpad(n, ct, (int)ctlen), (int)ctlen)) + goto err; + expected_reason = RSA_R_DATA_TOO_LARGE_FOR_MODULUS; + break; + default: + goto err; + } + + if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(testctx, rsakey, NULL)) + || !TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, NULL), 1) + || !TEST_int_eq(EVP_PKEY_CTX_set_kem_op(ctx, "RSASVE"), 1)) + goto err; + + ERR_clear_error(); + if (!TEST_int_eq(EVP_PKEY_decapsulate(ctx, secret, &secretlen, ct, ctlen), 0) + || !TEST_int_eq(ERR_GET_REASON(ERR_get_error()), expected_reason)) + goto err; + + testresult = 1; +err: + OPENSSL_free(secret); + OPENSSL_free(ct); + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(rsakey); + BN_free(n); + return testresult; +} + /* * Test combinations of private, public, missing and private + public key * params to ensure they are all accepted @@ -2229,20 +2358,83 @@ static int test_EVP_md_null(void) } #ifndef OPENSSL_NO_POLY1305 -/* Test that EVP_MAC_final fails for Poly1305 when no key was set */ +/* Test Poly1305 no-key failures and staged key initialization */ static int test_evp_mac_poly1305_no_key(void) { int ret = 0; EVP_MAC *mac = NULL; EVP_MAC_CTX *ctx = NULL; + /* RFC 7539 Poly1305 test vector. */ + static const unsigned char staged_data[] = "Cryptographic Forum Research Group"; + static const unsigned char expected[16] = { + 0xa8, 0x06, 0x1d, 0xc1, 0x30, 0x51, 0x36, 0xc6, + 0xc2, 0x2b, 0x8b, 0xaf, 0x0c, 0x01, 0x27, 0xa9 + }; + unsigned char no_key_data[16] = { 0 }; + unsigned char key[32] = { + 0x85, 0xd6, 0xbe, 0x78, 0x57, 0x55, 0x6d, 0x33, + 0x7f, 0x44, 0x52, 0xfe, 0x42, 0xd5, 0x06, 0xa8, + 0x01, 0x03, 0x80, 0x8a, 0xfb, 0x0d, 0xb2, 0xfd, + 0x4a, 0xbf, 0xf6, 0xaf, 0x41, 0x49, 0xf5, 0x1b + }; unsigned char out[16]; + OSSL_PARAM key_params[2]; + OSSL_PARAM null_key_params[2]; size_t outl = 0; + key_params[0] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, + key, sizeof(key)); + key_params[1] = OSSL_PARAM_construct_end(); + null_key_params[0] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, + NULL, sizeof(key)); + null_key_params[1] = OSSL_PARAM_construct_end(); + if (!TEST_ptr(mac = EVP_MAC_fetch(testctx, "Poly1305", testpropq)) || !TEST_ptr(ctx = EVP_MAC_CTX_new(mac)) - || !TEST_int_eq(EVP_MAC_init(ctx, NULL, 0, NULL), 1) - || !TEST_int_eq(EVP_MAC_final(ctx, out, &outl, sizeof(out)), 0)) + || !TEST_int_eq(EVP_MAC_init(ctx, NULL, 0, NULL), 1)) + goto err; + + ERR_clear_error(); + if (!TEST_int_eq(EVP_MAC_update(ctx, no_key_data, sizeof(no_key_data)), 0) + || !TEST_int_eq(ERR_GET_REASON(ERR_get_error()), PROV_R_NO_KEY_SET)) + goto err; + + /* The failed update must not block staged key initialization. */ + if (!TEST_int_eq(EVP_MAC_CTX_set_params(ctx, key_params), 1) + || !TEST_int_eq(EVP_MAC_update(ctx, staged_data, + sizeof(staged_data) - 1), + 1) + || !TEST_int_eq(EVP_MAC_final(ctx, out, &outl, sizeof(out)), 1) + || !TEST_size_t_eq(outl, sizeof(expected)) + || !TEST_mem_eq(out, outl, expected, sizeof(expected))) + goto err; + + EVP_MAC_CTX_free(ctx); + ctx = NULL; + + if (!TEST_ptr(ctx = EVP_MAC_CTX_new(mac)) + || !TEST_int_eq(EVP_MAC_init(ctx, NULL, 0, NULL), 1)) + goto err; + + ERR_clear_error(); + if (!TEST_int_eq(EVP_MAC_final(ctx, out, &outl, sizeof(out)), 0) + || !TEST_int_eq(ERR_GET_REASON(ERR_get_error()), PROV_R_NO_KEY_SET)) + goto err; + + ERR_clear_error(); + if (!TEST_int_eq(EVP_MAC_init(ctx, NULL, 0, null_key_params), 0) + || !TEST_int_eq(ERR_GET_REASON(ERR_get_error()), + PROV_R_INVALID_KEY_LENGTH)) + goto err; + + ERR_clear_error(); + if (!TEST_int_eq(EVP_MAC_CTX_set_params(ctx, null_key_params), 0) + || !TEST_int_eq(ERR_GET_REASON(ERR_get_error()), + PROV_R_INVALID_KEY_LENGTH)) goto err; + + EVP_MAC_CTX_free(ctx); + ctx = NULL; ret = 1; err: EVP_MAC_CTX_free(ctx); @@ -4081,6 +4273,76 @@ static int test_RSA_verify_recover_rejects_short_buffer(void) return ret; } +/* + * A raw RSA PKCS#1 v1.5 signature whose recovered data is empty must be + * recovered successfully with a length of zero, not rejected as an error. + */ +static int test_RSA_verify_recover_empty_payload(void) +{ + int ret = 0; + int recovered_cap = 0; + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *sign_ctx = NULL, *verify_ctx = NULL; + unsigned char *sig = NULL, *recovered = NULL; + size_t sig_len = 0, recovered_len = 0; + /* + * The signed input has zero length, but a valid non-null address is still + * passed so the result does not depend on how lower layers treat NULL for + * zero-length data. + */ + const unsigned char empty[] = { 0 }; + + if (OSSL_PROVIDER_available(testctx, "fips")) + return TEST_skip("Test skipped for FIPS provider"); + + if (!TEST_ptr(pkey = load_example_rsa_key()) + || !TEST_ptr(sign_ctx = EVP_PKEY_CTX_new_from_pkey(testctx, pkey, NULL)) + || !TEST_int_gt(EVP_PKEY_sign_init(sign_ctx), 0) + || !TEST_int_gt(EVP_PKEY_CTX_set_rsa_padding(sign_ctx, RSA_PKCS1_PADDING), 0) + /* + * Deliberately do not configure a signature digest so that the raw + * PKCS#1 v1.5 sign and verify-recover paths are exercised. + */ + || !TEST_int_gt(EVP_PKEY_sign(sign_ctx, NULL, &sig_len, empty, 0), 0) + || !TEST_ptr(sig = OPENSSL_malloc(sig_len)) + || !TEST_int_gt(EVP_PKEY_sign(sign_ctx, sig, &sig_len, empty, 0), 0) + || !TEST_int_gt(recovered_cap = EVP_PKEY_get_size(pkey), 0) + || !TEST_ptr(recovered = OPENSSL_malloc(recovered_cap)) + || !TEST_ptr(verify_ctx = EVP_PKEY_CTX_new_from_pkey(testctx, pkey, NULL)) + || !TEST_int_gt(EVP_PKEY_verify_recover_init(verify_ctx), 0) + || !TEST_int_gt(EVP_PKEY_CTX_set_rsa_padding(verify_ctx, RSA_PKCS1_PADDING), + 0)) + goto done; + + /* Size-query call must succeed. */ + recovered_len = (size_t)recovered_cap; + if (!TEST_int_gt(EVP_PKEY_verify_recover(verify_ctx, NULL, + &recovered_len, sig, sig_len), + 0)) + goto done; + + /* + * The actual recovery call is essential: a NULL output buffer would only + * run the size-query path, which never decodes the signature and so would + * not reproduce the regression. + */ + recovered_len = (size_t)recovered_cap; + if (!TEST_int_gt(EVP_PKEY_verify_recover(verify_ctx, recovered, + &recovered_len, sig, sig_len), + 0) + || !TEST_size_t_eq(recovered_len, 0)) + goto done; + + ret = 1; +done: + EVP_PKEY_CTX_free(sign_ctx); + EVP_PKEY_CTX_free(verify_ctx); + EVP_PKEY_free(pkey); + OPENSSL_free(sig); + OPENSSL_free(recovered); + return ret; +} + static int test_RSA_encrypt(void) { int ret = 0; @@ -4333,6 +4595,257 @@ static int test_EVP_PKEY_set1_DH(void) return ret; } #endif /* !OPENSSL_NO_DEPRECATED_3_0 */ + +/* Test that DHX (X9.42) rejects a malicious peer key during the + * derivation phase (specifically EVP_PKEY_derive_set_peer) when the + * remote 'q' does not match the local domain parameters but is still + * consistent with the remote key share. + * (CVE-2026-42770) + */ +static int test_dhx_derive_rejects_bad_peer_q(void) +{ + int ret = 0; + EVP_PKEY *local_key = NULL, *remote_key = NULL; + EVP_PKEY_CTX *pctx = NULL, *derive_ctx = NULL; + OSSL_PARAM_BLD *bld = NULL; + OSSL_PARAM *params = NULL; + + BIGNUM *p = NULL, *g = NULL; + BIGNUM *q_valid = NULL, *pub_local = NULL, *priv_local = NULL; + BIGNUM *q_bad = NULL, *pub_bad = NULL; + + static const unsigned char bin_p[] = { + 0x87, 0xa8, 0xe6, 0x1d, 0xb4, 0xb6, 0x66, 0x3c, + 0xff, 0xbb, 0xd1, 0x9c, 0x65, 0x19, 0x59, 0x99, + 0x8c, 0xee, 0xf6, 0x08, 0x66, 0x0d, 0xd0, 0xf2, + 0x5d, 0x2c, 0xee, 0xd4, 0x43, 0x5e, 0x3b, 0x00, + 0xe0, 0x0d, 0xf8, 0xf1, 0xd6, 0x19, 0x57, 0xd4, + 0xfa, 0xf7, 0xdf, 0x45, 0x61, 0xb2, 0xaa, 0x30, + 0x16, 0xc3, 0xd9, 0x11, 0x34, 0x09, 0x6f, 0xaa, + 0x3b, 0xf4, 0x29, 0x6d, 0x83, 0x0e, 0x9a, 0x7c, + 0x20, 0x9e, 0x0c, 0x64, 0x97, 0x51, 0x7a, 0xbd, + 0x5a, 0x8a, 0x9d, 0x30, 0x6b, 0xcf, 0x67, 0xed, + 0x91, 0xf9, 0xe6, 0x72, 0x5b, 0x47, 0x58, 0xc0, + 0x22, 0xe0, 0xb1, 0xef, 0x42, 0x75, 0xbf, 0x7b, + 0x6c, 0x5b, 0xfc, 0x11, 0xd4, 0x5f, 0x90, 0x88, + 0xb9, 0x41, 0xf5, 0x4e, 0xb1, 0xe5, 0x9b, 0xb8, + 0xbc, 0x39, 0xa0, 0xbf, 0x12, 0x30, 0x7f, 0x5c, + 0x4f, 0xdb, 0x70, 0xc5, 0x81, 0xb2, 0x3f, 0x76, + 0xb6, 0x3a, 0xca, 0xe1, 0xca, 0xa6, 0xb7, 0x90, + 0x2d, 0x52, 0x52, 0x67, 0x35, 0x48, 0x8a, 0x0e, + 0xf1, 0x3c, 0x6d, 0x9a, 0x51, 0xbf, 0xa4, 0xab, + 0x3a, 0xd8, 0x34, 0x77, 0x96, 0x52, 0x4d, 0x8e, + 0xf6, 0xa1, 0x67, 0xb5, 0xa4, 0x18, 0x25, 0xd9, + 0x67, 0xe1, 0x44, 0xe5, 0x14, 0x05, 0x64, 0x25, + 0x1c, 0xca, 0xcb, 0x83, 0xe6, 0xb4, 0x86, 0xf6, + 0xb3, 0xca, 0x3f, 0x79, 0x71, 0x50, 0x60, 0x26, + 0xc0, 0xb8, 0x57, 0xf6, 0x89, 0x96, 0x28, 0x56, + 0xde, 0xd4, 0x01, 0x0a, 0xbd, 0x0b, 0xe6, 0x21, + 0xc3, 0xa3, 0x96, 0x0a, 0x54, 0xe7, 0x10, 0xc3, + 0x75, 0xf2, 0x63, 0x75, 0xd7, 0x01, 0x41, 0x03, + 0xa4, 0xb5, 0x43, 0x30, 0xc1, 0x98, 0xaf, 0x12, + 0x61, 0x16, 0xd2, 0x27, 0x6e, 0x11, 0x71, 0x5f, + 0x69, 0x38, 0x77, 0xfa, 0xd7, 0xef, 0x09, 0xca, + 0xdb, 0x09, 0x4a, 0xe9, 0x1e, 0x1a, 0x15, 0x97 + }; + static const unsigned char bin_g[] = { + 0x3F, 0xB3, 0x2C, 0x9B, 0x73, 0x13, 0x4D, 0x0B, + 0x2E, 0x77, 0x50, 0x66, 0x60, 0xED, 0xBD, 0x48, + 0x4C, 0xA7, 0xB1, 0x8F, 0x21, 0xEF, 0x20, 0x54, + 0x07, 0xF4, 0x79, 0x3A, 0x1A, 0x0B, 0xA1, 0x25, + 0x10, 0xDB, 0xC1, 0x50, 0x77, 0xBE, 0x46, 0x3F, + 0xFF, 0x4F, 0xED, 0x4A, 0xAC, 0x0B, 0xB5, 0x55, + 0xBE, 0x3A, 0x6C, 0x1B, 0x0C, 0x6B, 0x47, 0xB1, + 0xBC, 0x37, 0x73, 0xBF, 0x7E, 0x8C, 0x6F, 0x62, + 0x90, 0x12, 0x28, 0xF8, 0xC2, 0x8C, 0xBB, 0x18, + 0xA5, 0x5A, 0xE3, 0x13, 0x41, 0x00, 0x0A, 0x65, + 0x01, 0x96, 0xF9, 0x31, 0xC7, 0x7A, 0x57, 0xF2, + 0xDD, 0xF4, 0x63, 0xE5, 0xE9, 0xEC, 0x14, 0x4B, + 0x77, 0x7D, 0xE6, 0x2A, 0xAA, 0xB8, 0xA8, 0x62, + 0x8A, 0xC3, 0x76, 0xD2, 0x82, 0xD6, 0xED, 0x38, + 0x64, 0xE6, 0x79, 0x82, 0x42, 0x8E, 0xBC, 0x83, + 0x1D, 0x14, 0x34, 0x8F, 0x6F, 0x2F, 0x91, 0x93, + 0xB5, 0x04, 0x5A, 0xF2, 0x76, 0x71, 0x64, 0xE1, + 0xDF, 0xC9, 0x67, 0xC1, 0xFB, 0x3F, 0x2E, 0x55, + 0xA4, 0xBD, 0x1B, 0xFF, 0xE8, 0x3B, 0x9C, 0x80, + 0xD0, 0x52, 0xB9, 0x85, 0xD1, 0x82, 0xEA, 0x0A, + 0xDB, 0x2A, 0x3B, 0x73, 0x13, 0xD3, 0xFE, 0x14, + 0xC8, 0x48, 0x4B, 0x1E, 0x05, 0x25, 0x88, 0xB9, + 0xB7, 0xD2, 0xBB, 0xD2, 0xDF, 0x01, 0x61, 0x99, + 0xEC, 0xD0, 0x6E, 0x15, 0x57, 0xCD, 0x09, 0x15, + 0xB3, 0x35, 0x3B, 0xBB, 0x64, 0xE0, 0xEC, 0x37, + 0x7F, 0xD0, 0x28, 0x37, 0x0D, 0xF9, 0x2B, 0x52, + 0xC7, 0x89, 0x14, 0x28, 0xCD, 0xC6, 0x7E, 0xB6, + 0x18, 0x4B, 0x52, 0x3D, 0x1D, 0xB2, 0x46, 0xC3, + 0x2F, 0x63, 0x07, 0x84, 0x90, 0xF0, 0x0E, 0xF8, + 0xD6, 0x47, 0xD1, 0x48, 0xD4, 0x79, 0x54, 0x51, + 0x5E, 0x23, 0x27, 0xCF, 0xEF, 0x98, 0xC5, 0x82, + 0x66, 0x4B, 0x4C, 0x0F, 0x6C, 0xC4, 0x16, 0x59 + }; + + static const unsigned char bin_q_valid[] = { + 0x8C, 0xF8, 0x36, 0x42, 0xA7, 0x09, 0xA0, 0x97, + 0xB4, 0x47, 0x99, 0x76, 0x40, 0x12, 0x9D, 0xA2, + 0x99, 0xB1, 0xA4, 0x7D, 0x1E, 0xB3, 0x75, 0x0B, + 0xA3, 0x08, 0xB0, 0xFE, 0x64, 0xF5, 0xFB, 0xD3 + }; + static const unsigned char bin_local_pub[] = { + 0x79, 0x6e, 0x15, 0x43, 0x14, 0x70, 0xac, 0x86, + 0xfa, 0x8a, 0x78, 0xb8, 0xbc, 0xdd, 0x1f, 0x35, + 0x89, 0xdb, 0xf1, 0x5f, 0xfe, 0x0e, 0x0a, 0x7a, + 0x41, 0xdd, 0x86, 0x40, 0x88, 0x7f, 0x3c, 0xc3, + 0xf0, 0x43, 0x9e, 0x28, 0x1f, 0x4c, 0xf3, 0x80, + 0x0b, 0xac, 0x2d, 0xbd, 0xfc, 0xda, 0x58, 0x9b, + 0x26, 0xcc, 0x82, 0x85, 0x12, 0x08, 0x5c, 0xe0, + 0xd3, 0xe5, 0x7a, 0xa1, 0x3c, 0xd9, 0xe7, 0xa4, + 0x66, 0xd8, 0x81, 0xba, 0xce, 0x91, 0xed, 0x10, + 0xc6, 0x06, 0x4a, 0xb3, 0x6e, 0x0d, 0x66, 0x36, + 0x7c, 0x4b, 0xfe, 0xd5, 0x6a, 0x9f, 0x90, 0x7e, + 0x4d, 0xae, 0xc1, 0x67, 0x32, 0xfb, 0x5c, 0x54, + 0x89, 0x1c, 0xb0, 0xd2, 0x62, 0x51, 0xfd, 0x61, + 0xc3, 0x20, 0x40, 0x77, 0x42, 0x46, 0xb3, 0xf8, + 0xbd, 0xcd, 0x5e, 0xf6, 0x0e, 0x68, 0x47, 0xcd, + 0xd6, 0x9b, 0xd6, 0xd3, 0x18, 0xd1, 0xcd, 0xa0, + 0xe8, 0xa3, 0x0a, 0x71, 0x6d, 0xe4, 0xdc, 0x1a, + 0x4e, 0xb9, 0x9b, 0x06, 0x86, 0xb7, 0x71, 0x20, + 0xc4, 0xb6, 0x9b, 0x00, 0x05, 0xf6, 0xa8, 0xc3, + 0xae, 0x76, 0x8d, 0x23, 0xc0, 0x8c, 0x85, 0xbd, + 0x1d, 0x58, 0xf4, 0x0d, 0xc0, 0x13, 0x8d, 0x62, + 0x77, 0x43, 0x61, 0x37, 0xae, 0x69, 0x77, 0x9f, + 0xdc, 0x21, 0x8c, 0x07, 0x1c, 0x14, 0x82, 0x6f, + 0x47, 0x15, 0x62, 0x03, 0x3e, 0x85, 0xff, 0xc9, + 0x9a, 0x21, 0x47, 0xd5, 0x39, 0xe2, 0x74, 0x13, + 0x6a, 0x4a, 0x1e, 0x7f, 0x1d, 0xb9, 0x75, 0x83, + 0xb5, 0x1d, 0xc0, 0x38, 0x5a, 0x52, 0xd7, 0x38, + 0x39, 0x63, 0x75, 0x8d, 0x89, 0x33, 0x98, 0xa8, + 0xd0, 0x13, 0xfd, 0xba, 0xd2, 0x0d, 0xdf, 0x30, + 0xfb, 0xe0, 0x5f, 0xbb, 0x22, 0x49, 0x91, 0x3a, + 0xe6, 0x75, 0x1b, 0x6b, 0x24, 0x6a, 0xe5, 0x62, + 0x2b, 0xa2, 0x6c, 0x48, 0x27, 0x41, 0x7c, 0x2d + }; + static const unsigned char bin_local_priv[] = { + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, + 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, + 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, + 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22 + }; + + /* Remote malicious parameters */ + static const unsigned char bin_remote_q[] = { 0x09, 0xf5 }; + static const unsigned char bin_remote_pub[] = { + 0x54, 0xc0, 0x57, 0x90, 0x3d, 0x36, 0x22, 0x35, + 0xa6, 0x5c, 0x03, 0xf0, 0x01, 0xd8, 0xa3, 0xea, + 0x25, 0x28, 0x36, 0xb3, 0x58, 0x02, 0x50, 0xab, + 0xdc, 0x0a, 0x10, 0x83, 0x45, 0x1a, 0xf0, 0x12, + 0x6f, 0xd1, 0x50, 0xf9, 0xe8, 0xd2, 0x12, 0xb3, + 0x84, 0xae, 0x0c, 0x23, 0xaa, 0x7c, 0x67, 0xfe, + 0x85, 0x13, 0x68, 0x11, 0x4c, 0xcc, 0x06, 0x1a, + 0x66, 0x1e, 0x98, 0x6b, 0xd7, 0xe6, 0x3d, 0x25, + 0x75, 0x13, 0x33, 0x9a, 0x69, 0x14, 0xcb, 0xfa, + 0xb2, 0x09, 0xad, 0x79, 0x3e, 0xf2, 0x57, 0x04, + 0xcd, 0x53, 0x2d, 0xdf, 0xb7, 0xe6, 0x93, 0xde, + 0x70, 0x1d, 0x17, 0xe6, 0x29, 0xef, 0x3c, 0x18, + 0x4d, 0x40, 0xd5, 0xfe, 0xa1, 0xf9, 0xed, 0xb8, + 0x9c, 0x5b, 0xf8, 0xd7, 0xaa, 0x19, 0xe3, 0x37, + 0x4f, 0x80, 0x59, 0x32, 0x15, 0x9c, 0xa7, 0xb5, + 0xd5, 0x73, 0xb9, 0xe2, 0xf3, 0xc9, 0x4f, 0xe7, + 0x47, 0xc4, 0xa3, 0xb0, 0x9e, 0x31, 0xaf, 0xa3, + 0x78, 0x8d, 0x35, 0x83, 0x3a, 0xaf, 0x2a, 0xc8, + 0xae, 0x8b, 0xc4, 0x85, 0x00, 0x13, 0x14, 0x64, + 0xe7, 0x93, 0xa2, 0xe0, 0x35, 0x2e, 0x7c, 0x3e, + 0xd9, 0xda, 0x9f, 0xcf, 0x89, 0xb1, 0x21, 0xbc, + 0x1c, 0xee, 0x83, 0xc5, 0x44, 0x21, 0x4c, 0xeb, + 0x33, 0x38, 0xb1, 0x4a, 0xc6, 0x89, 0x19, 0x68, + 0x35, 0x17, 0x46, 0xea, 0xf6, 0x2b, 0xb5, 0x17, + 0xeb, 0x98, 0xfc, 0x63, 0x3d, 0x8d, 0x23, 0x5b, + 0xac, 0x37, 0xbc, 0x08, 0xe4, 0x7f, 0x18, 0x51, + 0xd0, 0x55, 0x01, 0x94, 0x9a, 0x67, 0x33, 0x96, + 0x5a, 0xdb, 0xfe, 0x8e, 0x43, 0xf7, 0xc3, 0xb9, + 0x3c, 0xa7, 0x51, 0x5c, 0xd6, 0xab, 0x36, 0xd7, + 0xef, 0x26, 0xbb, 0x0f, 0xd6, 0x03, 0x3a, 0xbc, + 0x39, 0x61, 0x3e, 0x88, 0x0f, 0xff, 0xc8, 0x72, + 0x9b, 0x03, 0xbf, 0xea, 0xdd, 0xf0, 0x88, 0x33 + }; + + if (!TEST_ptr(p = BN_bin2bn(bin_p, sizeof(bin_p), NULL)) + || !TEST_ptr(g = BN_bin2bn(bin_g, sizeof(bin_g), NULL))) + goto err; + + if (!TEST_ptr(q_valid = BN_bin2bn(bin_q_valid, sizeof(bin_q_valid), NULL)) + || !TEST_ptr(pub_local + = BN_bin2bn(bin_local_pub, sizeof(bin_local_pub), NULL)) + || !TEST_true(priv_local + = BN_bin2bn(bin_local_priv, sizeof(bin_local_priv), NULL))) + goto err; + + if (!TEST_ptr(bld = OSSL_PARAM_BLD_new()) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, p)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_Q, q_valid)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, g)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PUB_KEY, pub_local)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, priv_local)) + || !TEST_ptr(params = OSSL_PARAM_BLD_to_param(bld))) + goto err; + + if (!TEST_ptr(pctx = EVP_PKEY_CTX_new_from_name(testctx, "DHX", testpropq)) + || !TEST_int_gt(EVP_PKEY_fromdata_init(pctx), 0) + || !TEST_int_gt(EVP_PKEY_fromdata(pctx, &local_key, EVP_PKEY_KEYPAIR, params), 0)) + goto err; + + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(bld); + EVP_PKEY_CTX_free(pctx); + params = NULL; + bld = NULL; + pctx = NULL; + + if (!TEST_ptr(q_bad = BN_bin2bn(bin_remote_q, sizeof(bin_remote_q), NULL)) + || !TEST_ptr(pub_bad + = BN_bin2bn(bin_remote_pub, sizeof(bin_remote_pub), NULL))) + goto err; + + if (!TEST_ptr(bld = OSSL_PARAM_BLD_new()) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, p)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_Q, q_bad)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, g)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PUB_KEY, pub_bad)) + || !TEST_ptr(params = OSSL_PARAM_BLD_to_param(bld))) + goto err; + + if (!TEST_ptr(pctx = EVP_PKEY_CTX_new_from_name(testctx, "DHX", testpropq)) + || !TEST_int_gt(EVP_PKEY_fromdata_init(pctx), 0) + || !TEST_int_gt(EVP_PKEY_fromdata(pctx, &remote_key, EVP_PKEY_PUBLIC_KEY, params), 0)) + goto err; + + if (!TEST_ptr(derive_ctx = EVP_PKEY_CTX_new(local_key, NULL)) + || !TEST_int_gt(EVP_PKEY_derive_init(derive_ctx), 0)) + goto err; + + /* reject the remote key share, even if it is self-consistent, correct + * code needs to use local q, not remote-provided q. */ + if (!TEST_int_le(EVP_PKEY_derive_set_peer(derive_ctx, remote_key), 0)) { + TEST_error("EVP_PKEY_derive_set_peer incorrectly accepted a peer with malicious 'q'"); + goto err; + } + + ret = 1; + +err: + BN_free(p); + BN_free(g); + BN_free(q_valid); + BN_free(pub_local); + BN_free(priv_local); + BN_free(q_bad); + BN_free(pub_bad); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(bld); + EVP_PKEY_CTX_free(pctx); + EVP_PKEY_CTX_free(derive_ctx); + EVP_PKEY_free(local_key); + EVP_PKEY_free(remote_key); + return ret; +} #endif /* !OPENSSL_NO_DH */ /* @@ -6711,6 +7224,30 @@ static int test_aes_gcm_siv_empty_data(void) return ret; } +#if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305) +static int test_chacha20_poly1305_late_aad(void) +{ + EVP_CIPHER_CTX *ctx = NULL; + EVP_CIPHER *c = NULL; + unsigned char key[32] = { 0 }; + unsigned char iv[12] = { 0 }; + unsigned char aad[4] = "aad"; + unsigned char msg[8] = "message"; + unsigned char out[32]; + int len, test; + + test = TEST_ptr(ctx = EVP_CIPHER_CTX_new()) + && TEST_ptr(c = EVP_CIPHER_fetch(testctx, "ChaCha20-Poly1305", testpropq)) + && TEST_true(EVP_EncryptInit_ex2(ctx, c, key, iv, NULL)) + && TEST_true(EVP_EncryptUpdate(ctx, NULL, &len, aad, sizeof(aad))) + && TEST_true(EVP_EncryptUpdate(ctx, out, &len, msg, sizeof(msg))) + && TEST_false(EVP_EncryptUpdate(ctx, NULL, &len, aad, sizeof(aad))); + + EVP_CIPHER_free(c); + EVP_CIPHER_CTX_free(ctx); + return test; +} +#endif /* * AES-SIV reuse-without-rekey: * msg1: legit non-empty CT, tag verifies, final_ret=0 @@ -6870,6 +7407,12 @@ static const AEAD_ONESHOT_CFG aead_oneshot_cfgs[] = { { "ChaCha20-Poly1305", 32, 12, 16, 0 } }; +static const AEAD_ONESHOT_CFG aead_oneshot_zerolen_cfgs[] = { + { "AES-128-OCB", 16, 12, 16, 0 }, + { "ChaCha20-Poly1305", 32, 12, 16, 0 }, + { "AES-128-GCM-SIV", 16, 12, 16, 0 } +}; + /* * Drive an encrypt or decrypt operation. AAD always via EVP_CipherUpdate. * Body via EVP_Cipher() when oneshot_body is non-zero, EVP_CipherUpdate @@ -7090,6 +7633,302 @@ static int test_aead_oneshot_roundtrip(int idx) return ok; } +static EVP_CIPHER_CTX *aead_oneshot_zerolen_ctx(const EVP_CIPHER *cipher, + int enc, const unsigned char *key, const unsigned char *iv, + const unsigned char *aad, size_t aad_len, + const unsigned char *tag, size_t tag_len) +{ + EVP_CIPHER_CTX *ctx = NULL; + int outl = 0; + + if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new()) + || !TEST_true(EVP_CipherInit_ex2(ctx, cipher, key, iv, enc, NULL)) + || (aad_len > 0 + && !TEST_true(EVP_CipherUpdate(ctx, NULL, &outl, aad, + (int)aad_len))) + || (!enc + && !TEST_int_gt(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, + (int)tag_len, (void *)tag), + 0))) { + EVP_CIPHER_CTX_free(ctx); + return NULL; + } + return ctx; +} + +/* + * For these built-in provider implementations, a NULL-input EVP_Cipher() call + * must produce or check the empty-message tag even when no payload Update was + * made. + */ +static int test_aead_oneshot_zerolen(int idx) +{ + static const unsigned char key[32] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f + }; + static const unsigned char iv[12] = { + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab + }; + static const unsigned char aad[] = "empty message context"; + const AEAD_ONESHOT_CFG *cfg = &aead_oneshot_zerolen_cfgs[idx / 2]; + int with_aad = idx % 2; + size_t aad_len = with_aad ? sizeof(aad) - 1 : 0; + EVP_CIPHER *cipher = NULL; + EVP_CIPHER_CTX *ctx_oracle = NULL, *ctx_oneshot = NULL; + EVP_CIPHER_CTX *ctx_dec = NULL, *ctx_dec_bad = NULL; + static const unsigned char empty = 0; + unsigned char out[16] = { 0 }; + unsigned char tag_oracle[16] = { 0 }; + unsigned char tag_oneshot[16] = { 0 }; + unsigned char tag_bad[16] = { 0 }; + int outl = 0, ret = 0; + + ERR_set_mark(); + cipher = EVP_CIPHER_fetch(testctx, cfg->name, testpropq); + ERR_pop_to_mark(); + if (cipher == NULL) + return TEST_skip("'%s' is not available", cfg->name); + + /* + * The explicit zero-length Update provides an oracle that also works on + * the unpatched GCM-SIV implementation, whose empty Final cannot generate + * a tag. + */ + ctx_oracle = aead_oneshot_zerolen_ctx(cipher, 1, key, iv, aad, aad_len, + NULL, cfg->taglen); + if (!TEST_ptr(ctx_oracle) + || !TEST_true(EVP_EncryptUpdate(ctx_oracle, out, &outl, &empty, 0)) + || !TEST_true(EVP_EncryptFinal_ex(ctx_oracle, out, &outl)) + || !TEST_int_gt(EVP_CIPHER_CTX_ctrl(ctx_oracle, EVP_CTRL_AEAD_GET_TAG, + (int)cfg->taglen, tag_oracle), + 0)) + goto end; + + ctx_dec = aead_oneshot_zerolen_ctx(cipher, 0, key, iv, aad, aad_len, + tag_oracle, cfg->taglen); + if (!TEST_ptr(ctx_dec) + || !TEST_int_ge(EVP_Cipher(ctx_dec, out, NULL, 0), 0)) + goto end; + + memcpy(tag_bad, tag_oracle, cfg->taglen); + tag_bad[0] ^= 1; + ctx_dec_bad = aead_oneshot_zerolen_ctx(cipher, 0, key, iv, aad, aad_len, + tag_bad, cfg->taglen); + if (!TEST_ptr(ctx_dec_bad) + || !TEST_int_lt(EVP_Cipher(ctx_dec_bad, out, NULL, 0), 0)) + goto end; + + ctx_oneshot = aead_oneshot_zerolen_ctx(cipher, 1, key, iv, aad, aad_len, + NULL, cfg->taglen); + if (!TEST_ptr(ctx_oneshot) + || !TEST_int_ge(EVP_Cipher(ctx_oneshot, out, NULL, 0), 0) + || !TEST_int_gt(EVP_CIPHER_CTX_ctrl(ctx_oneshot, EVP_CTRL_AEAD_GET_TAG, + (int)cfg->taglen, tag_oneshot), + 0) + || !TEST_mem_eq(tag_oneshot, cfg->taglen, + tag_oracle, cfg->taglen)) + goto end; + + ret = 1; +end: + if (!ret) + TEST_info("zero-length %s test failed (%s)", cfg->name, + with_aad ? "with AAD" : "no AAD"); + EVP_CIPHER_CTX_free(ctx_oracle); + EVP_CIPHER_CTX_free(ctx_oneshot); + EVP_CIPHER_CTX_free(ctx_dec); + EVP_CIPHER_CTX_free(ctx_dec_bad); + EVP_CIPHER_free(cipher); + return ret; +} + +static const AEAD_ONESHOT_CFG ccm_empty_final_cfgs[] = { + { "AES-128-CCM", 16, 12, 16, 1 }, + { "AES-192-CCM", 24, 12, 16, 1 }, + { "AES-256-CCM", 32, 12, 16, 1 }, + { "ARIA-128-CCM", 16, 12, 16, 1 }, + { "ARIA-192-CCM", 24, 12, 16, 1 }, + { "ARIA-256-CCM", 32, 12, 16, 1 }, + { "SM4-CCM", 16, 12, 16, 1 } +}; + +/* + * Finalize CCM after declaring an empty payload and supplying AAD, without a + * payload Update. Return one for authentication success, zero for an + * authentication failure, and minus one for any other failure. + */ +static int ccm_empty_final_op(const AEAD_ONESHOT_CFG *cfg, int enc, + int oneshot_final, const unsigned char *key, const unsigned char *iv, + const unsigned char *aad, size_t aad_len, unsigned char *tag, + const char **why) +{ + EVP_CIPHER_CTX *ctx = NULL; + EVP_CIPHER *cipher = NULL; + unsigned char out[1] = { 0 }; + int outl = 0, rv; + int ret = -1; + + *why = NULL; + + if (!TEST_ptr(cipher = EVP_CIPHER_fetch(testctx, cfg->name, testpropq))) { + *why = "CIPHER_FETCH"; + goto end; + } + if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new())) { + *why = "CTX_NEW"; + goto end; + } + if (!TEST_true(EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, enc))) { + *why = "INIT_CIPHER"; + goto end; + } + if (!TEST_int_gt(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, + (int)cfg->ivlen, NULL), + 0)) { + *why = "SET_IVLEN"; + goto end; + } + if (!TEST_int_gt(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, + (int)cfg->taglen, enc ? NULL : tag), + 0)) { + *why = "SET_TAG"; + goto end; + } + if (!TEST_true(EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, enc))) { + *why = "INIT_KEY_IV"; + goto end; + } + if (!TEST_true(EVP_CipherUpdate(ctx, NULL, &outl, NULL, 0))) { + *why = "LENGTH"; + goto end; + } + if (!TEST_true(EVP_CipherUpdate(ctx, NULL, &outl, aad, (int)aad_len))) { + *why = "AAD"; + goto end; + } + + if (oneshot_final) { + rv = EVP_Cipher(ctx, out, NULL, 0); + ret = rv >= 0; + if (ret && rv != 0) { + *why = "ONESHOT_FINAL_LENGTH"; + ret = -1; + goto end; + } + } else { + ret = EVP_CipherFinal_ex(ctx, out, &outl) > 0; + if (ret && outl != 0) { + *why = "STREAM_FINAL_LENGTH"; + ret = -1; + goto end; + } + } + + if (ret && enc + && !TEST_int_gt(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, + (int)cfg->taglen, tag), + 0)) { + *why = "GET_TAG"; + ret = -1; + } + +end: + EVP_CIPHER_CTX_free(ctx); + EVP_CIPHER_free(cipher); + return ret; +} + +static int test_ccm_empty_final(int idx) +{ + static const unsigned char fixed_key[32] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f + }; + static const unsigned char fixed_iv[12] = { + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab + }; + static const unsigned char fixed_aad[] = "CCM empty-payload Final regression"; + const AEAD_ONESHOT_CFG *cfg = &ccm_empty_final_cfgs[idx]; + EVP_CIPHER *probe = NULL; + unsigned char tag_stream[16], tag_oneshot[16], bad_tag[16]; + const char *why = NULL; + int rv, ok = 0; + + ERR_set_mark(); + probe = EVP_CIPHER_fetch(testctx, cfg->name, testpropq); + ERR_pop_to_mark(); + if (probe == NULL) { + TEST_info("skipping, '%s' is not available", cfg->name); + return 1; + } + EVP_CIPHER_free(probe); + + memset(tag_stream, 0, sizeof(tag_stream)); + rv = ccm_empty_final_op(cfg, 1, 0, fixed_key, fixed_iv, fixed_aad, + sizeof(fixed_aad) - 1, tag_stream, &why); + if (!TEST_int_eq(rv, 1)) { + TEST_error("%s: streaming encryption failed at %s", + cfg->name, why ? why : "FINAL"); + goto end; + } + + memset(tag_oneshot, 0, sizeof(tag_oneshot)); + rv = ccm_empty_final_op(cfg, 1, 1, fixed_key, fixed_iv, fixed_aad, + sizeof(fixed_aad) - 1, tag_oneshot, &why); + if (!TEST_int_eq(rv, 1)) { + TEST_error("%s: one-shot encryption failed at %s", + cfg->name, why ? why : "FINAL"); + goto end; + } + if (!TEST_mem_eq(tag_stream, cfg->taglen, tag_oneshot, cfg->taglen)) { + TEST_error("%s: streaming and one-shot tags differ", cfg->name); + goto end; + } + + rv = ccm_empty_final_op(cfg, 0, 0, fixed_key, fixed_iv, fixed_aad, + sizeof(fixed_aad) - 1, tag_stream, &why); + if (!TEST_int_eq(rv, 1)) { + TEST_error("%s: streaming verification failed at %s", + cfg->name, why ? why : "FINAL"); + goto end; + } + rv = ccm_empty_final_op(cfg, 0, 1, fixed_key, fixed_iv, fixed_aad, + sizeof(fixed_aad) - 1, tag_stream, &why); + if (!TEST_int_eq(rv, 1)) { + TEST_error("%s: one-shot verification failed at %s", + cfg->name, why ? why : "FINAL"); + goto end; + } + + memcpy(bad_tag, tag_stream, cfg->taglen); + bad_tag[0] ^= 1; + rv = ccm_empty_final_op(cfg, 0, 0, fixed_key, fixed_iv, fixed_aad, + sizeof(fixed_aad) - 1, bad_tag, &why); + if (!TEST_int_eq(rv, 0)) { + TEST_error("%s: streaming Final accepted an invalid tag", cfg->name); + goto end; + } + ERR_clear_error(); + rv = ccm_empty_final_op(cfg, 0, 1, fixed_key, fixed_iv, fixed_aad, + sizeof(fixed_aad) - 1, bad_tag, &why); + if (!TEST_int_eq(rv, 0)) { + TEST_error("%s: one-shot Final accepted an invalid tag", cfg->name); + goto end; + } + ERR_clear_error(); + + ok = 1; +end: + return ok; +} + #ifndef OPENSSL_NO_DES static int test_EVP_CIPHER_get_type_des_ede3(void) { @@ -7476,18 +8315,21 @@ int setup_tests(void) ADD_TEST(test_RSA_OAEP_set_get_params); ADD_TEST(test_RSA_OAEP_set_null_label); ADD_TEST(test_RSA_verify_recover_rejects_short_buffer); + ADD_TEST(test_RSA_verify_recover_empty_payload); ADD_TEST(test_RSA_encrypt); #ifndef OPENSSL_NO_DEPRECATED_3_0 ADD_TEST(test_RSA_legacy); #endif #if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305) ADD_TEST(test_decrypt_null_chunks); + ADD_TEST(test_chacha20_poly1305_late_aad); #endif #ifndef OPENSSL_NO_DH ADD_TEST(test_DH_priv_pub); #ifndef OPENSSL_NO_DEPRECATED_3_0 ADD_TEST(test_EVP_PKEY_set1_DH); #endif + ADD_TEST(test_dhx_derive_rejects_bad_peer_q); #endif #ifndef OPENSSL_NO_EC ADD_TEST(test_EC_priv_pub); @@ -7561,6 +8403,12 @@ int setup_tests(void) #endif ADD_ALL_TESTS(test_aead_oneshot_roundtrip, 2 * OSSL_NELEM(aead_oneshot_cfgs)); + ADD_ALL_TESTS(test_aead_oneshot_zerolen, + 2 * OSSL_NELEM(aead_oneshot_zerolen_cfgs)); + + ADD_ALL_TESTS(test_rsasve_degenerate_exponent, 2); + ADD_ALL_TESTS(test_rsasve_degenerate_ciphertext, 3); + ADD_ALL_TESTS(test_ccm_empty_final, OSSL_NELEM(ccm_empty_final_cfgs)); /* Test cases for CVE-2026-45446 */ ADD_TEST(test_aes_gcm_siv_empty_data); diff --git a/test/evp_extra_test2.c b/test/evp_extra_test2.c index 4458f5b2426f1..f7be80b11bc2c 100644 --- a/test/evp_extra_test2.c +++ b/test/evp_extra_test2.c @@ -178,6 +178,115 @@ static const unsigned char kExampleRSAKeyPKCS8[] = { 0x20, 0x1b, 0xe5, 0xdf }; +/* + * An RSA-PSS 2048-bit private key in ASN.1 DER form. Used by the + * table-driven checks instead of keygen to save CI cycles (RSA keygen + * at this size is slow). Generated with: + * > openssl genpkey -quiet -algorithm rsa-pss -outform DER > rsa-pss.der + * > xxd -i < rsa-pss.der + * Of course, never use this key for anything but tests. + */ +static const unsigned char kExampleRSAPSSKeyDER[] = { + 0x30, 0x82, 0x04, 0xba, 0x02, 0x01, 0x00, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0a, 0x04, 0x82, 0x04, 0xa6, 0x30, 0x82, 0x04, 0xa2, 0x02, 0x01, + 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa3, 0x32, 0x24, 0xdb, 0x9b, 0xec, 0x8f, 0x18, 0xbe, + 0xeb, 0xef, 0x9b, 0x0e, 0x06, 0x11, 0x78, 0x26, 0x66, 0x2b, 0x75, 0xff, 0x79, 0x50, 0xa9, + 0x96, 0xb2, 0xdf, 0xe1, 0x71, 0x2f, 0x8f, 0x3f, 0x08, 0x16, 0x3f, 0x53, 0x5a, 0x2c, 0x7c, + 0xbb, 0xb9, 0xa2, 0x54, 0x2c, 0x81, 0xaf, 0x58, 0xd1, 0xb4, 0xfe, 0xd6, 0x2a, 0x5c, 0x47, + 0xfe, 0x20, 0xf0, 0xce, 0xdc, 0xfe, 0x08, 0x7f, 0x3a, 0x24, 0xcd, 0xa0, 0x87, 0xcb, 0x0e, + 0xd7, 0xcf, 0xee, 0x26, 0x12, 0x1f, 0xdb, 0x8b, 0x0f, 0x12, 0x32, 0x05, 0x73, 0x8f, 0x60, + 0xfa, 0x75, 0x49, 0xb5, 0x50, 0x2d, 0x45, 0x72, 0x8b, 0x1d, 0x7f, 0xd3, 0x47, 0x2c, 0x5b, + 0x0e, 0x24, 0x28, 0xe2, 0xc6, 0x01, 0x74, 0x10, 0xbe, 0xe4, 0xc7, 0xd2, 0xe5, 0xf4, 0x90, + 0x10, 0xc0, 0x28, 0x66, 0xed, 0xc4, 0x84, 0xac, 0xb2, 0x01, 0x8e, 0x8a, 0xd1, 0x86, 0x82, + 0x77, 0x89, 0xd8, 0x64, 0xaa, 0xca, 0x1d, 0x27, 0x3e, 0xfd, 0x78, 0x4e, 0xd7, 0x8d, 0xc5, + 0x25, 0xab, 0xb1, 0xfb, 0x94, 0x86, 0xa1, 0x3d, 0xc4, 0x8d, 0x62, 0x5e, 0x59, 0x13, 0x25, + 0xb7, 0x77, 0x20, 0x7e, 0x0a, 0xf8, 0xd0, 0x4f, 0xf4, 0x9c, 0x6f, 0x19, 0x67, 0xe7, 0x6f, + 0x62, 0xd9, 0xc9, 0xe5, 0x97, 0x90, 0xaa, 0xd5, 0x94, 0x98, 0x61, 0xb7, 0xf9, 0xfc, 0x86, + 0x45, 0xd8, 0x6f, 0x37, 0x35, 0x51, 0x0d, 0x9f, 0xb0, 0x9f, 0xd5, 0x1b, 0x10, 0x87, 0xa2, + 0xb9, 0xe0, 0x5e, 0xc9, 0x6b, 0x1b, 0x5d, 0xf3, 0x3a, 0x16, 0x4a, 0x79, 0x25, 0xcf, 0x95, + 0xfc, 0xca, 0x8a, 0x7a, 0xac, 0x49, 0xd9, 0x36, 0xa5, 0x45, 0xc4, 0x9a, 0x01, 0x60, 0xed, + 0x8b, 0xcf, 0x66, 0xf2, 0xfb, 0x98, 0x93, 0x69, 0x84, 0xf2, 0xa8, 0x02, 0x12, 0x4d, 0x7b, + 0x48, 0xa1, 0xfb, 0x4d, 0x59, 0x96, 0x57, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, + 0x00, 0x0f, 0x43, 0x65, 0xda, 0x1a, 0x53, 0xbe, 0x30, 0x78, 0xce, 0xd5, 0x4a, 0xa1, 0xbd, + 0xa4, 0x8d, 0xa1, 0xbd, 0xc5, 0x8b, 0xd4, 0x38, 0x92, 0xf8, 0x41, 0x8d, 0x7a, 0x4d, 0xfa, + 0x09, 0x92, 0x32, 0xb9, 0x7d, 0x67, 0x2f, 0xd3, 0x0b, 0xbd, 0x20, 0xcb, 0xa4, 0x68, 0x8d, + 0xff, 0x15, 0x18, 0xd0, 0x08, 0x47, 0x1b, 0x5d, 0xbb, 0xe2, 0xc9, 0xdc, 0x67, 0xd9, 0x59, + 0x26, 0xf3, 0x41, 0x7e, 0xfd, 0x29, 0x34, 0x3d, 0xef, 0x1a, 0x74, 0xc9, 0xd0, 0x42, 0xc4, + 0x48, 0x31, 0x7e, 0xe8, 0x8a, 0x71, 0x9e, 0x3b, 0xe8, 0x29, 0x90, 0x53, 0x3e, 0xf1, 0x13, + 0xce, 0x20, 0x24, 0x2d, 0xe9, 0xb4, 0xe6, 0x5c, 0x4e, 0x44, 0x37, 0xe6, 0xde, 0xe2, 0x12, + 0xd5, 0xd8, 0xf6, 0xa5, 0xfb, 0xfc, 0xca, 0x77, 0x52, 0x6f, 0xd4, 0xf9, 0x3b, 0xee, 0x20, + 0x87, 0xd4, 0x46, 0xd8, 0xa1, 0x37, 0xa5, 0x39, 0x22, 0x5e, 0xb6, 0x2c, 0xe8, 0x49, 0xf4, + 0x78, 0x07, 0x23, 0xba, 0x19, 0x6e, 0x25, 0xb6, 0x7b, 0x2b, 0x9d, 0x7e, 0x19, 0x26, 0x95, + 0xe7, 0x20, 0xb8, 0x21, 0xd1, 0xf5, 0xb9, 0x6d, 0xa6, 0x2a, 0xcb, 0x46, 0xe4, 0x62, 0x71, + 0x63, 0xe1, 0xa0, 0x77, 0x1d, 0xf7, 0x10, 0xf6, 0x1e, 0x70, 0x27, 0x72, 0xf8, 0x68, 0x19, + 0x6d, 0x84, 0xa1, 0x46, 0xcd, 0x52, 0x0f, 0x86, 0x77, 0x7a, 0x92, 0x5c, 0xc6, 0x39, 0xc2, + 0x67, 0x12, 0xb0, 0x68, 0x6c, 0xe0, 0x19, 0xde, 0x61, 0xeb, 0x39, 0x1f, 0x14, 0xd0, 0xc7, + 0xd6, 0x77, 0xc2, 0x83, 0x9e, 0xe2, 0xa3, 0x3a, 0x22, 0x02, 0x45, 0xf1, 0x10, 0x86, 0x77, + 0x4a, 0x95, 0xf3, 0x75, 0x90, 0x22, 0x9b, 0xb2, 0xcd, 0xcd, 0x2f, 0x27, 0xff, 0xe7, 0xac, + 0x9c, 0xdb, 0x85, 0x31, 0xeb, 0x2b, 0xfa, 0x8f, 0x9e, 0xbe, 0x92, 0x1a, 0xcd, 0xd3, 0x98, + 0x1a, 0x75, 0x02, 0x81, 0x81, 0x00, 0xd5, 0x06, 0xa1, 0x08, 0x41, 0x02, 0xab, 0x3a, 0x00, + 0xf5, 0x74, 0x5f, 0xb7, 0xf0, 0xa7, 0x9d, 0x0a, 0x26, 0x32, 0x7e, 0x48, 0xa4, 0xf7, 0xbe, + 0xcf, 0xba, 0x27, 0x2a, 0x7d, 0x60, 0xd2, 0x16, 0x59, 0xc3, 0xf0, 0x78, 0x33, 0x3a, 0x36, + 0x86, 0xb5, 0xd4, 0x29, 0x25, 0x23, 0x5a, 0xeb, 0x5a, 0x96, 0x82, 0xfc, 0x08, 0x08, 0x1c, + 0xcc, 0xed, 0xb3, 0xf1, 0x27, 0xca, 0x1c, 0xa8, 0xe8, 0x36, 0x77, 0xa4, 0x57, 0x9a, 0x1d, + 0xde, 0x2b, 0x3b, 0xc3, 0x41, 0x7c, 0x58, 0x33, 0x11, 0x3b, 0xee, 0x7a, 0xc9, 0xe9, 0x4b, + 0xa2, 0x3b, 0xc3, 0x68, 0x19, 0x6a, 0x00, 0x7c, 0x59, 0x90, 0x77, 0x11, 0xed, 0x47, 0x4a, + 0x5a, 0xfe, 0x3a, 0x29, 0x3a, 0xad, 0x80, 0xe9, 0xff, 0xce, 0x07, 0x3f, 0x80, 0x5f, 0x98, + 0x14, 0x1a, 0xf0, 0x9c, 0xc7, 0x8d, 0x42, 0x06, 0xc4, 0xf8, 0x89, 0xe3, 0xe0, 0x23, 0x02, + 0x81, 0x81, 0x00, 0xc4, 0x1e, 0x20, 0x31, 0xfa, 0xe7, 0x6a, 0xa5, 0x18, 0xbe, 0xce, 0x45, + 0x15, 0x97, 0x67, 0x5f, 0xd0, 0xc6, 0x0f, 0xa2, 0x6c, 0x68, 0x5e, 0xe9, 0xca, 0x48, 0x8c, + 0x46, 0x08, 0x06, 0xc1, 0xe9, 0xac, 0x8c, 0x01, 0x55, 0xc7, 0xf2, 0x02, 0x98, 0x2b, 0x8d, + 0x4e, 0x24, 0x2d, 0x56, 0x7b, 0x40, 0x24, 0x28, 0xaa, 0x4a, 0xf7, 0x83, 0x88, 0x38, 0xa5, + 0x03, 0x2b, 0xb3, 0x1c, 0x4a, 0x95, 0x70, 0xf6, 0x80, 0xcc, 0x21, 0xd0, 0xab, 0x8a, 0x10, + 0xb2, 0xa6, 0x1a, 0x27, 0xb6, 0xae, 0x24, 0xed, 0xa9, 0xfe, 0xfc, 0x74, 0x7f, 0x97, 0x9b, + 0xe1, 0xc2, 0x46, 0x48, 0xed, 0x5f, 0x2f, 0x9e, 0x54, 0x77, 0x1f, 0x61, 0x46, 0x24, 0x08, + 0x7e, 0xb5, 0x63, 0xa1, 0xe2, 0x6f, 0x58, 0xc8, 0x76, 0x98, 0x8a, 0x9a, 0xa5, 0xb9, 0x15, + 0xfb, 0xf4, 0xb8, 0xfd, 0x84, 0xb6, 0xbc, 0x5f, 0x59, 0xfa, 0x3d, 0x02, 0x81, 0x80, 0x2a, + 0x97, 0x43, 0xb4, 0xf1, 0xc2, 0x85, 0xd7, 0x77, 0xff, 0x9b, 0x3f, 0xd3, 0xf7, 0xe2, 0x9b, + 0x2c, 0x3f, 0x4c, 0xd3, 0x20, 0xd5, 0x12, 0xcf, 0x6c, 0x9a, 0xcc, 0x5f, 0xdb, 0x67, 0x73, + 0x39, 0x92, 0xc2, 0xf1, 0x1e, 0x27, 0x27, 0xd9, 0x64, 0xff, 0x8f, 0xa6, 0x96, 0x4d, 0x46, + 0x4d, 0x4d, 0xf4, 0x4f, 0xc5, 0xf2, 0x19, 0x25, 0x20, 0xf7, 0xd9, 0x85, 0x3a, 0xae, 0x57, + 0x22, 0x92, 0x22, 0xe9, 0xb2, 0xca, 0xec, 0xfe, 0x51, 0xc0, 0x15, 0x17, 0xc9, 0xcd, 0x01, + 0x99, 0x5c, 0x35, 0xbe, 0x4d, 0x80, 0x77, 0x0b, 0x6f, 0x29, 0x41, 0xbd, 0x5b, 0x6f, 0x6d, + 0x1f, 0x6f, 0x8c, 0xc9, 0xb1, 0xa4, 0xde, 0x1f, 0x08, 0xa8, 0x51, 0x9a, 0x92, 0xa7, 0xc3, + 0xe1, 0x85, 0x0a, 0x7d, 0x3a, 0x7e, 0x01, 0x1e, 0xd7, 0xce, 0x37, 0x13, 0x31, 0x76, 0x95, + 0x9f, 0xe2, 0xdb, 0xca, 0x3d, 0xec, 0x3f, 0x02, 0x81, 0x80, 0x73, 0x99, 0x66, 0x54, 0xcf, + 0x96, 0x34, 0xd0, 0x58, 0x03, 0xb0, 0x46, 0x1c, 0x72, 0x00, 0x27, 0x04, 0x42, 0x9a, 0xd8, + 0x9c, 0x99, 0xf0, 0xc8, 0x51, 0xc9, 0xed, 0x95, 0x22, 0x0a, 0x09, 0xa7, 0x19, 0x63, 0xf5, + 0x2d, 0x81, 0x0b, 0xef, 0xe7, 0x8e, 0x54, 0x5e, 0x69, 0x08, 0xa8, 0x5f, 0x41, 0xf1, 0x8e, + 0x5e, 0xc2, 0x8d, 0x9e, 0xe4, 0x5e, 0xaf, 0x35, 0x6d, 0x3e, 0xc8, 0x40, 0x56, 0x52, 0x1d, + 0x9a, 0xd1, 0xb8, 0x64, 0xed, 0x98, 0x16, 0x3b, 0x97, 0x98, 0xf7, 0x2b, 0xc0, 0xfe, 0x57, + 0x70, 0xca, 0xb2, 0x38, 0x61, 0x35, 0x16, 0x57, 0x3e, 0x52, 0x7b, 0x8e, 0x1f, 0x7b, 0x4c, + 0x12, 0x71, 0x9c, 0xf7, 0x93, 0x86, 0x8d, 0xd3, 0x52, 0x4c, 0x06, 0x12, 0x18, 0x9b, 0xf6, + 0x9d, 0xa1, 0x50, 0xa1, 0xd3, 0x69, 0x83, 0xc1, 0xde, 0x00, 0x64, 0xbf, 0x23, 0x8f, 0x69, + 0x8c, 0xf9, 0xe9, 0x02, 0x81, 0x80, 0x02, 0xce, 0x66, 0x6b, 0x32, 0x73, 0x62, 0x60, 0x27, + 0x3e, 0x38, 0x1d, 0xd8, 0x70, 0xdb, 0x4e, 0x32, 0xf7, 0x7a, 0x7b, 0x22, 0x7b, 0x9b, 0xd7, + 0x49, 0x4f, 0x5b, 0x9b, 0xaa, 0x2c, 0x5b, 0x99, 0x22, 0x1e, 0x6e, 0x7e, 0x19, 0x8a, 0xf1, + 0x97, 0xfe, 0x3f, 0xcd, 0x9e, 0xa4, 0x46, 0xf0, 0x9a, 0x62, 0x0f, 0x1a, 0xcd, 0x77, 0xe1, + 0x88, 0xe1, 0x9a, 0x22, 0x84, 0x1b, 0xbf, 0xf0, 0x71, 0xf4, 0x64, 0xfd, 0xd5, 0xaa, 0xb4, + 0x28, 0xdc, 0xef, 0xd9, 0xec, 0x29, 0x11, 0xc4, 0x58, 0x0f, 0xeb, 0x3c, 0x41, 0x66, 0x4a, + 0x98, 0x18, 0x26, 0xfe, 0x3e, 0x7e, 0xc3, 0x36, 0xfa, 0xbc, 0x64, 0x69, 0x1f, 0xce, 0x1c, + 0xc1, 0xb5, 0xe9, 0xa8, 0x78, 0xf7, 0x6d, 0xb6, 0x0c, 0x58, 0x29, 0xe2, 0xbf, 0xd0, 0xbe, + 0x2e, 0x10, 0xfa, 0x74, 0x02, 0x9b, 0x48, 0xa5, 0xc9, 0x74, 0xed, 0xed, 0x7d, 0xa8 +}; + +#ifndef OPENSSL_NO_DH +static char group_ffdhe2048[] = "ffdhe2048"; +static const OSSL_PARAM dhx_keygen_params[] = { + OSSL_PARAM_utf8_string("group", group_ffdhe2048, + sizeof(group_ffdhe2048) - 1), + OSSL_PARAM_END +}; +#endif + +#ifndef OPENSSL_NO_EC +static char group_p256[] = "P-256"; +static const OSSL_PARAM ec_keygen_params[] = { + OSSL_PARAM_utf8_string("group", group_p256, sizeof(group_p256) - 1), + OSSL_PARAM_END +}; +#endif + #ifndef OPENSSL_NO_DH static const unsigned char kExampleDHPrivateKeyDER[] = { 0x30, 0x82, 0x02, 0x26, 0x02, 0x01, 0x00, 0x30, 0x82, 0x01, 0x17, 0x06, @@ -296,49 +405,73 @@ static APK_DATA keydata[] = { static int pkey_has_private(EVP_PKEY *key, const char *privtag, int use_octstring) { - int ret = 0; - if (use_octstring) { - unsigned char buf[64]; - - ret = EVP_PKEY_get_octet_string_param(key, privtag, buf, sizeof(buf), - NULL); + /* + * Existence probe only: pass NULL buffer, ignore the returned size. + * Avoids hard-coded fixed buffers that would cap at 64 bytes and + * fail for PQC private keys (ML-DSA-44 is ~2.5 KB). + */ + return EVP_PKEY_get_octet_string_param(key, privtag, NULL, 0, NULL); } else { BIGNUM *bn = NULL; + int ret = EVP_PKEY_get_bn_param(key, privtag, &bn); - ret = EVP_PKEY_get_bn_param(key, privtag, &bn); BN_free(bn); + return ret; } - return ret; } +/* + * Private-component tags we know about, in lookup order. Extend this + * list if a new algorithm adopts a different convention; do_pkey_tofrom + * _data_select() scans it on each key and only needs one match. + */ +static const char *const pkey_priv_tags[] = { + OSSL_PKEY_PARAM_PRIV_KEY, /* DH, DSA, EC, ECX, SM2, ML-*, SLH-DSA */ + OSSL_PKEY_PARAM_RSA_D, /* RSA, RSA-PSS */ +}; + static int do_pkey_tofrom_data_select(EVP_PKEY *key, const char *keytype) { int ret = 0; OSSL_PARAM *pub_params = NULL, *keypair_params = NULL; + const OSSL_PARAM *priv = NULL; EVP_PKEY *fromkey = NULL, *fromkeypair = NULL; EVP_PKEY_CTX *fromctx = NULL; - const char *privtag = strcmp(keytype, "RSA") == 0 ? "d" : "priv"; - const int use_octstring = strcmp(keytype, "X25519") == 0; + const char *privtag; + int use_octstring; + size_t t; /* - * Select only the public key component when using EVP_PKEY_todata() and - * check that the resulting param array does not contain a private key. + * Export the full keypair first so we can discover the algorithm's + * private-component tag from the emitted params rather than hand-coding + * it per keytype. */ - if (!TEST_int_eq(EVP_PKEY_todata(key, EVP_PKEY_PUBLIC_KEY, &pub_params), 1) - || !TEST_ptr_null(OSSL_PARAM_locate(pub_params, privtag))) + if (!TEST_int_eq(EVP_PKEY_todata(key, EVP_PKEY_KEYPAIR, &keypair_params), 1)) + goto end; + + for (t = 0; t < OSSL_NELEM(pkey_priv_tags); t++) + if ((priv = OSSL_PARAM_locate(keypair_params, pkey_priv_tags[t])) != NULL) + break; + if (priv == NULL) { + TEST_error("%s: KEYPAIR todata() emitted no known private component", + keytype); goto end; + } + privtag = priv->key; + use_octstring = priv->data_type == OSSL_PARAM_OCTET_STRING; + /* - * Select the keypair when using EVP_PKEY_todata() and check that - * the param array contains a private key. + * Select only the public key via EVP_PKEY_todata(): the private tag we + * just learned must be absent. */ - if (!TEST_int_eq(EVP_PKEY_todata(key, EVP_PKEY_KEYPAIR, &keypair_params), 1) - || !TEST_ptr(OSSL_PARAM_locate(keypair_params, privtag))) + if (!TEST_int_eq(EVP_PKEY_todata(key, EVP_PKEY_PUBLIC_KEY, &pub_params), 1) + || !TEST_ptr_null(OSSL_PARAM_locate(pub_params, privtag))) goto end; /* - * Select only the public key when using EVP_PKEY_fromdata() and check that - * the resulting key does not contain a private key. + * Round-trip: importing only the public selection from the full keypair + * params must yield a key that has no private component. */ if (!TEST_ptr(fromctx = EVP_PKEY_CTX_new_from_name(mainctx, keytype, NULL)) || !TEST_int_eq(EVP_PKEY_fromdata_init(fromctx), 1) @@ -347,10 +480,8 @@ static int do_pkey_tofrom_data_select(EVP_PKEY *key, const char *keytype) 1) || !TEST_false(pkey_has_private(fromkey, privtag, use_octstring))) goto end; - /* - * Select the keypair when using EVP_PKEY_fromdata() and check that - * the resulting key contains a private key. - */ + + /* Round-trip: a full keypair import must carry the private component. */ if (!TEST_int_eq(EVP_PKEY_fromdata(fromctx, &fromkeypair, EVP_PKEY_KEYPAIR, keypair_params), 1) @@ -366,35 +497,135 @@ static int do_pkey_tofrom_data_select(EVP_PKEY *key, const char *keytype) return ret; } -#ifndef OPENSSL_NO_DH -static int test_dh_tofrom_data_select(void) +/* + * Pass every advertised gettable parameter through EVP_PKEY_get_params() + * as a probe, twice: once with NULL data (size negotiation), then again + * with storage allocated for the advertised type. Either fetch must + * succeed as a whole. Pass 2 is what exercises the type-matching + * branches in the per-type OSSL_PARAM setters: a NULL-data probe + * succeeds before those branches are reached, which is why this check + * would otherwise miss gettable-table / getter mismatches (an entry + * advertised as OCTET_STRING whose getter populates it as a BIGNUM). + * + * The provider is free to leave individual entries unmodified, e.g. + * private-key data on a public-only key; only whole-fetch failure + * is treated as a regression. + */ +static int do_pkey_all_gettables_probe(EVP_PKEY *pkey, const char *keytype) { - int ret; - OSSL_PARAM params[2]; - EVP_PKEY *key = NULL; - EVP_PKEY_CTX *gctx = NULL; -#ifndef OPENSSL_NO_DEPRECATED_3_0 - const DH *dhkey; - const BIGNUM *privkey; -#endif + int ret = 0; + const OSSL_PARAM *gettable; + OSSL_PARAM *probe = NULL; + void **storage = NULL; + size_t n = 0, i; + int need_refetch = 0; - params[0] = OSSL_PARAM_construct_utf8_string("group", "ffdhe2048", 0); - params[1] = OSSL_PARAM_construct_end(); - ret = TEST_ptr(gctx = EVP_PKEY_CTX_new_from_name(mainctx, "DHX", NULL)) - && TEST_int_gt(EVP_PKEY_keygen_init(gctx), 0) - && TEST_true(EVP_PKEY_CTX_set_params(gctx, params)) - && TEST_int_gt(EVP_PKEY_generate(gctx, &key), 0) - && TEST_true(do_pkey_tofrom_data_select(key, "DHX")); -#ifndef OPENSSL_NO_DEPRECATED_3_0 - ret = ret && TEST_ptr(dhkey = EVP_PKEY_get0_DH(key)) - && TEST_ptr(privkey = DH_get0_priv_key(dhkey)) - && TEST_int_le(BN_num_bits(privkey), 225); -#endif - EVP_PKEY_free(key); - EVP_PKEY_CTX_free(gctx); + if (!TEST_ptr(gettable = EVP_PKEY_gettable_params(pkey))) + goto err; + + while (gettable[n].key != NULL) + n++; + if (!TEST_ptr(probe = OPENSSL_zalloc((n + 1) * sizeof(*probe))) + || (n > 0 + && !TEST_ptr(storage = OPENSSL_zalloc(n * sizeof(*storage))))) + goto err; + + for (i = 0; i < n; i++) { + /* + * Copy the advertised entry as a template, then reset the + * data fields to the "probe" state. For OCTET_PTR / UTF8_PTR + * the setter writes *data directly (no size negotiation), + * so hand it a pointer slot up front. + */ + probe[i] = gettable[i]; + probe[i].data = NULL; + probe[i].data_size = 0; + probe[i].return_size = OSSL_PARAM_UNMODIFIED; + if (gettable[i].data_type == OSSL_PARAM_OCTET_PTR + || gettable[i].data_type == OSSL_PARAM_UTF8_PTR) { + if (!TEST_ptr(storage[i] = OPENSSL_zalloc(sizeof(void *)))) + goto err; + probe[i].data = storage[i]; + } + } + probe[n] = OSSL_PARAM_construct_end(); + + /* Pass 1: NULL-data probe populates return_size for sized entries. */ + if (!TEST_true(EVP_PKEY_get_params(pkey, probe))) { + TEST_info("%s: Pass 1 (size probe) failed", keytype); + goto err; + } + + /* Allocate storage for each populated sized entry. */ + for (i = 0; i < n; i++) { + size_t need; + + if (!OSSL_PARAM_modified(&probe[i])) + continue; + switch (probe[i].data_type) { + case OSSL_PARAM_INTEGER: + case OSSL_PARAM_UNSIGNED_INTEGER: + case OSSL_PARAM_OCTET_STRING: + case OSSL_PARAM_REAL: + need = probe[i].return_size; + if (!TEST_ptr(storage[i] = OPENSSL_malloc(need == 0 ? 1 : need))) + goto err; + probe[i].data = storage[i]; + probe[i].data_size = need; + probe[i].return_size = OSSL_PARAM_UNMODIFIED; + need_refetch = 1; + break; + case OSSL_PARAM_UTF8_STRING: + /* Leave room for a trailing NUL beyond return_size. */ + need = probe[i].return_size + 1; + if (!TEST_ptr(storage[i] = OPENSSL_malloc(need))) + goto err; + probe[i].data = storage[i]; + probe[i].data_size = need; + probe[i].return_size = OSSL_PARAM_UNMODIFIED; + need_refetch = 1; + break; + default: + /* PTR types were populated in Pass 1; unknown types left as-is. */ + break; + } + } + + /* + * Pass 2: real fetch, with typed storage. This is what actually + * catches advertised-vs-populated type mismatches: the per-type + * OSSL_PARAM_set_*() setters only enforce data_type when data is + * non-NULL. + */ + if (need_refetch && !TEST_true(EVP_PKEY_get_params(pkey, probe))) { + TEST_info("%s: Pass 2 (real fetch) failed", keytype); + goto err; + } + ret = 1; +err: + if (storage != NULL) + for (i = 0; i < n; i++) + OPENSSL_free(storage[i]); + OPENSSL_free(storage); + OPENSSL_free(probe); return ret; } +/* + * Composite check: exercise both the selection-mask semantics of + * todata/fromdata and the advertised-vs-populated type consistency of + * every gettable parameter on the given key. The individual helpers are + * algorithm-agnostic, so this driver works for any asymmetric EVP_PKEY. + * Each keytype-specific test function reduces to (a) key generation and + * (b) invoking this driver. + */ +static int do_pkey_checks(EVP_PKEY *key, const char *keytype) +{ + return do_pkey_tofrom_data_select(key, keytype) + && do_pkey_all_gettables_probe(key, keytype); +} + +#ifndef OPENSSL_NO_DH static int test_dh_paramgen(void) { int ret; @@ -494,7 +725,7 @@ static int test_new_keytype(void) unsigned char *out = NULL, *secret = NULL, *secret2 = NULL; /* without tls-provider key should not be create-able */ - if (TEST_ptr(key = EVP_PKEY_Q_keygen(mainctx, NULL, "XOR"))) + if (!TEST_ptr_null(key = EVP_PKEY_Q_keygen(mainctx, NULL, "XOR"))) goto err; /* prepare & load tls-provider */ if (!TEST_true(OSSL_PROVIDER_add_builtin(mainctx, "tls-provider", @@ -559,57 +790,7 @@ static int test_ec_d2i_i2d_pubkey(void) return ret; } -static int test_ec_tofrom_data_select(void) -{ - int ret; - EVP_PKEY *key = NULL; - - ret = TEST_ptr(key = EVP_PKEY_Q_keygen(mainctx, NULL, "EC", "P-256")) - && TEST_true(do_pkey_tofrom_data_select(key, "EC")); - EVP_PKEY_free(key); - return ret; -} - -#ifndef OPENSSL_NO_ECX -static int test_ecx_tofrom_data_select(void) -{ - int ret; - EVP_PKEY *key = NULL; - - ret = TEST_ptr(key = EVP_PKEY_Q_keygen(mainctx, NULL, "X25519")) - && TEST_true(do_pkey_tofrom_data_select(key, "X25519")); - EVP_PKEY_free(key); - return ret; -} -#endif -#endif - -#ifndef OPENSSL_NO_SM2 -static int test_sm2_tofrom_data_select(void) -{ - int ret; - EVP_PKEY *key = NULL; - - ret = TEST_ptr(key = EVP_PKEY_Q_keygen(mainctx, NULL, "SM2")) - && TEST_true(do_pkey_tofrom_data_select(key, "SM2")); - EVP_PKEY_free(key); - return ret; -} -#endif - -static int test_rsa_tofrom_data_select(void) -{ - int ret; - EVP_PKEY *key = NULL; - const unsigned char *pdata = kExampleRSAKeyDER; - int pdata_len = sizeof(kExampleRSAKeyDER); - - ret = TEST_ptr(key = d2i_AutoPrivateKey_ex(NULL, &pdata, pdata_len, - mainctx, NULL)) - && TEST_true(do_pkey_tofrom_data_select(key, "RSA")); - EVP_PKEY_free(key); - return ret; -} +#endif /* OPENSSL_NO_EC */ /* This is the equivalent of test_d2i_AutoPrivateKey in evp_extra_test */ static int test_d2i_AutoPrivateKey_ex(int i) @@ -1069,7 +1250,9 @@ static const unsigned char dsa_pub[] = { 0xcc, 0xe2, 0x46, 0xce, 0xf5, 0x6d, 0xd8, 0x18, 0x91, 0xc4, 0x20, 0xbf, 0x07, 0x48, 0x45, 0xfd }; +#endif +#ifndef OPENSSL_NO_DSA static int do_check_params(OSSL_PARAM key_params[], int expected) { EVP_PKEY_CTX *gen_ctx = NULL, *check_ctx = NULL; @@ -1116,20 +1299,6 @@ static int do_check_int(OSSL_PARAM params[], const char *key, int expected) && TEST_int_eq(val, expected); } -static int test_dsa_tofrom_data_select(void) -{ - int ret; - EVP_PKEY *key = NULL; - const unsigned char *pkeydata = dsa_key; - - ret = TEST_ptr(key = d2i_AutoPrivateKey_ex(NULL, &pkeydata, sizeof(dsa_key), - mainctx, NULL)) - && TEST_true(do_pkey_tofrom_data_select(key, "DSA")); - - EVP_PKEY_free(key); - return ret; -} - static int test_dsa_todata(void) { EVP_PKEY *pkey = NULL; @@ -1483,6 +1652,112 @@ static int evp_test_name_parsing(void) return 1; } +/* + * Table-driven driver for do_pkey_checks(). Each entry names the + * algorithm and supplies either (a) a prefabricated DER blob, loaded + * via d2i_AutoPrivateKey_ex(), or (b) an optional OSSL_PARAM array + * passed to EVP_PKEY_CTX_set_params() before EVP_PKEY_generate(). + * The downstream checks are algorithm-agnostic; only the per-algorithm + * inputs live in this table. + */ +typedef struct pkey_test_spec_st { + const char *name; /* algorithm name for keygen or logging */ + const unsigned char *der; /* prefab private key DER, or NULL */ + uint32_t der_len; /* size of the DER blob when set */ + const OSSL_PARAM *params; /* keygen params, or NULL for defaults */ +} PKEY_TEST_SPEC; + +static const PKEY_TEST_SPEC pkey_test_specs[] = { +#ifndef OPENSSL_NO_DH + { "DHX", NULL, 0, dhx_keygen_params }, +#endif +#ifndef OPENSSL_NO_DSA + { "DSA", dsa_key, sizeof(dsa_key), NULL }, +#endif + { "RSA", kExampleRSAKeyDER, sizeof(kExampleRSAKeyDER), NULL }, + { "RSA-PSS", kExampleRSAPSSKeyDER, sizeof(kExampleRSAPSSKeyDER), NULL }, +#ifndef OPENSSL_NO_EC + { "EC", NULL, 0, ec_keygen_params }, +#ifndef OPENSSL_NO_ECX + { "X25519", NULL, 0, NULL }, + { "ED25519", NULL, 0, NULL }, +#endif +#ifndef OPENSSL_NO_SM2 + { "SM2", NULL, 0, NULL }, +#endif +#endif +#ifndef OPENSSL_NO_ML_KEM + { "ML-KEM-512", NULL, 0, NULL }, +#endif +#ifndef OPENSSL_NO_ML_DSA + { "ML-DSA-44", NULL, 0, NULL }, +#endif +#ifndef OPENSSL_NO_SLH_DSA + { "SLH-DSA-SHA2-128f", NULL, 0, NULL }, +#endif +}; + +static EVP_PKEY *pkey_from_spec(OSSL_LIB_CTX *libctx, + const PKEY_TEST_SPEC *spec) +{ + EVP_PKEY *key = NULL; + EVP_PKEY_CTX *gctx = NULL; + + if (spec->der != NULL) { + const unsigned char *p = spec->der; + + return d2i_AutoPrivateKey_ex(NULL, &p, spec->der_len, libctx, NULL); + } + + if ((gctx = EVP_PKEY_CTX_new_from_name(libctx, spec->name, NULL)) == NULL + || EVP_PKEY_keygen_init(gctx) <= 0 + || (spec->params != NULL + && EVP_PKEY_CTX_set_params(gctx, spec->params) <= 0) + || EVP_PKEY_generate(gctx, &key) <= 0) { + EVP_PKEY_free(key); + key = NULL; + } + EVP_PKEY_CTX_free(gctx); + return key; +} + +static int test_pkey_by_spec(int i) +{ + EVP_PKEY *key = pkey_from_spec(mainctx, &pkey_test_specs[i]); + int ret = TEST_ptr(key) + && do_pkey_checks(key, pkey_test_specs[i].name); + + EVP_PKEY_free(key); + return ret; +} + +#if !defined(OPENSSL_NO_DH) && !defined(OPENSSL_NO_DEPRECATED_3_0) +/* + * DHX keygen with group "ffdhe2048" reduces the private exponent modulo + * the sub-group order, so the exposed BN_num_bits() should not exceed + * the sub-group size. This tail check is DHX-specific and therefore + * does not fit the generic spec-table driver. + */ +static int test_dh_priv_bits(void) +{ + static const PKEY_TEST_SPEC dhx_spec = { + "DHX", NULL, 0, dhx_keygen_params + }; + int ret; + EVP_PKEY *key; + const DH *dhkey; + const BIGNUM *privkey; + + if (!TEST_ptr(key = pkey_from_spec(mainctx, &dhx_spec))) + return 0; + ret = TEST_ptr(dhkey = EVP_PKEY_get0_DH(key)) + && TEST_ptr(privkey = DH_get0_priv_key(dhkey)) + && TEST_int_le(BN_num_bits(privkey), 225); + EVP_PKEY_free(key); + return ret; +} +#endif + int setup_tests(void) { if (!test_get_libctx(&mainctx, &nullprov, NULL, NULL, NULL)) { @@ -1497,28 +1772,22 @@ int setup_tests(void) ADD_TEST(test_new_keytype); #ifndef OPENSSL_NO_EC ADD_ALL_TESTS(test_d2i_PrivateKey_ex, 2); - ADD_TEST(test_ec_tofrom_data_select); -#ifndef OPENSSL_NO_ECX - ADD_TEST(test_ecx_tofrom_data_select); -#endif ADD_TEST(test_ec_d2i_i2d_pubkey); #else ADD_ALL_TESTS(test_d2i_PrivateKey_ex, 1); #endif -#ifndef OPENSSL_NO_SM2 - ADD_TEST(test_sm2_tofrom_data_select); -#endif #ifndef OPENSSL_NO_DSA ADD_TEST(test_dsa_todata); - ADD_TEST(test_dsa_tofrom_data_select); ADD_ALL_TESTS(test_dsa_fromdata_digest_prop, 2); #endif #ifndef OPENSSL_NO_DH - ADD_TEST(test_dh_tofrom_data_select); ADD_TEST(test_dh_paramgen); ADD_TEST(test_dh_paramfromdata); +#ifndef OPENSSL_NO_DEPRECATED_3_0 + ADD_TEST(test_dh_priv_bits); +#endif #endif - ADD_TEST(test_rsa_tofrom_data_select); + ADD_ALL_TESTS(test_pkey_by_spec, OSSL_NELEM(pkey_test_specs)); ADD_TEST(test_pkey_todata_null); ADD_TEST(test_pkey_export_null); diff --git a/test/fipsidentity.cnf b/test/fipsidentity.cnf new file mode 100644 index 0000000000000..30b7775275d6b --- /dev/null +++ b/test/fipsidentity.cnf @@ -0,0 +1,23 @@ +openssl_conf = openssl_init + +# Comment out the next line to ignore configuration errors +config_diagnostics = 1 + +.include fipsmodule.cnf + +[openssl_init] +providers = provider_sect +random = random_sect + +[provider_sect] +default = default_sect +fips = fips_sect + +[default_sect] +activate = yes + +[fips_sect] +identity = fips-identity + +[random_sect] +properties = fips=yes diff --git a/test/helpers/quictestlib.c b/test/helpers/quictestlib.c index 164acc4007728..c73431338d9e7 100644 --- a/test/helpers/quictestlib.c +++ b/test/helpers/quictestlib.c @@ -1,5 +1,5 @@ /* - * Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -18,6 +18,8 @@ #include "../threadstest.h" #endif #include "internal/quic_ssl.h" +#include "../../ssl/ssl_local.h" +#include "internal/ssl_unwrap.h" #include "internal/quic_wire_pkt.h" #include "internal/quic_record_tx.h" #include "internal/quic_error.h" @@ -311,6 +313,8 @@ int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx, } SSL_set_bio(*cssl, cbio, cbio); + /* Ownership of cbio is now held by *cssl */ + cbio = NULL; if (!TEST_true(SSL_set_blocking_mode(*cssl, (flags & QTEST_FLAG_BLOCK) != 0 ? 1 : 0))) @@ -1373,3 +1377,316 @@ int bio_msg_copy(BIO_MSG *dst, BIO_MSG *src) return 1; } + +static const unsigned char alpn[] = { + 8, 'o', 's', 's', 'l', 't', 'e', 's', 't' +}; + +static int select_alpn(SSL *ssl, const unsigned char **out, unsigned char *out_len, + const unsigned char *in, unsigned int in_len, void *arg) +{ + int e; + + e = SSL_select_next_proto((unsigned char **)out, out_len, alpn, sizeof(alpn), + in, in_len); + return (e == OPENSSL_NPN_NEGOTIATED) ? SSL_TLSEXT_ERR_OK : SSL_TLSEXT_ERR_ALERT_FATAL; +} + +int create_quic_ctx_pair(OSSL_LIB_CTX *libctx, SSL_CTX **c_sctx_p, SSL_CTX **s_sctx_p, + const char *certfile, const char *keyfile) +{ + int ok = 0; + SSL_CTX *c_sctx, *s_sctx; + + c_sctx = NULL; + s_sctx = NULL; + c_sctx = SSL_CTX_new_ex(libctx, NULL, OSSL_QUIC_client_method()); + if (!TEST_ptr(c_sctx)) { + TEST_info("%s SSL_CTX_new_ex(OSSL_QUIC_client_method()) failed", OPENSSL_FUNC); + goto done; + } + + s_sctx = SSL_CTX_new_ex(libctx, NULL, OSSL_QUIC_server_method()); + if (!TEST_ptr(s_sctx)) { + TEST_info("%s SSL_CTX_new_ex(OSSL_QUIC_server_method()) failed", OPENSSL_FUNC); + goto done; + } + + ok = SSL_CTX_use_certificate_file(s_sctx, certfile, SSL_FILETYPE_PEM); + if (ok != 1) { + TEST_info("%s SSL_CTX_use_certificate_file(%s) failed", OPENSSL_FUNC, certfile); + ok = 0; + goto done; + } + + ok = SSL_CTX_use_PrivateKey_file(s_sctx, keyfile, SSL_FILETYPE_PEM); + if (ok != 1) { + TEST_info("%s SSL_CTX_use_PrivateKey_file(%s) failed", OPENSSL_FUNC, keyfile); + ok = 0; + goto done; + } + SSL_CTX_set_alpn_select_cb(s_sctx, select_alpn, NULL); + + *c_sctx_p = c_sctx; + c_sctx = NULL; + *s_sctx_p = s_sctx; + s_sctx = NULL; + +done: + SSL_CTX_free(c_sctx); + SSL_CTX_free(s_sctx); + + return ok; +} + +static int create_dgram_pair(BIO **c_bio_p, BIO **s_bio_p) +{ + BIO *c_bio, *s_bio; + BIO_ADDR *localaddr = NULL; + struct in_addr ina; + int bio_flags = 0; + int ok; + + ina.s_addr = htonl(0x7f000001); + bio_flags |= BIO_DGRAM_CAP_HANDLES_DST_ADDR + | BIO_DGRAM_CAP_HANDLES_SRC_ADDR + | BIO_DGRAM_CAP_PROVIDES_DST_ADDR + | BIO_DGRAM_CAP_PROVIDES_SRC_ADDR; + + c_bio = NULL; + s_bio = NULL; + ok = BIO_new_bio_dgram_pair(&c_bio, 1500, &s_bio, 1500); + if (ok == 0) { + TEST_info("%s BIO_new_bio_dgram_pair() error", OPENSSL_FUNC); + goto done; + } + + ok = BIO_dgram_set_caps(c_bio, bio_flags); + if (ok == 0) { + TEST_info("%s BIO_dgram_set_caps(c_bio, bio_flags) failed", OPENSSL_FUNC); + goto done; + } + + ok = BIO_dgram_set_caps(s_bio, bio_flags); + if (ok == 0) { + TEST_info("%s BIO_dgram_set_caps(s_bio, bio_flags) failed", OPENSSL_FUNC); + goto done; + } + + ok = BIO_dgram_set_mtu(c_bio, 1500); + if (ok == 0) { + TEST_info("%s BIO_dgram_set_mtu(c_bio) error", OPENSSL_FUNC); + goto done; + } + + ok = BIO_dgram_set_mtu(s_bio, 1500); + if (ok == 0) { + TEST_info("%s BIO_dgram_set_mtu(s_bio) error", OPENSSL_FUNC); + goto done; + } + + localaddr = BIO_ADDR_new(); + if (!TEST_ptr(localaddr)) { + TEST_info("%s BIO_ADDR_new() error", OPENSSL_FUNC); + goto done; + } + ok = BIO_ADDR_rawmake(localaddr, AF_INET, &ina, sizeof(ina), htons(4080)); + if (ok == 0) { + TEST_info("%s BIO_ADDR_rawmake(4080) error", OPENSSL_FUNC); + goto done; + } + ok = BIO_dgram_set0_local_addr(c_bio, localaddr); + if (ok != 1) { + TEST_info("%s BIO_dgram_set0_local_addr(c_bio)", OPENSSL_FUNC); + ok = 0; + goto done; + } + + localaddr = BIO_ADDR_new(); + if (!TEST_ptr(localaddr)) { + TEST_info("%s BIO_ADDR_new() error", OPENSSL_FUNC); + goto done; + } + ok = BIO_ADDR_rawmake(localaddr, AF_INET, &ina, sizeof(ina), htons(8040)); + if (ok == 0) { + TEST_info("%s BIO_ADDR_rawmake(8040) error", OPENSSL_FUNC); + goto done; + } + ok = BIO_dgram_set0_local_addr(s_bio, localaddr); + if (ok != 1) { + TEST_info("%s BIO_dgram_set0_local_addr(c_bio)", OPENSSL_FUNC); + ok = 0; + goto done; + } + localaddr = NULL; + + ok = BIO_dgram_set_local_addr_enable(c_bio, 1); + if (ok == 0) { + TEST_info("%s BIO_dgram_set_local_addr_enable(c_bio)", OPENSSL_FUNC); + goto done; + } + + ok = BIO_dgram_set_local_addr_enable(s_bio, 1); + if (ok == 0) { + TEST_info("%s BIO_dgram_set_local_addr_enable(s_bio)", OPENSSL_FUNC); + goto done; + } + + *c_bio_p = c_bio; + c_bio = NULL; + *s_bio_p = s_bio; + s_bio = NULL; + +done: + BIO_free(c_bio); + BIO_free(s_bio); + BIO_ADDR_free(localaddr); + + return ok; +} + +static int init_client(SSL *c_ssl) +{ + BIO_ADDR *peer_addr = NULL; + struct in_addr ina; + int ok = 0; + SSL_CONNECTION *sc; + + ina.s_addr = htonl(0x7f000001); + + ok = SSL_set_tlsext_host_name(c_ssl, "localhost"); + if (ok == 0) { + TEST_info("%s SSL_set_tlsext_host_name()", OPENSSL_FUNC); + goto done; + } + + sc = SSL_CONNECTION_FROM_SSL(c_ssl); + if (sc == NULL || !X509_VERIFY_PARAM_set1_host(sc->param, "localhost", 0)) { + ok = 0; + TEST_info("%s SSL_set1_dnsname()", OPENSSL_FUNC); + goto done; + } + + ok = SSL_set_alpn_protos(c_ssl, alpn, sizeof(alpn)); + if (ok != 0) { + TEST_info("%s SSL_set_alpn_protos() failed", OPENSSL_FUNC); + ok = 0; + goto done; + } + + ok = SSL_set_blocking_mode(c_ssl, 0); + if (ok == 0) { + TEST_info("%s SSL_set_block_mode() failed", OPENSSL_FUNC); + goto done; + } + + peer_addr = BIO_ADDR_new(); + if (!TEST_ptr(peer_addr)) { + TEST_info("%s BIO_ADDR_new() failed", OPENSSL_FUNC); + goto done; + } + ok = BIO_ADDR_rawmake(peer_addr, AF_INET, &ina, sizeof(ina), htons(8040)); + if (ok == 0) { + TEST_info("%s BIO_ADDR_rawmake() failed", OPENSSL_FUNC); + goto done; + } + ok = SSL_set1_initial_peer_addr(c_ssl, peer_addr); + if (ok == 0) { + TEST_info("%s SSL_set1_initial_peer_addr() failed", OPENSSL_FUNC); + goto done; + } + +done: + BIO_ADDR_free(peer_addr); + + return ok; +} + +int create_quic_conn_objects(SSL_CTX *c_sctx, SSL_CTX *s_sctx, SSL **c_ssl_p, SSL **s_ssl_p) +{ + BIO *c_bio = NULL, *s_bio = NULL; + SSL *c_ssl = NULL, *s_ssl = NULL; + int ok; + + ok = create_dgram_pair(&c_bio, &s_bio); + if (ok == 0) + goto done; + + c_ssl = SSL_new(c_sctx); + if (!TEST_ptr(c_ssl)) { + TEST_info("%s SSL_new(c_sctx) failed", OPENSSL_FUNC); + ok = 0; + goto done; + } + + ok = init_client(c_ssl); + if (ok == 0) + goto done; + + s_ssl = SSL_new_listener(s_sctx, 0); + if (!TEST_ptr(s_ssl)) { + TEST_info("%s SSL_new_listener() failed", OPENSSL_FUNC); + ok = 0; + goto done; + } + + SSL_set_bio(c_ssl, c_bio, c_bio); + SSL_set_bio(s_ssl, s_bio, s_bio); + c_bio = NULL; + s_bio = NULL; + + ok = SSL_set_blocking_mode(s_ssl, 0); + if (ok == 0) { + TEST_info("%s SSL_set_blocking_mode() failed", OPENSSL_FUNC); + ok = 0; + goto done; + } + + *c_ssl_p = c_ssl; + c_ssl = NULL; + *s_ssl_p = s_ssl; + s_ssl = NULL; + +done: + BIO_free(c_bio); + BIO_free(s_bio); + SSL_free(c_ssl); + SSL_free(s_ssl); + + return ok; +} + +SSL *create_quic_client(SSL_CTX *c_sctx, BIO *c_bio) +{ + SSL *c_ssl; + + if (!TEST_ptr(c_bio)) + return NULL; + + c_ssl = SSL_new(c_sctx); + if (!TEST_ptr(c_ssl)) { + TEST_info("%s SSL_new(c_sctx) failed", OPENSSL_FUNC); + return NULL; + } + + if (BIO_up_ref(c_bio) == 0) { + TEST_info("%s BIO_up_ref() failed)", OPENSSL_FUNC); + goto error; + } + SSL_set_bio(c_ssl, c_bio, c_bio); + + if (init_client(c_ssl) == 0) + goto error; + + if (SSL_set_blocking_mode(c_ssl, 0) == 0) { + TEST_info("%s SSL_set_blocking_mode() failed", OPENSSL_FUNC); + goto error; + } + + return c_ssl; + +error: + SSL_free(c_ssl); + + return NULL; +} diff --git a/test/helpers/quictestlib.h b/test/helpers/quictestlib.h index 63c77f90b78be..c03bfac78fec9 100644 --- a/test/helpers/quictestlib.h +++ b/test/helpers/quictestlib.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -289,3 +289,7 @@ const BIO_METHOD *bio_f_pkt_split_dgram_filter(void); /* Free the BIO filter method object */ void bio_f_pkt_split_dgram_filter_free(void); + +int create_quic_ctx_pair(OSSL_LIB_CTX *libctx, SSL_CTX **c_sctx_p, SSL_CTX **s_sctx_p, const char *certfile, const char *keyfile); +int create_quic_conn_objects(SSL_CTX *c_sctx, SSL_CTX *s_ctx, SSL **c_ssl_p, SSL **s_ssl_p); +SSL *create_quic_client(SSL_CTX *c_sctx, BIO *c_bio); diff --git a/test/helpers/ssltestlib.c b/test/helpers/ssltestlib.c index 0f9b83865d864..27c113383c64a 100644 --- a/test/helpers/ssltestlib.c +++ b/test/helpers/ssltestlib.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -43,11 +43,13 @@ static int tls_dump_puts(BIO *bp, const char *str); #define BIO_TYPE_MEMPACKET_TEST 0x81 #define BIO_TYPE_ALWAYS_RETRY 0x82 #define BIO_TYPE_MAYBE_RETRY (0x83 | BIO_TYPE_FILTER) +#define BIO_TYPE_NO_RETRY_ZERO (0x84 | BIO_TYPE_FILTER) static BIO_METHOD *method_tls_dump = NULL; static BIO_METHOD *meth_mem = NULL; static BIO_METHOD *meth_always_retry = NULL; static BIO_METHOD *meth_maybe_retry = NULL; +static BIO_METHOD *meth_no_retry_zero = NULL; static int retry_err = -1; /* Note: Not thread safe! */ @@ -856,6 +858,10 @@ static int maybe_retry_new(BIO *bi); static int maybe_retry_free(BIO *a); static int maybe_retry_write(BIO *b, const char *in, int inl); static long maybe_retry_ctrl(BIO *b, int cmd, long num, void *ptr); +static int no_retry_zero_new(BIO *bi); +static int no_retry_zero_free(BIO *a); +static int no_retry_zero_write(BIO *b, const char *in, int inl); +static long no_retry_zero_ctrl(BIO *b, int cmd, long num, void *ptr); const BIO_METHOD *bio_s_maybe_retry(void) { @@ -942,6 +948,61 @@ static long maybe_retry_ctrl(BIO *bio, int cmd, long num, void *ptr) } } +const BIO_METHOD *bio_s_no_retry_zero(void) +{ + if (meth_no_retry_zero == NULL) { + if (!TEST_ptr(meth_no_retry_zero = BIO_meth_new(BIO_TYPE_NO_RETRY_ZERO, + "No Retry Zero")) + || !TEST_true(BIO_meth_set_write(meth_no_retry_zero, + no_retry_zero_write)) + || !TEST_true(BIO_meth_set_ctrl(meth_no_retry_zero, + no_retry_zero_ctrl)) + || !TEST_true(BIO_meth_set_create(meth_no_retry_zero, + no_retry_zero_new)) + || !TEST_true(BIO_meth_set_destroy(meth_no_retry_zero, + no_retry_zero_free))) + return NULL; + } + return meth_no_retry_zero; +} + +void bio_s_no_retry_zero_free(void) +{ + BIO_meth_free(meth_no_retry_zero); +} + +static int no_retry_zero_new(BIO *bio) +{ + BIO_set_init(bio, 1); + return 1; +} + +static int no_retry_zero_free(BIO *bio) +{ + BIO_set_data(bio, NULL); + BIO_set_init(bio, 0); + return 1; +} + +static int no_retry_zero_write(BIO *bio, const char *in, int inl) +{ + BIO_clear_retry_flags(bio); + return 0; +} + +static long no_retry_zero_ctrl(BIO *bio, int cmd, long num, void *ptr) +{ + BIO *next = BIO_next(bio); + + switch (cmd) { + case BIO_CTRL_FLUSH: + return next == NULL ? 1 : BIO_ctrl(next, cmd, num, ptr); + + default: + return next == NULL ? 0 : BIO_ctrl(next, cmd, num, ptr); + } +} + int create_ssl_ctx_pair(OSSL_LIB_CTX *libctx, const SSL_METHOD *sm, const SSL_METHOD *cm, int min_proto_version, int max_proto_version, SSL_CTX **sctx, SSL_CTX **cctx, diff --git a/test/helpers/ssltestlib.h b/test/helpers/ssltestlib.h index 7db8fd3248c5b..86397f2b6fbd2 100644 --- a/test/helpers/ssltestlib.h +++ b/test/helpers/ssltestlib.h @@ -1,5 +1,5 @@ /* - * Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -59,6 +59,9 @@ void set_always_retry_err_val(int err); const BIO_METHOD *bio_s_maybe_retry(void); void bio_s_maybe_retry_free(void); +const BIO_METHOD *bio_s_no_retry_zero(void); +void bio_s_no_retry_zero_free(void); + /* Packet types - value 0 is reserved */ #define INJECT_PACKET 1 #define INJECT_PACKET_IGNORE_REC_SEQ 2 diff --git a/test/hpke_test.c b/test/hpke_test.c index c7b30012ad2b4..df3f4574a0f06 100644 --- a/test/hpke_test.c +++ b/test/hpke_test.c @@ -949,10 +949,9 @@ static int test_hpke_modes_suites(void) hpke_suite.kem_id = kem_id; if (hpke_mode == OSSL_HPKE_MODE_AUTH || hpke_mode == OSSL_HPKE_MODE_PSKAUTH) { - if (TEST_true(OSSL_HPKE_keygen(hpke_suite, authpub, &authpublen, + if (!TEST_true(OSSL_HPKE_keygen(hpke_suite, authpub, &authpublen, &authpriv, NULL, 0, - testctx, NULL)) - != 1) { + testctx, NULL))) { overallresult = 0; } authpubp = authpub; @@ -1195,7 +1194,7 @@ static int test_hpke_suite_strs(void) for (aeadind = 0; aeadind != OSSL_NELEM(aead_str_list); aeadind++) { BIO_snprintf(sstr, 128, "%s,%s,%s", kem_str_list[kemind], kdf_str_list[kdfind], aead_str_list[aeadind]); - if (TEST_true(OSSL_HPKE_str2suite(sstr, &stirred)) != 1) { + if (!TEST_true(OSSL_HPKE_str2suite(sstr, &stirred))) { if (verbose) TEST_note("Unexpected str2suite fail for :%s", bogus_suite_strs[sind]); @@ -1205,9 +1204,8 @@ static int test_hpke_suite_strs(void) } } for (sind = 0; sind != OSSL_NELEM(bogus_suite_strs); sind++) { - if (TEST_false(OSSL_HPKE_str2suite(bogus_suite_strs[sind], - &stirred)) - != 1) { + if (!TEST_false(OSSL_HPKE_str2suite(bogus_suite_strs[sind], + &stirred))) { if (verbose) TEST_note("OSSL_HPKE_str2suite didn't fail for bogus[%d]:%s", sind, bogus_suite_strs[sind]); @@ -1250,20 +1248,18 @@ static int test_hpke_grease(void) /* GREASEing */ /* check too short for public value */ g_pub_len = 10; - if (TEST_false(OSSL_HPKE_get_grease_value(NULL, &g_suite, + if (!TEST_false(OSSL_HPKE_get_grease_value(NULL, &g_suite, g_pub, &g_pub_len, g_cipher, g_cipher_len, - testctx, NULL)) - != 1) { + testctx, NULL))) { overallresult = 0; } /* reset to work */ g_pub_len = OSSL_HPKE_TSTSIZE; - if (TEST_true(OSSL_HPKE_get_grease_value(NULL, &g_suite, + if (!TEST_true(OSSL_HPKE_get_grease_value(NULL, &g_suite, g_pub, &g_pub_len, g_cipher, g_cipher_len, - testctx, NULL)) - != 1) { + testctx, NULL))) { overallresult = 0; } /* expansion */ diff --git a/test/http_test.c b/test/http_test.c index 76d0d4348587a..94c1171fb784e 100644 --- a/test/http_test.c +++ b/test/http_test.c @@ -287,8 +287,8 @@ static int test_http_keep_alive(char version, int keep_alive, int kept_alive) return res; } -static int test_http_url_ok(const char *url, int exp_ssl, const char *exp_host, - const char *exp_port, const char *exp_path) +static int test_http_url_frag_ok(const char *url, int exp_ssl, const char *exp_host, + const char *exp_port, const char *exp_path, const char *exp_frag) { char *user, *host, *port, *path, *query, *frag; int exp_num, num, ssl; @@ -305,8 +305,8 @@ static int test_http_url_ok(const char *url, int exp_ssl, const char *exp_host, && TEST_int_eq(ssl, exp_ssl); if (res && *user != '\0') res = TEST_str_eq(user, "user:pass"); - if (res && *frag != '\0') - res = TEST_str_eq(frag, "fr"); + if (res) + res = TEST_str_eq(frag, exp_frag); if (res && *query != '\0') res = TEST_str_eq(query, "q"); OPENSSL_free(user); @@ -318,6 +318,12 @@ static int test_http_url_ok(const char *url, int exp_ssl, const char *exp_host, return res; } +static int test_http_url_ok(const char *url, int exp_ssl, const char *exp_host, + const char *exp_port, const char *exp_path) +{ + return test_http_url_frag_ok(url, exp_ssl, exp_host, exp_port, exp_path, ""); +} + static int test_http_url_path_query_ok(const char *url, const char *exp_path_qu) { char *host, *path; @@ -349,6 +355,11 @@ static int test_http_url_dns(void) return test_http_url_ok("host:65535/path", 0, "host", "65535", "/path"); } +static int test_http_url_ip(void) +{ + return test_http_url_ok("1.2.3.4:5678//blahblablah", 0, "1.2.3.4", "5678", "//blahblablah"); +} + static int test_http_url_timestamp(void) { return test_http_url_ok("host/p/2017-01-03T00:00:00", 0, "host", "80", @@ -368,7 +379,9 @@ static int test_http_url_path_query(void) static int test_http_url_userinfo_query_fragment(void) { - return test_http_url_ok("user:pass@host/p?q#fr", 0, "host", "80", "/p"); + return test_http_url_frag_ok("user:pass@host/p?q#fr", 0, "host", "80", "/p", "fr") + && test_http_url_frag_ok("host.example.org/some/path#://not-a-scheme/not.a.host:404", 0, + "host.example.org", "80", "/some/path", "://not-a-scheme/not.a.host:404"); } static int test_http_url_at_sign_outside_authority(void) @@ -573,7 +586,7 @@ static int test_http_resp_hdr_limit(size_t limit) int res = 0; OSSL_HTTP_REQ_CTX *rctx = NULL; - if (TEST_ptr(wbio) == 0 || TEST_ptr(rbio) == 0) + if (!TEST_ptr(wbio) || !TEST_ptr(rbio)) goto err; mock_args.txt = text1; @@ -585,7 +598,7 @@ static int test_http_resp_hdr_limit(size_t limit) BIO_set_callback_arg(wbio, (char *)&mock_args); rctx = OSSL_HTTP_REQ_CTX_new(wbio, rbio, 8192); - if (TEST_ptr(rctx) == 0) + if (!TEST_ptr(rctx)) goto err; if (!TEST_true(OSSL_HTTP_REQ_CTX_set_request_line(rctx, 0 /* GET */, @@ -652,6 +665,7 @@ int setup_tests(void) return 0; ADD_TEST(test_http_url_dns); + ADD_TEST(test_http_url_ip); ADD_TEST(test_http_url_timestamp); ADD_TEST(test_http_url_path_query); ADD_TEST(test_http_url_userinfo_query_fragment); diff --git a/test/list_test.c b/test/list_test.c index 9deb57c4b91a9..4170df92cd39c 100644 --- a/test/list_test.c +++ b/test/list_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -175,9 +175,55 @@ static int test_insert(void) return 1; } +static int test_join(void) +{ + OSSL_LIST(int) + l_h, l_t; + INTL elem_h[20]; + INTL elem_t[20]; + int i; + + ossl_list_int_init(&l_h); + ossl_list_int_init(&l_t); + ossl_list_int_join(&l_h, &l_t); + if (!TEST_size_t_eq(ossl_list_int_num(&l_t), 0)) + return 0; + + for (i = 0; i < (int)OSSL_NELEM(elem_h); i++) { + ossl_list_int_init_elem(&elem_h[i]); + elem_h[i].n = i; + ossl_list_int_insert_head(&l_h, &elem_h[i]); + } + + for (i = 0; i < (int)OSSL_NELEM(elem_t); i++) { + ossl_list_int_init_elem(&elem_t[i]); + elem_t[i].n = i + 10; + ossl_list_int_insert_head(&l_t, &elem_t[i]); + } + + ossl_list_int_join(NULL, NULL); + + ossl_list_int_join(NULL, &l_t); + if (!TEST_size_t_eq(ossl_list_int_num(&l_t), OSSL_NELEM(elem_t))) + return 0; + + ossl_list_int_join(&l_h, NULL); + if (!TEST_size_t_eq(ossl_list_int_num(&l_h), OSSL_NELEM(elem_h))) + return 0; + + ossl_list_int_join(&l_h, &l_t); + if (!TEST_size_t_eq(ossl_list_int_num(&l_h), OSSL_NELEM(elem_h) + OSSL_NELEM(elem_t))) + return 0; + + if (!TEST_true(ossl_list_int_is_empty(&l_t))) + return 0; + + return 1; +} int setup_tests(void) { ADD_TEST(test_fizzbuzz); ADD_TEST(test_insert); + ADD_TEST(test_join); return 1; } diff --git a/test/p_test.c b/test/p_test.c index 1e38bee717b68..aca1707b05cb0 100644 --- a/test/p_test.c +++ b/test/p_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -43,7 +43,6 @@ typedef struct p_test_ctx { OSSL_LIB_CTX *libctx; } P_TEST_CTX; -static OSSL_FUNC_core_gettable_params_fn *c_gettable_params = NULL; static OSSL_FUNC_core_get_params_fn *c_get_params = NULL; static OSSL_FUNC_core_new_error_fn *c_new_error; static OSSL_FUNC_core_set_error_debug_fn *c_set_error_debug; @@ -258,9 +257,6 @@ int OSSL_provider_init(const OSSL_CORE_HANDLE *handle, for (; in->function_id != 0; in++) { switch (in->function_id) { - case OSSL_FUNC_CORE_GETTABLE_PARAMS: - c_gettable_params = OSSL_FUNC_core_gettable_params(in); - break; case OSSL_FUNC_CORE_GET_PARAMS: c_get_params = OSSL_FUNC_core_get_params(in); break; diff --git a/test/pairwise_fail_test.c b/test/pairwise_fail_test.c index 3173225a0c852..628f123cb2711 100644 --- a/test/pairwise_fail_test.c +++ b/test/pairwise_fail_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2023-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2023-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -99,8 +99,6 @@ static int test_keygen_pairwise_failure(void) if (!TEST_ptr_null(pkey = EVP_PKEY_Q_keygen(libctx, NULL, "RSA", (size_t)2048))) goto err; } else if (strncmp(pairwise_name, "ec", 2) == 0) { - if (strcmp(pairwise_name, "eckat") == 0) - type = OSSL_SELF_TEST_TYPE_PCT_KAT; if (!TEST_true(setup_selftest_pairwise_failure(type))) goto err; if (!TEST_ptr_null(pkey = EVP_PKEY_Q_keygen(libctx, NULL, "EC", "P-256"))) diff --git a/test/pkcs12_api_test.c b/test/pkcs12_api_test.c index 147d65bd665ab..b98343da86af3 100644 --- a/test/pkcs12_api_test.c +++ b/test/pkcs12_api_test.c @@ -175,7 +175,7 @@ static int pkcs12_create_ex2_test(int test) 0, 0, 0, testctx, NULL, NULL, NULL); - if (TEST_ptr(ptr)) + if (!TEST_ptr_null(ptr)) goto err; /* Can't proceed without a valid cert at least */ @@ -201,7 +201,7 @@ static int pkcs12_create_ex2_test(int test) testctx, NULL, pkcs12_create_cb, (void *)&cb_ret); /* PKCS12 not created */ - if (TEST_ptr(ptr)) + if (!TEST_ptr_null(ptr)) goto err; } else if (test == 2) { /* Specified call back called - return failure */ diff --git a/test/pkcs7_test.c b/test/pkcs7_test.c index ac4bb84bbe366..8d9c111e58bbc 100644 --- a/test/pkcs7_test.c +++ b/test/pkcs7_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2021 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 @@ -15,6 +15,30 @@ #include "internal/nelem.h" #include "testutil.h" +static int pkcs7_issuer_and_serial_negative_idx_test(void) +{ + PKCS7 *p7 = NULL; + PKCS7_RECIP_INFO *ri = NULL; + int ret = 0; + + if (!TEST_ptr(p7 = PKCS7_new()) + || !TEST_true(PKCS7_set_type(p7, NID_pkcs7_signedAndEnveloped)) + || !TEST_ptr(ri = PKCS7_RECIP_INFO_new()) + || !TEST_true(PKCS7_add_recipient_info(p7, ri))) + goto end; + ri = NULL; + + if (!TEST_ptr(PKCS7_get_issuer_and_serial(p7, 0)) + || !TEST_ptr_null(PKCS7_get_issuer_and_serial(p7, -1))) + goto end; + + ret = 1; +end: + PKCS7_RECIP_INFO_free(ri); + PKCS7_free(p7); + return ret; +} + #ifndef OPENSSL_NO_EC static const unsigned char cert_der[] = { 0x30, 0x82, 0x01, 0x51, 0x30, 0x81, 0xf7, 0xa0, 0x03, 0x02, 0x01, 0x02, @@ -387,11 +411,101 @@ static int pkcs7_inner_content_verify_test(void) } #endif /* OPENSSL_NO_EC */ +static int pkcs7_stream_enveloped_no_content_test(void) +{ + int ret = 0; + PKCS7 *p7 = NULL; + BIO *sink = NULL; + BIO *bio = NULL; + + const unsigned char data_enveloped_no_body[] = { 0x30, 0x0b, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03 }; + const unsigned char *ptr_env_no_body = data_enveloped_no_body; + + ret = TEST_ptr(p7 = d2i_PKCS7(NULL, &ptr_env_no_body, + sizeof(data_enveloped_no_body))) + && TEST_ptr(sink = BIO_new(BIO_s_null())) + && TEST_ptr_null(bio = BIO_new_PKCS7(sink, p7)) + && TEST_int_eq(ERR_GET_REASON(ERR_peek_last_error()), + PKCS7_R_NO_CONTENT); + + BIO_free(bio); + BIO_free(sink); + PKCS7_free(p7); + return ret; +} + +static int pkcs7_stream_enveloped_signed_no_content_test(void) +{ + int ret = 0; + PKCS7 *p7 = NULL; + BIO *sink = NULL; + BIO *bio = NULL; + + const unsigned char data_enveloped_signed_no_body[] = { 0x30, 0x0b, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x04 }; + const unsigned char *ptr_env_signed_no_body = data_enveloped_signed_no_body; + + ret = TEST_ptr(p7 = d2i_PKCS7(NULL, &ptr_env_signed_no_body, + sizeof(data_enveloped_signed_no_body))) + && TEST_ptr(sink = BIO_new(BIO_s_null())) + && TEST_ptr_null(bio = BIO_new_PKCS7(sink, p7)) + && TEST_int_eq(ERR_GET_REASON(ERR_peek_last_error()), + PKCS7_R_NO_CONTENT); + + BIO_free(bio); + BIO_free(sink); + PKCS7_free(p7); + return ret; +} + +static int pkcs7_stream_non_data_test(void) +{ + int ret = 0; + PKCS7 *p7 = NULL; + BIO *sink = NULL; + BIO *bio = NULL; + + /* clang-format off */ + static const unsigned char malformed_der[] = { + 0x30, 0x32, /* SEQUENCE, 50 bytes */ + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, /* pkcs7-signedData */ + 0xa0, 0x25, /* [0] EXPLICIT, 37 bytes */ + 0x30, 0x23, /* SEQUENCE PKCS7_SIGNED, 35 bytes */ + 0x02, 0x01, 0x01, /* INTEGER version=1 */ + 0x31, 0x00, /* SET{} md_algs */ + 0x30, 0x1a, /* SEQUENCE inner PKCS7 (contents), 26 bytes */ + 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x01, 0x04, /* id-ct-TSTInfo */ + 0xa0, 0x0b, /* [0] EXPLICIT, 11 bytes (makes d.other non-NULL) */ + 0x30, 0x09, /* SEQUENCE */ + 0x02, 0x01, 0x01, /* INTEGER 1 */ + 0x04, 0x04, 0xde, 0xad, 0xbe, 0xef, /* OCTET STRING */ + 0x31, 0x00, /* SET{} signer_info */ + }; + /* clang-format on */ + + const unsigned char *ptr_malformed_der = malformed_der; + + ret = TEST_ptr(p7 = d2i_PKCS7(NULL, &ptr_malformed_der, sizeof(malformed_der))) + && TEST_ptr(sink = BIO_new(BIO_s_null())) + && TEST_ptr_null(bio = BIO_new_PKCS7(sink, p7)) + && TEST_int_eq(ERR_GET_REASON(ERR_peek_last_error()), PKCS7_R_UNSUPPORTED_CONTENT_TYPE); + + BIO_free(bio); + BIO_free(sink); + PKCS7_free(p7); + return ret; +} + int setup_tests(void) { + ADD_TEST(pkcs7_issuer_and_serial_negative_idx_test); #ifndef OPENSSL_NO_EC ADD_TEST(pkcs7_verify_test); ADD_TEST(pkcs7_inner_content_verify_test); #endif /* OPENSSL_NO_EC */ + ADD_TEST(pkcs7_stream_enveloped_no_content_test); + ADD_TEST(pkcs7_stream_enveloped_signed_no_content_test); + ADD_TEST(pkcs7_stream_non_data_test); return 1; } diff --git a/test/punycode_test.c b/test/punycode_test.c index 37f6056903c67..7911b9d6d8578 100644 --- a/test/punycode_test.c +++ b/test/punycode_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -188,7 +188,7 @@ static int test_puny_overrun(void) unsigned int bsize = OSSL_NELEM(buf) - 1; if (!TEST_false(ossl_punycode_decode(in, strlen(in), buf, &bsize))) { - if (TEST_mem_eq(buf, bsize * sizeof(*buf), out, sizeof(out))) + if (!TEST_mem_ne(buf, bsize * sizeof(*buf), out, sizeof(out))) TEST_error("CRITICAL: buffer overrun detected!"); return 0; } diff --git a/test/quic_ackm_test.c b/test/quic_ackm_test.c index 9b8e3aafb7fa5..a23ea28a6b3f8 100644 --- a/test/quic_ackm_test.c +++ b/test/quic_ackm_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -11,6 +11,7 @@ #include #include "internal/quic_ackm.h" #include "internal/quic_cc.h" +#include "internal/quic_vlint.h" static OSSL_TIME fake_time = { 0 }; @@ -147,13 +148,26 @@ struct tx_ack_test_case { const OSSL_QUIC_ACK_RANGE *ack_ranges; size_t num_ack_ranges; const char *expect_ack; /* 1=ack, 2=lost, 4=discarded */ + int expect_reject; /* if nonzero the ACK must be rejected (returns 0) */ }; #define DEFINE_TX_ACK_CASE(n, pntable) \ static const struct tx_ack_test_case tx_ack_case_##n = { \ (pntable), OSSL_NELEM(pntable), \ tx_ack_range_##n, OSSL_NELEM(tx_ack_range_##n), \ - tx_ack_expect_##n \ + tx_ack_expect_##n, 0 \ + } + +/* + * As DEFINE_TX_ACK_CASE, but the ACK acknowledges a packet number that was + * never sent and so must be rejected by ossl_ackm_on_rx_ack_frame() + * (RFC 9000 s. 13.1). + */ +#define DEFINE_TX_ACK_CASE_REJECT(n, pntable) \ + static const struct tx_ack_test_case tx_ack_case_##n = { \ + (pntable), OSSL_NELEM(pntable), \ + tx_ack_range_##n, OSSL_NELEM(tx_ack_range_##n), \ + tx_ack_expect_##n, 1 \ } /* One range, partial coverage of space */ @@ -207,32 +221,32 @@ static const char tx_ack_expect_5[] = { }; DEFINE_TX_ACK_CASE(5, linear_20); -/* One range, covering entire space */ +/* One range covering the whole space (0..19, highest sent PN is 19): all acked */ static const OSSL_QUIC_ACK_RANGE tx_ack_range_6[] = { - { 0, 20 }, + { 0, 19 }, }; static const char tx_ack_expect_6[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; DEFINE_TX_ACK_CASE(6, linear_20); -/* One range, covering more space than exists */ +/* One range above the highest sent PN (30 > 19): ACK rejected */ static const OSSL_QUIC_ACK_RANGE tx_ack_range_7[] = { { 0, 30 }, }; static const char tx_ack_expect_7[] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -DEFINE_TX_ACK_CASE(7, linear_20); +DEFINE_TX_ACK_CASE_REJECT(7, linear_20); -/* One range, covering nothing (too high) */ +/* One range entirely above the sent PNs (21..30): ACK rejected */ static const OSSL_QUIC_ACK_RANGE tx_ack_range_8[] = { { 21, 30 }, }; static const char tx_ack_expect_8[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -DEFINE_TX_ACK_CASE(8, linear_20); +DEFINE_TX_ACK_CASE_REJECT(8, linear_20); /* One range, covering nothing (too low) */ static const OSSL_QUIC_ACK_RANGE tx_ack_range_9[] = { @@ -289,6 +303,20 @@ static const char tx_ack_expect_13[] = { }; DEFINE_TX_ACK_CASE(13, high_linear_20); +/* + * Largest range claims the maximum PN (2**62 - 1, never sent) plus a second + * range over real packets so loss detection would otherwise run. ACK rejected; + * otherwise largest_acked_pkt pins at the maximum and every in-flight packet is + * declared lost. + */ +static const OSSL_QUIC_ACK_RANGE tx_ack_range_14[] = { + { OSSL_QUIC_VLINT_MAX, OSSL_QUIC_VLINT_MAX }, { 15, 19 } +}; +static const char tx_ack_expect_14[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +DEFINE_TX_ACK_CASE_REJECT(14, linear_20); + static const struct tx_ack_test_case *const tx_ack_cases[] = { &tx_ack_case_1, &tx_ack_case_2, @@ -303,6 +331,7 @@ static const struct tx_ack_test_case *const tx_ack_cases[] = { &tx_ack_case_11, &tx_ack_case_12, &tx_ack_case_13, + &tx_ack_case_14, }; enum { @@ -402,6 +431,25 @@ static int test_tx_ack_case_actual(int tidx, int space, int mode) /* Try acknowledging. */ ack.ack_ranges = (OSSL_QUIC_ACK_RANGE *)c->ack_ranges; ack.num_ack_ranges = c->num_ack_ranges; + + if (c->expect_reject) { + /* ACK of an unsent PN: rejected without touching loss detection. */ + if (!TEST_int_eq(ossl_ackm_on_rx_ack_frame(h.ackm, &ack, space, + fake_time), + 0)) + goto err; + + for (i = 0; i < c->pn_table_len; ++i) { + if (!TEST_int_eq(h.pkts[i].acked, 0) + || !TEST_int_eq(h.pkts[i].lost, 0) + || !TEST_int_eq(h.pkts[i].discarded, 0)) + goto err; + } + + testresult = 1; + goto err; + } + if (!TEST_int_eq(ossl_ackm_on_rx_ack_frame(h.ackm, &ack, space, fake_time), 1)) goto err; @@ -577,7 +625,7 @@ static int test_tx_ack_time_script(int tidx) ack.num_ack_ranges = 1; ack_range.start = s->pn; - ack_range.end = s->pn + s->num_pn; + ack_range.end = s->pn + s->num_pn - 1; fake_time = ossl_time_add(fake_time, ossl_ticks2time(s->time_advance)); diff --git a/test/quic_multistream_test.c b/test/quic_multistream_test.c index 169577a64595f..93a7bd2ff2ec7 100644 --- a/test/quic_multistream_test.c +++ b/test/quic_multistream_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2023-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2023-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -4034,9 +4034,14 @@ static const struct script_op script_49[] = { OP_SET_INJECT_WORD(4, 0) OP_S_WRITE(a, "Strawberry", 10) - OP_C_READ_EXPECT(DEFAULT, "Strawberry", 10) + /* + * The injected ACK acknowledges a packet number we have not sent, which the + * peer is expected to treat as a PROTOCOL_VIOLATION, so the connection is + * closed rather than the stream data being delivered. + */ + OP_C_EXPECT_CONN_CLOSE_INFO(OSSL_QUIC_ERR_PROTOCOL_VIOLATION, 0, 0) - OP_END + OP_END }; /* 50. Fault injection - ACK - duplicate PN */ diff --git a/test/quic_tserver_test.c b/test/quic_tserver_test.c index ae576441e7335..559a7d954fa8b 100644 --- a/test/quic_tserver_test.c +++ b/test/quic_tserver_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -331,16 +331,38 @@ static int do_test(int use_thread_assist, int use_fake_time, int use_inject) CRYPTO_THREAD_unlock(fake_time_lock); ++idle_units_done; - ossl_quic_conn_force_assist_thread_wake(c_ssl); /* - * If the event timeout has expired then give the assistance - * thread a chance to catch up + * The assist thread alone keeps the idle connection alive. It + * waits on real time internally, so advancing fake time can + * outrun it. Rather than race it, wait until it has caught up: + * the event timeout is computed against fake time, so once the + * next deadline is back in the future all events due up to now + * - including any keepalive - have been serviced. */ - if (!TEST_true(SSL_get_event_timeout(c_ssl, &tv, &isinf))) - goto err; - if (!isinf && ossl_time_compare(ossl_time_zero(), ossl_time_from_timeval(tv)) >= 0) - OSSL_sleep(100); /* Ensure CPU scheduling for test purposes */ + for (;;) { + ossl_quic_conn_force_assist_thread_wake(c_ssl); + + if (!TEST_true(SSL_get_event_timeout(c_ssl, &tv, &isinf))) + goto err; + + if (isinf + || ossl_time_compare(ossl_time_from_timeval(tv), + ossl_time_zero()) + > 0) + break; + + if (ossl_time_compare(ossl_time_subtract(real_now(NULL), + start_time), + ossl_ms2time(limit_ms)) + >= 0) { + TEST_error("timeout waiting for assist thread to send " + "keepalive during idle test"); + goto err; + } + + OSSL_sleep(1); /* Yield so the assist thread can run. */ + } } else { c_done_idle_test = 1; } diff --git a/test/quicapitest.c b/test/quicapitest.c index d40413898a6ff..fd950772c878a 100644 --- a/test/quicapitest.c +++ b/test/quicapitest.c @@ -21,6 +21,8 @@ #include "../ssl/ssl_local.h" #include "../ssl/quic/quic_channel_local.h" #include "internal/quic_error.h" +#include "internal/quic_ssl.h" +#include "internal/quic_port.h" static OSSL_LIB_CTX *libctx = NULL; static OSSL_PROVIDER *defctxnull = NULL; @@ -3088,6 +3090,129 @@ static int test_quic_resize_txe(void) return ret; } +#define PENDING_LIMIT 5 +#define HANDSHAKE_STEPS 10 +static int test_pending_limit(void) +{ + SSL_CTX *cctx = NULL, *sctx = NULL; + SSL *clientssl = NULL, *serverssl_listener = NULL, *serverssl = NULL; + SSL *extra_clients[PENDING_LIMIT * 2] = { NULL }; + BIO *bio; + unsigned int i, handshake_step; + int done; + int testresult = 0; + int ok; + QUIC_PORT *port; + size_t pending_connections = 0; + + if (!TEST_true(create_quic_ctx_pair(libctx, &cctx, &sctx, cert, privkey))) + return 0; + + if (!TEST_true(create_quic_conn_objects(cctx, sctx, &clientssl, &serverssl_listener))) + goto end; + + ok = SSL_set_generic_value_uint(serverssl_listener, + SSL_VALUE_QUIC_MAX_PENDING_CONNS, PENDING_LIMIT); + if (!TEST_true(ok)) { + TEST_info("%s call to SSL_set_generic_request_uint" + "(SSL_VALUE_QUIC_MAX_PENDING_CONNS failed", + OPENSSL_FUNC); + goto end; + } + + if (!TEST_true(SSL_listen(serverssl_listener))) { + TEST_info("%s SSL_listen() failed", OPENSSL_FUNC); + goto end; + } + + port = ossl_quic_listener_get_port(serverssl_listener); + if (!TEST_ptr(port)) + goto end; + + bio = SSL_get_rbio(clientssl); + if (!TEST_ptr(bio)) + goto end; + + if (!TEST_ptr_eq(bio, SSL_get_wbio(clientssl))) + goto end; + + for (i = 0; i < OSSL_NELEM(extra_clients); i++) { + extra_clients[i] = create_quic_client(cctx, bio); + if (!TEST_ptr(extra_clients[i])) + goto end; + } + + for (i = 0; i < PENDING_LIMIT; i++) { + handshake_step = 0; + done = 0; + while (!done && handshake_step++ < HANDSHAKE_STEPS) { + /* + * connections are never accepted by the server. The SSL_connect() + * for non-blocking client returns -1 to keep connect retrying + */ + if (!TEST_int_lt(SSL_connect(extra_clients[i]), 0)) + goto end; + SSL_handle_events(serverssl_listener); + pending_connections = ossl_quic_port_get_num_incoming_channels(port); + done = (pending_connections == (i + 1)); + } + } + + if (!TEST_size_t_eq(pending_connections, PENDING_LIMIT)) + goto end; + + /* + * initiate yet another connection. The connection must not be inserted + * to pending queue. The pending_connections must be 5. + */ + for (i = PENDING_LIMIT; i < OSSL_NELEM(extra_clients); i++) { + handshake_step = 0; + done = 0; + while (!done && handshake_step++ < HANDSHAKE_STEPS) { + /* + * connections are never accepted by the server. The SSL_connect() + * for non-blocking client returns -1 to keep connect retrying + */ + if (!TEST_int_le(SSL_connect(extra_clients[i]), 0)) + goto end; + SSL_handle_events(serverssl_listener); + pending_connections = ossl_quic_port_get_num_incoming_channels(port); + done = (pending_connections == (i + 1)); + } + } + pending_connections = ossl_quic_port_get_num_incoming_channels(port); + if (!TEST_size_t_eq(pending_connections, PENDING_LIMIT)) + goto end; + + /* + * accept one connection and check the length of the queue dropped to 4. + */ + done = 0; + handshake_step = 0; + while (!done && handshake_step++ < HANDSHAKE_STEPS) { + if (!TEST_int_lt(SSL_connect(extra_clients[0]), 0)) + goto end; + SSL_handle_events(serverssl_listener); + serverssl = SSL_accept_connection(serverssl_listener, 0); + done = (serverssl != NULL); + } + pending_connections = ossl_quic_port_get_num_incoming_channels(port); + if (!TEST_size_t_eq(pending_connections, PENDING_LIMIT - 1)) + goto end; + + testresult = 1; +end: + for (i = 0; i < OSSL_NELEM(extra_clients); i++) + SSL_free(extra_clients[i]); + SSL_free(clientssl); + SSL_free(serverssl); + SSL_free(serverssl_listener); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + + return testresult; +} + /***********************************************************************************/ OPT_TEST_DECLARE_USAGE("provider config certsdir datadir\n") @@ -3192,6 +3317,7 @@ int setup_tests(void) ADD_TEST(test_ssl_set_verify); ADD_TEST(test_client_hello_retry); ADD_TEST(test_quic_resize_txe); + ADD_TEST(test_pending_limit); return 1; err: diff --git a/test/radix/quic_bindings.c b/test/radix/quic_bindings.c index eb9423ef314e2..ab39a89412e6c 100644 --- a/test/radix/quic_bindings.c +++ b/test/radix/quic_bindings.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -403,6 +403,22 @@ static int RADIX_PROCESS_join_all_threads(RADIX_PROCESS *rp, int *testresult) return ok; } +/* + * Free every non-listener object's SSL before cleanup_one() frees any listener. + * + * A connection's assist thread reads from its network BIO, and for a dgram BIO + * pair (see hf_link_dgram_pair) that BIO belongs to the linked listener. Freeing + * the connection joins its assist thread (see ossl_quic_free), so doing so first + * ensures no assist thread is still reading when the listener BIOs are freed. + */ +static void cleanup_nonlistener(RADIX_OBJ *obj) +{ + if (obj->ssl != NULL && !SSL_is_listener(obj->ssl)) { + SSL_free(obj->ssl); + obj->ssl = NULL; + } +} + static void cleanup_one(RADIX_OBJ *obj) { obj->registered = 0; @@ -423,6 +439,7 @@ static void RADIX_PROCESS_cleanup(RADIX_PROCESS *rp) sk_RADIX_THREAD_free(rp->threads); rp->threads = NULL; + lh_RADIX_OBJ_doall(rp->objs, cleanup_nonlistener); lh_RADIX_OBJ_doall(rp->objs, cleanup_one); lh_RADIX_OBJ_free(rp->objs); rp->objs = NULL; diff --git a/test/radix/quic_ops.c b/test/radix/quic_ops.c index 4475f91803232..5e0642ec56f33 100644 --- a/test/radix/quic_ops.c +++ b/test/radix/quic_ops.c @@ -1,5 +1,5 @@ /* - * Copyright 2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2025-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 @@ -142,45 +142,6 @@ static int ssl_attach_bio_dgram(SSL *ssl, return 1; } -/* - * Test to make sure that SSL_accept_connection returns the same ssl object - * that is used in the various TLS callbacks - * - * Unlike TCP, QUIC processes new connections independently from their - * acceptance, and so we need to pre-allocate tls objects to return during - * connection acceptance via the user_ssl. This is just a quic test to validate - * that: - * 1) The new callback to inform the user of a new pending ssl acceptance works - * properly - * 2) That the object returned from SSL_accept_connection matches the one passed - * to various callbacks - * - * It would be better as its own test, but currently the tserver used in the - * other quic_tests doesn't actually accept connections (it pre-creates them - * and fixes them up in place), so testing there is not feasible at the moment - * - * For details on this issue see: - * https://github.com/openssl/project/issues/918 - */ -static SSL *pending_ssl_obj = NULL; -static SSL *client_hello_ssl_obj = NULL; -static int check_pending_match = 0; -static int pending_cb_called = 0; -static int hello_cb_called = 0; -static int new_pending_cb(SSL_CTX *ctx, SSL *new_ssl, void *arg) -{ - pending_ssl_obj = new_ssl; - pending_cb_called = 1; - return 1; -} - -static int client_hello_cb(SSL *s, int *al, void *arg) -{ - client_hello_ssl_obj = s; - hello_cb_called = 1; - return 1; -} - DEF_FUNC(hf_new_ssl) { int ok = 0; @@ -215,9 +176,6 @@ DEF_FUNC(hf_new_ssl) goto err; } else if (is_server) { - SSL_CTX_set_new_pending_conn_cb(ctx, new_pending_cb, NULL); - SSL_CTX_set_client_hello_cb(ctx, client_hello_cb, NULL); - check_pending_match = 1; if (!TEST_ptr(ssl = SSL_new_listener(ctx, 0))) goto err; } else { @@ -351,23 +309,6 @@ DEF_FUNC(hf_accept_conn) goto err; } - if (check_pending_match) { - if (!pending_cb_called || !hello_cb_called) { - TEST_info("Callbacks not called, skipping user_ssl check\n"); - } else { - if (!TEST_ptr_eq(pending_ssl_obj, client_hello_ssl_obj)) { - SSL_free(conn); - goto err; - } - if (!TEST_ptr_eq(pending_ssl_obj, conn)) { - SSL_free(conn); - goto err; - } - } - pending_ssl_obj = client_hello_ssl_obj = NULL; - check_pending_match = 0; - pending_cb_called = hello_cb_called = 0; - } ok = 1; err: return ok; diff --git a/test/radix/quic_tests.c b/test/radix/quic_tests.c index d6f0a19077a2b..8501b46a7715b 100644 --- a/test/radix/quic_tests.c +++ b/test/radix/quic_tests.c @@ -7,6 +7,9 @@ * https://www.openssl.org/source/license.html */ +#include "internal/quic_reactor.h" +#include "../../ssl/rio/poll_builder.h" + #if defined(_AIX) /* * Some versions of AIX define macros for events and revents for use when @@ -242,6 +245,178 @@ DEF_SCRIPT(ssl_poll, } } +/* + * Test: poll_abort_blocking + * ------------------------- + * + * SSL_poll(), when it has to block, registers each item's QUIC connection + * for cross-thread notification one item at a time (poll_translate() in + * ssl/rio/poll_immediate.c). If an item turns out to already be ready right + * as it is being registered, translation is aborted so the readout loop can + * retry instead of actually blocking. This exercises that abort path and + * checks that: + * + * - SSL_poll() reports success rather than spuriously failing, and + * - any items already registered before the abort have their blocking + * section correctly left (i.e. no leak in the QUIC reactor's blocking + * waiter count). + * + * The race between an item being registered and becoming ready is normally + * vanishingly narrow, so we use ossl_quic_poll_translate_test_step_cb (test + * instrumentation only, see ssl/rio/poll_builder.h) to deterministically + * make the second item ready immediately before poll_translate() processes + * it, while the first item is still mid-registration. + */ +struct poll_abort_test_ctx { + SSL *peer_writer; /* write here to make target ready */ + SSL *target; + uint64_t target_events; + size_t trigger_idx; + int made_ready; /* set by poll_abort_test_step_cb() on success */ +}; + +static void poll_abort_test_step_cb(size_t idx, void *arg) +{ + struct poll_abort_test_ctx *ctx = arg; + uint64_t revents = 0; + int i; + + if (idx != ctx->trigger_idx) + return; + + if (SSL_write(ctx->peer_writer, "x", 1) != 1) + return; + + /* Force the data through synchronously so target is ready by the time we return. */ + for (i = 0; i < 1000; ++i) { + if (!ossl_quic_conn_poll_events(ctx->target, ctx->target_events, + /* do_tick = */ 1, &revents)) + return; + + if (revents != 0) { + ctx->made_ready = 1; + return; + } + + OSSL_sleep(1); + } +} + +DEF_FUNC(check_poll_abort_blocking) +{ + int ok = 0; + SSL *C, *C0, *Cb0, *Lb0; + QUIC_CHANNEL *ch0; + QUIC_REACTOR *rtor0; + SSL_POLL_ITEM items[2] = { 0 }; + size_t result_count = SIZE_MAX, waiters_before, waiters_after; + struct poll_abort_test_ctx ctx; + const struct timeval z_timeout = { 0 }; + + /* + * C0 and Cb0 are streams of two independent client connections, and so + * belong to two independent QUIC_REACTORs. The bug being tested for does + * not actually require this: it reproduces just as well if all items + * share one reactor. What needs two reactors is poll_abort_test_step_cb() + * below, which forces Cb0 ready by ticking its reactor directly, on this + * thread, while C0's blocking section is still open. Doing that on C0's + * own (shared) reactor would deadlock: ossl_quic_reactor_tick() would see + * a nonzero cur_blocking_waiters left over from C0 and call + * rtor_notify_other_threads(), which waits on a condvar for some *other* + * thread to clear the notifier signal - a thread that doesn't exist here. + * Using Cb0's own, still-untouched reactor keeps that tick a no-op. + */ + REQUIRE_SSL_4(C, C0, Cb0, Lb0); + + items[0].desc = SSL_as_poll_descriptor(C0); + items[0].events = SSL_POLL_EVENT_R; + items[1].desc = SSL_as_poll_descriptor(Cb0); + items[1].events = SSL_POLL_EVENT_R; + + /* Sanity check: nothing ready yet, so SSL_poll() will need to block. */ + if (!TEST_true(SSL_poll(items, OSSL_NELEM(items), sizeof(SSL_POLL_ITEM), + &z_timeout, 0, &result_count)) + || !TEST_size_t_eq(result_count, 0)) + goto err; + + if (!TEST_ptr(ch0 = ossl_quic_conn_get_channel(C))) + goto err; + rtor0 = ossl_quic_channel_get_reactor(ch0); + waiters_before = rtor0->cur_blocking_waiters; + + ctx.peer_writer = Lb0; + ctx.target = Cb0; + ctx.target_events = items[1].events; + ctx.trigger_idx = 1; + ctx.made_ready = 0; + + ossl_quic_poll_translate_test_step_cb_arg = &ctx; + ossl_quic_poll_translate_test_step_cb = poll_abort_test_step_cb; + + result_count = SIZE_MAX; + /* + * No timeout: if the abort_blocking case were instead to actually block, + * this call would hang forever rather than fail fast. + */ + ok = TEST_true(SSL_poll(items, OSSL_NELEM(items), sizeof(SSL_POLL_ITEM), + NULL, 0, &result_count)); + + ossl_quic_poll_translate_test_step_cb = NULL; + ossl_quic_poll_translate_test_step_cb_arg = NULL; + + if (!ok) + goto err; + + ok = 0; + if (!TEST_true(ctx.made_ready) + || !TEST_size_t_ge(result_count, 1) + || !TEST_true((items[1].revents & SSL_POLL_EVENT_R) != 0)) + goto err; + + /* The first item's blocking-section entry must have been balanced. */ + waiters_after = rtor0->cur_blocking_waiters; + if (!TEST_size_t_eq(waiters_after, waiters_before)) + goto err; + + ok = 1; +err: + ossl_quic_poll_translate_test_step_cb = NULL; + ossl_quic_poll_translate_test_step_cb_arg = NULL; + return ok; +} + +DEF_SCRIPT(poll_abort_blocking, + "test that SSL_poll() correctly handles an item becoming ready while blocking is being set up") +{ + OP_SIMPLE_PAIR_CONN_ND(); + + OP_NEW_STREAM(C, C0, 0); + OP_WRITE_B(C0, "probe0"); + + OP_ACCEPT_CONN_WAIT1_ND(L, La, 0); + OP_ACCEPT_STREAM_WAIT(La, La0, 0); + OP_READ_EXPECT_B(La0, "probe0"); + + /* A second, independent client connection to the same listener. */ + OP_NEW_SSL_C(Cb); + OP_SET_PEER_ADDR_FROM(Cb, L); + OP_CONNECT_WAIT(Cb); + OP_SET_DEFAULT_STREAM_MODE(Cb, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_NEW_STREAM(Cb, Cb0, 0); + OP_WRITE_B(Cb0, "probe1"); + + OP_ACCEPT_CONN_WAIT1_ND(L, Lb, 0); + OP_ACCEPT_STREAM_WAIT(Lb, Lb0, 0); + OP_READ_EXPECT_B(Lb0, "probe1"); + + OP_SELECT_SSL(0, C); + OP_SELECT_SSL(1, C0); + OP_SELECT_SSL(2, Cb0); + OP_SELECT_SSL(3, Lb0); + OP_FUNC(check_poll_abort_blocking); +} + DEF_FUNC(check_writeable) { int ok = 0; @@ -315,10 +490,17 @@ static int mutcbk_inject_frames(const QUIC_PKT_HDR *hdrin, /* * make injection callback a one shot event, * callback is invoked for every packet we - * want to modify only one packet here. + * want to modify only one packet here. Returning 0 tells the QTX the + * packet send itself failed (tearing down the connection), so once + * we're done mutating we must pass subsequent packets through + * unmodified instead. */ - if (mutctx->mutctx_done) - return 0; + if (mutctx->mutctx_done) { + *hdrout = (QUIC_PKT_HDR *)hdrin; + *iovecout = iovecin; + *numout = numin; + return 1; + } mutctx->mutctx_done = 1; @@ -455,9 +637,17 @@ DEF_FUNC(check_flood_stats) path_challenge_count = ossl_quic_channel_get_path_challenge_count(ch); path_response_count = ossl_quic_channel_get_path_response_count(ch); - if (TEST_uint64_t_ne(path_challenge_count, 16)) + /* + * The flood is delivered over a real socket and processed by the + * connection's assist thread asynchronously, so give it a chance to + * catch up rather than failing on the first observation. + */ + if (path_challenge_count < 16 || path_response_count < 1) + F_SPIN_AGAIN(); + + if (!TEST_uint64_t_eq(path_challenge_count, 16)) goto err; - if (TEST_uint64_t_ne(path_response_count, 1)) + if (!TEST_uint64_t_eq(path_response_count, 1)) goto err; ok = 1; @@ -476,6 +666,146 @@ DEF_SCRIPT(check_pc_flood, "check path challenge flood") OP_FUNC(check_flood_stats); } +/* + * Test to make sure that SSL_accept_connection returns the same ssl object + * that is used in the various TLS callbacks + * + * Unlike TCP, QUIC processes new connections independently from their + * acceptance, and so we need to pre-allocate tls objects to return during + * connection acceptance via the user_ssl. This is just a quic test to validate + * that: + * 1) The new callback to inform the user of a new pending ssl acceptance works + * properly + * 2) That the object returned from SSL_accept_connection matches the one passed + * to various callbacks + * + * It would be better as its own test, but currently the tserver used in the + * other quic_tests doesn't actually accept connections (it pre-creates them + * and fixes them up in place), so testing there is not feasible at the moment + * + * For details on this issue see: + * https://github.com/openssl/project/issues/918 + */ +static SSL *pending_ssl_obj = NULL; +static SSL *client_hello_ssl_obj = NULL; +static int check_pending_match = 0; +static int pending_cb_called = 0; +static int hello_cb_called = 0; + +static int new_pending_cb(SSL_CTX *ctx, SSL *new_ssl, void *arg) +{ + pending_ssl_obj = new_ssl; + pending_cb_called = 1; + return 1; +} + +static int client_hello_cb(SSL *s, int *al, void *arg) +{ + client_hello_ssl_obj = s; + hello_cb_called = 1; + return 1; +} + +DEF_FUNC(init_pending_test) +{ + pending_ssl_obj = NULL; + client_hello_ssl_obj = NULL; + check_pending_match = 0; + pending_cb_called = 0; + hello_cb_called = 0; + + return 1; +} + +DEF_FUNC(check_pending) +{ + int ok = 0; + SSL *conn; + + REQUIRE_SSL(conn); + + if (check_pending_match) { + if (!TEST_true(pending_cb_called)) + goto err; + + if (!TEST_true(hello_cb_called)) + goto err; + + if (!TEST_ptr_eq(pending_ssl_obj, client_hello_ssl_obj)) + goto err; + + if (!TEST_ptr_eq(pending_ssl_obj, conn)) + goto err; + + pending_ssl_obj = client_hello_ssl_obj = NULL; + check_pending_match = 0; + pending_cb_called = hello_cb_called = 0; + } + + ok = 1; +err: + return ok; +} + +DEF_FUNC(new_listener) +{ + int ok = 0; + SSL_CTX *ctx = NULL; + SSL *listener; + const char *name; + + F_POP(name); + + if (!TEST_ptr(ctx = SSL_CTX_new(OSSL_QUIC_server_method()))) + goto err; + +#if defined(OPENSSL_THREADS) + if (!TEST_true(SSL_CTX_set_domain_flags(ctx, + SSL_DOMAIN_FLAG_MULTI_THREAD + | SSL_DOMAIN_FLAG_BLOCKING))) + goto err; +#endif + + if (!TEST_true(ssl_ctx_configure(ctx, 1))) + goto err; + + SSL_CTX_set_new_pending_conn_cb(ctx, new_pending_cb, NULL); + SSL_CTX_set_client_hello_cb(ctx, client_hello_cb, NULL); + check_pending_match = 1; + if (!TEST_ptr(listener = SSL_new_listener(ctx, 0))) + goto err; + + if (!TEST_true(ssl_attach_bio_dgram(listener, 0, NULL))) { + SSL_free(listener); + goto err; + } + + if (!TEST_true(RADIX_PROCESS_set_ssl(RP(), name, listener))) { + SSL_free(listener); + goto err; + } + + ok = 1; +err: + /* SSL object will hold ref, we don't need it */ + SSL_CTX_free(ctx); + return ok; +} + +DEF_SCRIPT(check_ctx_cbks, "Check new_pending and client_hello callbacks") +{ + OP_FUNC(init_pending_test); + OP_PUSH_PZ("L"); + OP_FUNC(new_listener); + OP_LISTEN(L); + OP_NEW_SSL_C(C); + OP_SET_PEER_ADDR_FROM(C, L); + OP_CONNECT_WAIT(C); + OP_ACCEPT_CONN_WAIT(L, S, 0); + OP_SELECT_SSL(0, S); + OP_FUNC(check_pending); +} + /* * List of Test Scripts * ============================================================================ @@ -484,6 +814,8 @@ static SCRIPT_INFO *const scripts[] = { USE(simple_conn), USE(simple_thread), USE(ssl_poll), + USE(poll_abort_blocking), USE(check_cwm), USE(check_pc_flood), + USE(check_ctx_cbks), }; diff --git a/test/recipes/20-test_app_s_client.t b/test/recipes/20-test_app_s_client.t new file mode 100644 index 0000000000000..162fb710dac2b --- /dev/null +++ b/test/recipes/20-test_app_s_client.t @@ -0,0 +1,110 @@ +#! /usr/bin/env perl +# 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 + +use strict; +use warnings; + +use IO::Socket::INET; +use OpenSSL::Test qw/:DEFAULT result_file with/; +use OpenSSL::Test::Utils; + +setup("test_app_s_client"); + +plan skip_all => "test_app_s_client needs sock enabled" + if disabled("sock"); +plan skip_all => "test_app_s_client needs IPv4" + unless have_IPv4(); +plan skip_all => "test_app_s_client needs fork" + if $^O =~ /^(VMS|MSWin32|msys)$/; + +plan tests => 5; + +my $timeout = 30; +local $SIG{ALRM} = sub { BAIL_OUT("s_client Sieve STARTTLS test timed out") }; +alarm($timeout); + +my $listener = IO::Socket::INET->new( + LocalAddr => "127.0.0.1", + LocalPort => 0, + Listen => 1, + Proto => "tcp", + ReuseAddr => 1, +) or BAIL_OUT("failed to create local Sieve listener: $!"); + +my $port = $listener->sockport(); +my $command_file = result_file("sieve-starttls-command.txt"); +my $stdout_file = result_file("s_client-stdout.txt"); +my $stderr_file = result_file("s_client-stderr.txt"); +my $server_pid = fork(); + +BAIL_OUT("failed to fork Sieve listener: $!") unless defined $server_pid; + +if ($server_pid == 0) { + eval { + local $SIG{ALRM} = sub { die "Sieve listener timed out\n" }; + alarm($timeout); + + my $server = $listener->accept() + or die "failed to accept s_client connection: $!"; + + $server->autoflush(1); + print $server "\"STARTTLS\"\r\nOK\r\n"; + + my $command = <$server>; + open my $fh, ">", $command_file + or die "failed to open command capture file: $!"; + print $fh $command if defined $command; + close $fh; + + # This stub only needs to drive s_client through the plaintext + # Sieve STARTTLS response parser. After sending an exact two-byte + # lowercase OK response, it closes instead of performing TLS. The + # resulting handshake failure is expected, but sanitizer failures + # before that are not. + print $server "ok"; + close $server; + alarm(0); + }; + warn $@ if $@; + exit($@ ? 1 : 0); +} + +close $listener; + +with({ exit_checker => sub { return shift() < 128; } }, + sub { + ok(run(app(["openssl", "s_client", "-brief", "-starttls", "sieve", + "-connect", "127.0.0.1:$port"], + stdin => undef, stdout => $stdout_file, + stderr => $stderr_file)), + "s_client exits without signal"); + }); + +waitpid($server_pid, 0); +is($?, 0, "Sieve listener completed"); + +my $command = ""; +if (open my $fh, "<", $command_file) { + local $/; + $command = <$fh>; + close $fh; +} +is($command, "STARTTLS\r\n", "s_client sends Sieve STARTTLS command"); + +my $stderr = ""; +if (open my $fh, "<", $stderr_file) { + local $/; + $stderr = <$fh>; + close $fh; +} +unlike($stderr, qr/STARTTLS not supported/, + "s_client accepts case-insensitive two-byte OK response"); +unlike($stderr, qr/AddressSanitizer/, + "s_client does not trigger AddressSanitizer"); + +alarm(0); diff --git a/test/recipes/20-test_cli_fips.t b/test/recipes/20-test_cli_fips.t index 2abc4d243414c..fd8842b867e58 100644 --- a/test/recipes/20-test_cli_fips.t +++ b/test/recipes/20-test_cli_fips.t @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2020-2024 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 @@ -26,11 +26,12 @@ use platform; my $no_check = disabled("fips") || disabled('fips-securitychecks'); plan skip_all => "Test only supported in a fips build with security checks" if $no_check; -plan tests => 12; +plan tests => 13; my $fipsmodule = bldtop_file('providers', platform->dso('fips')); my $fipsconf = srctop_file("test", "fips-and-base.cnf"); my $defaultconf = srctop_file("test", "default.cnf"); +my $identityconf = srctop_file("test" ,"fipsidentity.cnf"); my $tbs_data = $fipsmodule; my $bogus_data = $fipsconf; @@ -282,6 +283,43 @@ SKIP: { }; } +SKIP: { + skip "FIPS RSA tests because of no rsa in this build", 1 + if disabled("rsa"); + + subtest RSA_identity => sub { + my $testtext_prefix = 'RSA'; + my $fips_key = $testtext_prefix.'.fips.priv.pem'; + my $fips_pub_key = $testtext_prefix.'.fips.pub.pem'; + my $nonfips_key = $testtext_prefix.'.nonfips.priv.pem'; + my $nonfips_pub_key = $testtext_prefix.'.nonfips.pub.pem'; + my $testtext = ''; + + plan tests => 2; + + my $destfips = bldtop_file("test-runs", "test_cli_fips", platform->dso("fips-identity")); + copy($fipsmodule, $destfips) or die("Couldn't copy file"); + $ENV{OPENSSL_CONF} = $identityconf; + my $oldmodules = $ENV{OPENSSL_MODULES}; + $ENV{OPENSSL_MODULES} = bldtop_dir("test-runs", "test_cli_fips"); + $testtext = $testtext_prefix.': '. + 'Generate a key with a non-FIPS algorithm with the default provider'; + print "Running genpkey"; + ok(run(app(['openssl', 'genpkey', '-algorithm', 'RSA', + '-pkeyopt', 'rsa_keygen_bits:512', + '-out', $nonfips_key])), + $testtext); + + $testtext = $testtext_prefix.': '. + 'Generate a key with a FIPS algorithm'; + ok(run(app(['openssl', 'genpkey', '-algorithm', 'RSA', + '-pkeyopt', 'rsa_keygen_bits:2048', + '-out', $fips_key])), + $testtext); + $ENV{OPENSSL_MODULES} = $oldmodules; + }; +} + SKIP : { skip "FIPS DSA tests because of no dsa in this build", 1 if disabled("dsa") || $dsasignpass == '0'; diff --git a/test/recipes/25-test_verify.t b/test/recipes/25-test_verify.t index ab8cdff23a212..f24ef21180add 100644 --- a/test/recipes/25-test_verify.t +++ b/test/recipes/25-test_verify.t @@ -30,7 +30,7 @@ sub verify { run(app([@args])); } -plan tests => 204; +plan tests => 206; # Canonical success ok(verify("ee-cert", "sslserver", ["root-cert"], ["ca-cert"]), @@ -606,6 +606,38 @@ run(app(["openssl", "verify", ok(grep(/CRL is not yet valid/, do { open my $fh, '<', $cve_28388_stderr; <$fh> }), "CVE-2026-28388"); +# Delta CRLs must not be accepted as complete CRLs +my $delta_crl_as_complete_stderr = "delta-crl-as-complete.err"; +ok(!run(app(["openssl", "verify", "-auth_level", "1", + "-CAfile", + srctop_file(@certspath, "delta-crl-as-complete-ca.pem"), + "-no_check_time", "-crl_check", + "-CRLfile", + srctop_file(@certspath, "delta-crl-as-complete-delta.pem"), + srctop_file(@certspath, "delta-crl-as-complete-leaf.pem")], + stderr => $delta_crl_as_complete_stderr)) + && grep(/unable to get certificate CRL/, + do { open my $fh, '<', $delta_crl_as_complete_stderr; <$fh> }), + "Delta CRL is not accepted as complete CRL"); + +my $delta_crl_as_complete_reasons_stderr = + "delta-crl-as-complete-reasons.err"; +ok(!run(app(["openssl", "verify", "-auth_level", "1", + "-CAfile", + srctop_file(@certspath, "delta-crl-as-complete-ca.pem"), + "-no_check_time", "-crl_check", "-extended_crl", + "-CRLfile", + srctop_file(@certspath, + "delta-crl-as-complete-delta-reasons.pem"), + srctop_file(@certspath, "delta-crl-as-complete-leaf.pem")], + stderr => $delta_crl_as_complete_reasons_stderr)) + && grep(/unable to get certificate CRL/, + do { + open my $fh, '<', $delta_crl_as_complete_reasons_stderr; + <$fh> + }), + "Delta CRL with onlySomeReasons is not accepted as complete CRL"); + # CAstore option my $rootcertname = "root-cert"; my $rootcert = srctop_file(@certspath, "${rootcertname}.pem"); diff --git a/test/recipes/30-test_evp_data/evprand.txt b/test/recipes/30-test_evp_data/evprand.txt index 9756859c0e80e..6f12c73c26942 100644 --- a/test/recipes/30-test_evp_data/evprand.txt +++ b/test/recipes/30-test_evp_data/evprand.txt @@ -1,5 +1,5 @@ # -# Copyright 2020-2024 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 @@ -27,7 +27,6 @@ EntropyPredictionResistanceA.0 = C0535ACD3D715A0B1453AB3447D53D9131C939AEE1D9CA2 EntropyPredictionResistanceB.0 = 9FBC48890273FCAFCA1904B6486D1877CAD91EB601E979259506F93BA462AC17D8676C570B2231D4D98EC617C4826573 Output.0 = 19CED57563D065B606DA27DD5E8DE83B93BB7C8F8B02D0288F475550C3F44B77 - # Test vectors come from: # https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/drbg/drbgtestvectors.zip @@ -3561,6 +3560,7 @@ AdditionalInputA.14 = 84922c0335a0ead609e5a92cfc4a225bd3c7c01ab4580b786338e1caa3 AdditionalInputB.14 = 34b034ca643bbfd2fcc57c9b53e0f9b3fd6a73454f1823dfe7b7076ec73fd956 Output.14 = 6caa4475189ee00ddc54910f8723b0e5b8d3d0c321ce7f2ac7194d134a0a31d96b102dd58e092e08f8a008f05c4f2afb2901c6e29549d3a720aa2b1d1f461bb9 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -3596,6 +3596,7 @@ Output.13 = e2b531ea43c513a1564fa65e9a68d43c875137773102941d0ef544c84e3689b82eac Entropy.14 = 727c0ac75a99bb1a318e4fe2fe0f2e312b3b61d82b2e5071acfb4a36bc8258c1 Output.14 = f595ee1af437fe1bed8d451088b788f1cd599f2b0c47feac1fb5c6efbf7a14a8ab0ea11a3569a3c23b2a9702b415bda355c15afd275c0d67b38bcfb54ab13f70 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -3661,6 +3662,7 @@ AdditionalInputA.14 = 170a92d093d30f939b3eac628a18bab5faf86b3a5d91f30cfd0beafdec AdditionalInputB.14 = fd0349af015037cdbb52983155c89fc59f37d512543559c3ee6589f7b93861f6 Output.14 = 0273a1317f3dd36877a505ca2e440445094d3c702c4ff5f4a07daa3f810d8d7a4f4b9c54dce169a1307fbdc5d197e6a3edc3ea737bedc1c9857aa0e9f87943e2 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -3711,6 +3713,7 @@ Entropy.14 = 22d1d8c8bde76a239d032804717face16d77b51170d0f53ccbcca4eaff4fb315 PersonalisationString.14 = 5d3a7d40fdf95b98454bca03c6fcbf6abf3807de75171b55bab2db5a3f5f12f2 Output.14 = 1007e11f48e3c4813fddd67310db56d67a49fe93e45e61b37ba81485df6a62ee57ca41fa1d987f467c2939790a20421c2b4f70b28fb0b90bbeab1ac0ae884f1a +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -3791,6 +3794,7 @@ AdditionalInputA.14 = 1eed7463c004c94b600245f4967af955919d0f325a2baf2e9c5f6e1504 AdditionalInputB.14 = 6eace0fdabf1bc84d08eaa4afcbebd502f1d83847d2e86a1e68147b3b15a76cf Output.14 = da59c09259ecc1d61e05d3198f349904df1468ffaf85f5d6cc57489e2785e54e710413674bd2ac41896ce9010d9588446e7540b35519c4689a5818ace7dbe0a8 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -3826,6 +3830,7 @@ Output.13 = 78b32d396f5a919f5ccb9be2afaf5f6212d75bf084e99357e28ccc98d433696455b1 Entropy.14 = 42cb183d2a04c89c69efbcec08bee2003b9a1cd56878a774f0162bf70f2c708f Output.14 = cb4afdec033b42949ebbb27245fd33c1503c1278027e11a1f050e04080abe4850821b71ed5a6bd83da6bde8e56c5faed49da26887028bab807d1ad055e2a8a27 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -3891,6 +3896,7 @@ AdditionalInputA.14 = eb2888119b0020cff3ac53cbb81d8576457a863fb087f91c795c297f68 AdditionalInputB.14 = ad80f4ecff758da0a5beed20a9d851fcca2ad4ea0d54af619470e3cf3033a04a Output.14 = e2105e60f2f2fceb27c882caebb0c1eca543c359947c4319c503efa82ed5cb63640f627c82217260f0203220435c842d7993623a2b05e26e1ed1d03f68ab3cb1 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -3941,6 +3947,7 @@ Entropy.14 = 3acd2c23bbae4d02cc9e4bb548e264f43e35764b446595bfe1e45165d42c770a PersonalisationString.14 = afb8203d4f7900c35d7bb454a83c5f2667ab506a68b710011c0be67055dfc3eb Output.14 = 02664c0570c4d3c468d16cc7c8b99da7a7f1752249e30f2833b1b7cd32a4df3c23454621d79119a9aaccc52d3f9055dbde98e773c26d4dace09ce9be1f1f61b2 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -4021,6 +4028,7 @@ AdditionalInputA.14 = f57cf314188b397797caa30733cdabd5ab2a90562cab9be5f812bbd482 AdditionalInputB.14 = 93839acaa271af55ec6c8464ac2ba8bc1c61584008b5d908b200d8048edc0562 Output.14 = 38a3dd584a68bd037c5d5be4a103083e1d4bbd8a845ac1832e4c545e942bb5232ccec9df2abaaf0870d1f75d3bf85aa9323b5eedc26a73ade2ddade69fcaf6d4 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -4056,6 +4064,7 @@ Output.13 = e6e345a50ced3cc68ae24ed9ad8cdb482815284e66f9b0151fdd75d13c9758663c4d Entropy.14 = ab875886827197b784b137726f1f5862c016e2c8780452fe98f4eeb68f71aca5 Output.14 = b6634452661b019afbf2e9b6e20b8be7d9cab739383de8636404c275dc495f54fbf23205dbf843afebbc4e88c6ee126f729cc407ccbbe792e3319230f23023d1 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -4121,6 +4130,7 @@ AdditionalInputA.14 = dacdc1a5c9b4215da6b1520c227724ffc888945a3cf1db2d2ff5c48266 AdditionalInputB.14 = f291eac0295f5e0936542010df7ca9c417cd78f7a109655e9050fd502ad91d4c Output.14 = 70b881acd434f90da8788bfe77226132c8a3f2544293b0ef7408559575ff0e52a17aff11b9601a4765e2ab0cc90f19f69fb4485554ec0b17ceabde960a56655d +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -4171,6 +4181,7 @@ Entropy.14 = 0c4564ba254455b6557aec1cfee2b2b726d2c4f45379267f0e27d11c6f1edc7f PersonalisationString.14 = 46aefb024c6acdc9297d5019109310de558f6afcca730c8414c54f4e574fab1e Output.14 = c94894d56985d73ac516c1249cea3d8e79b67dcdb2bf24b830d52f9e1fbdd8bdb37a546c4ffe13186ceb0a230a14ee1be0e409eb19eef018e54f79c3ddd4fbd4 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -4251,6 +4262,7 @@ AdditionalInputA.14 = 959a1aed8c1b0af637b8c0d0dfd600b0d5dcbcac12bc8cb160a2a0ee7f AdditionalInputB.14 = fdbb472c9f368a44f92bab4bd993c7f39d4e61c6503f69c205191d86bc1b2944 Output.14 = fa2f2a566b99ae810b2b95092da67bb16fa185013ad0c83a845b48cf4fa55f7017ed944d08b57d6813700fb60a30a2a2f976f8b9761516ef137e3e3a078312f9 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -4286,6 +4298,7 @@ Output.13 = 9ab8f2730cd5039a1c78f837ccaf7747b27ca425b07728933e61bc39b5c09fd63a0f Entropy.14 = 397427acb3683af13636a70fa2d9ff5b6d032f9fc6197d62ce1027517cb66268 Output.14 = 2c6b5c5682187740fb566ca60644052b2e0bc3285a399e8127ae53fafa3d5286680416772e552a2cbce4a523f26e7e7e45827a291b61a8b6fc7836e3a14e694a +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -4351,6 +4364,7 @@ AdditionalInputA.14 = 534589895777f502aa3712aeed8013d343a824584774d92f9b0668201d AdditionalInputB.14 = a97742c1e0c816626e67ebc81ba3987378499b75212b194bb56a6746029866b0 Output.14 = 8057f97b49700edc8ebf7bbc798e6eae639a443e4c8e935cd06ebf9e9bdb803cd3121a0602b32f088e7906abaa68b28b942e84bb09d13d565490d20295c520a6 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -4401,6 +4415,7 @@ Entropy.14 = 315bbe530ecfa44eb27250f6d20f4b6c648e42c61f6faed6fe483f26f6f8427f PersonalisationString.14 = efa10fa5bc1e445c031620ebb37e7552c2dfa08307dfe53c1b8e74ec55050356 Output.14 = c592d9e7b67415d09dfc46d3039b3afc1ce66afa98e8793437cfcb5ab3a122c636f0a84edc04099d3819d7fa30d196880d9199de17f7170de725f3650ef34b19 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -4481,6 +4496,7 @@ AdditionalInputA.14 = 36551ef09232d2199547aaefecaaad217443d616433d9d169bd8cd3eae AdditionalInputB.14 = 9e57a4e96ace483dbc3c226d2723c9258063278140d220c4fd023c77fb20b84c Output.14 = ca43dcecdab689549bc4493a38a6a017f6048270e5d70d0d7576a2ab764d922bc346e30f42dc5a73ea6a210d2eba9bee5b5afe3c66867a68ab3fe0d08f511101 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -4516,6 +4532,7 @@ Output.13 = 20d734ab5611a39d6ccaf8941d254804c36ba8bf206bf10d82f721ba9548b9f7cc10 Entropy.14 = 8dc5a9e8e9458f841dae788d24bb5fb192ef1ffaccd991f89f2b5d3ba57c1471612496c7d9cdd174 Output.14 = fd74a7b15c9af2ea140a2d0e353c3387b389144dda5779c69f299917dfb19de6ad60dd440c14c010ca161436243bf9d33a6649339a3543b8e71789621da7ab7b +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -4581,6 +4598,7 @@ AdditionalInputA.14 = 79b75fe104f0d7c86bbe311585198f82350a13c4a7e450cfb86e440c00 AdditionalInputB.14 = 6f20134564e79c7eb530727f5b649996c89d7bd54ebac095c19a162348fce468782f0324f2138c84 Output.14 = d00f784a9613677023d27a4350efc4cc28f95a3928c4c8da67063ee59de5d2da13a3090f580e61fff1af27a8f4ba9418e07d856a996e836a89062064bac7a9cc +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -4631,6 +4649,7 @@ Entropy.14 = 0ac627692b28d31e347179c8ee9e508e2b3ffbedae4009414b3b72e76a3739f0292 PersonalisationString.14 = 946fb7e5c3cbf3d198f19135b1a71a241ee892ac5a0316f57eae7076a4d99bf0e77fe23e81258cca Output.14 = 00007f407f75335a351d31d2754366f8f220ef2f9688a87e9d6aac59fa9f36be824b9bc7409ea991d3e0a7c411854b3701c84abdd7a696406dd13331e2785455 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -4711,6 +4730,7 @@ AdditionalInputA.14 = 1564d70c91a7f72151a4483b9eba35b52c196656ff96875d7c59c6d116 AdditionalInputB.14 = c2731fd38e65f8e724378ad4e01359512cb473dd9854fc2303e61c2d197caad69b12fde14aed66b6 Output.14 = c68d3e5697f36c9db2535b05226aa118e00fdab95ca2cdbd37421298d46d2054e900b82ccb63227a23380e4a2e93327718cca3b9f5fc9c3949adabd723bd4313 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -4746,6 +4766,7 @@ Output.13 = ba6649f527ef2d09cacf926d81abd456d4b43800dbf77de69bb9e2229cb6e3ac29c7 Entropy.14 = 62efa359ebd31d3c499353a5ab5f3b70a34c5f39c508231eae5f3ee20e17834b88fb804a32a268a1 Output.14 = 20dbd757317220a9a5b2394b495efe5e12cc7b759c877bfeed6425cd64146ee90c455c50b2243972b43015f69a015f1a4953e84a089d38171f9a6fd47b8d4870 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -4811,6 +4832,7 @@ AdditionalInputA.14 = 612b0fa86e20fcfaafb14424d1ea3092c9be131efaddff1bd9bf0c9f53 AdditionalInputB.14 = afc244f8c93dd4578bd193226d7ed321f96dfeafe8b491684e53a0fa7d5cfb95dc3cb7739df80279 Output.14 = 64806feb8e212b2b5def3375d83075a0cccecf2a8f0fd38a8ff4700a3152d2044b65e555f5a6171b10d72b6b6139ecd29309dd09e132ae88fa9a6adb500a03db +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -4861,6 +4883,7 @@ Entropy.14 = a59c31d7354eec799ecaba8193466aaa928025b162ff442ad2a4e0f9b65409f105d PersonalisationString.14 = 7b56fc016f55fe0ba21f9cc53b962e215e4ecd3dff487af67b275a19cde4afa74724a747358fd1fb Output.14 = aacfaf0360c415de87b92d74381be991f4a41bdd61175bccdd7c8dd19cd3f7076b485e95b1e9ae60ffb9b778f6470e5fe3a54092c6db3b909a4d9e5a8cb96ef5 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -4941,6 +4964,7 @@ AdditionalInputA.14 = 6cff7528b843b2efb40336bdcaa9629be2720bfa509a330430c36d5935 AdditionalInputB.14 = e0843ca3385ed55f56d51343dd718dbd1a3705d7b8a3a5cb7b955c9070ef1faf74382a9130a6803c Output.14 = 9052a75eb225ac7522cb141245e0592a334cdc8e194f5249a5843e6efb6398db1b8ae97a15829efa4685cb4f1435d022424cc7854d34743bb2d861866fff51c1 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -4976,6 +5000,7 @@ Output.13 = 2cb651524a6b094c93e8d1caf33bef269d267eaae0849c359b52d34640f14ad4a7fe Entropy.14 = 689f2f61670360472b24f8ad360fe08e249b59ec0cc4675b08ac0793dae6956db8f63108574ef0c2 Output.14 = 0897856129a42d785b60d770836a68198bc76e29840abb0802ba9d471acf8b8bff3f02e1a1c34015ad51ce85969b12ea65236bc12d349c03f2031fde19cb22c2 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -5041,6 +5066,7 @@ AdditionalInputA.14 = a0c8fb5bc632cec6f7f7a385587f27ee3ef3dfeb5aa13d978049c3d4a8 AdditionalInputB.14 = d2c1ec49b1b0f810ae9a71fe5d93ffa4004e05cf8ffb1e1eacc146c37b3af5258b4e46222cf33914 Output.14 = f3ef4c192e85dccd2df5b1c5f791daca65363d5f79bd490b7d9232b19c6059aaebc494dea3615295f407aec1af3b867a6d94abdcc41f68d2d9afbee19647f748 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -5091,6 +5117,7 @@ Entropy.14 = 2d0c45bdccac3a972fe401601379d5e5f6173edea823d53186829f343c0d1c843a6 PersonalisationString.14 = 9345dc1ee7c428a961f2b787e6f9487f938062afd5fe3b3ceb04ba8445b1118a8e2e30b3f0bcc299 Output.14 = 3d6f9140fdb46cc1a04ae987dda91a18a7eb59240c6b4292f64c8445f27f1f72a2d80e8463da01409cbf28416986ed8a85e8b9c4caa4541688aede1b6905b384 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -5171,6 +5198,7 @@ AdditionalInputA.14 = 28cb3cecec5705c020d8a3edb8079e004050d480efee70faec7e1b00e2 AdditionalInputB.14 = bf2d138b18cd6f6c698901db8b605b598b0c3ec9fb0b14f9b586b791ab6976717fcdda68e42e083c Output.14 = febe358e4daf7e1938d8c0756ae39531b1bc497e603f91c7aa2203327604144eb442ad2efee1fe9b1bbcf33a5eafa94c3c04d583631b91fe550daf227d5cc05d +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -5206,6 +5234,7 @@ Output.13 = 0ad3c8e5ad0cd1f3308f882f9aa0aa5f290d93b4a2045ceb867991f2640c5276156b Entropy.14 = 1f5f78458959b3cabd57a556a8e70c364bab260ad5572fca41fc2bb64335fb888a31cdb37deef5d1 Output.14 = 0c4436f75415d0eec411f5ba0d96fe333161c2d6faa30f6d806dc457b4123b7b2b65cf7bd8f4e699c563ec0c6f45ee37c31b3c6c11c28927b77d53053b0057a7 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -5271,6 +5300,7 @@ AdditionalInputA.14 = 320c3202d710d62b04bed6cc1d45b6a3fa306522b94cb7037ae7ed6609 AdditionalInputB.14 = bf6b78f3552fab90333117fd2fcfac3af10c5e4dc0dedc581b0b15b6aa579e576fd8b10a099d05e1 Output.14 = e9690cf3a6a69e92e56b8f793c2a27d2ed3c321e61c2e59b99b8aebae74aeb9f810348529386037ff4f1a9f525aff494f8817b087d67817c9a7547e56109224a +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -5321,6 +5351,7 @@ Entropy.14 = cf9477ba033c5d2324dd97b69cfe59d66ae7f7327aa928ed1ad36c2d9d63be731ff PersonalisationString.14 = 215a3e638fa6a74d91592b07fa08f8d4983c6ad0820a908ba735ac5bcee68c3f670f6fcf4d05b25c Output.14 = acade190508f25724a3c7dd4d960bee088cb6152f31a537295a8ff4b85af94a0ff006be9ce2f541b8237f6a7fc62a4bb8e41ac6979a6f112b57158aa6eca347f +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -5401,6 +5432,7 @@ AdditionalInputA.14 = 8b981ec9ca88b1493e7ff3b90c02da6f478bfa573f5a0354941dfedb86 AdditionalInputB.14 = 829e75a58edd00d86269ef332e6744723b289f7df8f1c0bbf70222b542b9014e2d0cdd6aaec8c194 Output.14 = 8c4aa794af3d7d4d684006808c98c11d8146b11fd062c69cac019f1913c457b49d423b5ec683f19143eab372079a6df551fc686d9d6f9ce5f64ef619186f816b +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -5436,6 +5468,7 @@ Output.13 = a0ea3af0cc95103ba3e89e5e4a6b792bfb19eef9580255ed76e71ed0e5325848497d Entropy.14 = b7f7e4e68356b2ac2c2c0075c0ef5ec6f5a6f225a18db00830261a95765771eba739a7cf8a1126c58994c43b2d28024a Output.14 = a15e8cc437a600a51dcfb778afa23d577d0e56b004f56eeb286e6c949d982bdb9353cbc63d33d7d397ceb4fea51a6df0b4d6d4cd32b9065bc4110d790c610e44 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -5501,6 +5534,7 @@ AdditionalInputA.14 = 67cd37e14222e5966d243bb44aabb32b0750220f75546953981631b948 AdditionalInputB.14 = 1c0f67ce459099f3993bc8ee4a4550d3e7dec1a5225280ecdb00ac68e17c7cf40afc5e6794208e5742c0012e87d5711c Output.14 = 26167ff9820aa23ab61f7872e007dd25d58c7f82eacb9474280731a550c8b899e08074d910d576939f87e90018987e0bff48da03aaabaa9b7faeaddd65fdf5e2 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -5551,6 +5585,7 @@ Entropy.14 = 4e37ee8649a86dd0bab8785a1e3acbd2c3a57ca346d0e31476490e49b588b928232 PersonalisationString.14 = 61334cdc8735332925221a6318987403a4c1c936c0a8066cbfbb1a84510bac2bb37ea52d6ba9f4e1a93269473f4566cb Output.14 = 8bf9c263c12a19c50525fb70cfe56980b26957e5c295f7546244ce6b7b1b90b24ce3cffc5536e96d973b192a77f878eb5e6987e1055475a0abd00312d7a65dd3 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -5631,6 +5666,7 @@ AdditionalInputA.14 = 781c2441577ac05fc069f0f988e150d7e983bbb49810eeac8b5d98fc5d AdditionalInputB.14 = 7598eabea8e516eb2d111441e94a98bb37916f291e3107dd991e7798ed896dc99b1a405443f7c781b98adc8ba9750696 Output.14 = eae935bf9ea3174c0d7da0359c175cc6bbb91ecf9357e7748011fba02fd52205df0a87a44eb4ccb6015b266ed3bb9be4d0d403838bacd42757cd34216d71989f +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -5666,6 +5702,7 @@ Output.13 = d39cb66ae64219a8de99b4f63daa8536defeaa53a055a66ec3de18c41673fc926b1a Entropy.14 = 100e176574bd55438477f0153ed04b6cf221bf6c1fcd7141aba10c80d71eb2e16bc8213aed689f44ef57807334dc3d12 Output.14 = b4315cc4470d4c50a15836f218b21c96668d32eafc1649cf6c92b96f0716aa54582a31a1c5f597b80f62102622369e422d98c34d1498cb9bc01d418a4d232074 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -5731,6 +5768,7 @@ AdditionalInputA.14 = cd4cb3a8e0f1f8a67577d71339e6c4f40a291cdd22d5a19aafe0f7c99e AdditionalInputB.14 = 0203e75cce2d2e81ec441ba73b3129c6ae5067733bc0031614cbc8fc92d599523ad30da2ea253c06c48293befb14ab71 Output.14 = 927c1e64d9f3acfdd74e7afeb9ab2280f37ce9c1839f8cec8c32db7676fab057620144d34c8382bcb904e85af45d348e10bb2e5708268343595ffc08dd258c00 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -5781,6 +5819,7 @@ Entropy.14 = 4e6768b663b1838fbd56c78b002c08c28121662238456ea93c4b286f4a1d6aa2a1f PersonalisationString.14 = 47c24038732c32baf7e1e71fb0b74b74ec055adb88f8cf111fc27598ea74872fde608266a8f49105282c2ca7093acea2 Output.14 = b1ce96d86e77a251c4fffe5de31e9199a19fa242b03b005cf0b6a23ea3a0c5b87edcbc77d0019f24d8c0594a4edba054b32d2c9e5e2f0893c424b11887b0be48 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -5861,6 +5900,7 @@ AdditionalInputA.14 = 0e2ec484d8866adc065b4f11d3760b4d276e2cf9c066b226311e7c7806 AdditionalInputB.14 = 9fdfcb7460ce5b9913ffb9889696df7abe28aad40eba3b675d7508cca1c98faaa27dd5f52997dd6f251a68e86f966fb1 Output.14 = 66d6b1693a3ca1cb6169858390741bae3285e0c28604d064b57f3aa2ef9a569bec22884ccc5cd315d3f3847c680c3481bcae423cb105ea47956f62cf8c2c5d29 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -5896,6 +5936,7 @@ Output.13 = 47b6dc1f9fc7ba68973e15b489e46b94b4ba58e23d6691a6e8311dd82a6187252e10 Entropy.14 = 80ffeccaddab35221cba00ff374728dab8f91f3e5498622704c050e3e13a2b0bdd2f913672e896a979974c52067e2a05 Output.14 = 0292bdaf725f469307e76e3ef5bed03470f6bdfc22e4d7f0661bd1b87696c9da201bbbdca6a22344ea88ffc7325370863b4cfb105740165eaed9c6e73b06a4e8 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -5961,6 +6002,7 @@ AdditionalInputA.14 = 8ca625e0daf65ecb70ccc63bbe88720ece7a415b12542c59db488bd056 AdditionalInputB.14 = e511e77b98df72d3e4c175b58b7182fa729a61649659ff117d9b4c514cf694fea2731b170d0babbf6b6bf8198be6d932 Output.14 = d9d3ac1480323439e9f8f09a54b3668684890fad51ad314c8e14bf0fdb429738b8955e3d2d928f2403f20caca2065795c0adaa30a5c4683a08d83074633be8f2 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -6011,6 +6053,7 @@ Entropy.14 = 409bc372b8738c80ac35721bbb8e806ddc93e816c8fab98d1d0f2a053f959601667 PersonalisationString.14 = 975da7439df9a5b76f8ae5201da35692fd46d277787f8a73b08201e6547ba72de26ba7725ad44a11f742e6c2b57c0e9f Output.14 = 01fe7c18b85ede519740ed4068af24b4baaaa7d727b05241af481ec843c20bfce41e4bb131cf03a504aecd5409d03f6b5b84d22f0e1042b66e5d99d4339742fd +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -6091,6 +6134,7 @@ AdditionalInputA.14 = b0bf3ae2cfe4d3fae5573781456b3725a59598d52ffdd081b412106481 AdditionalInputB.14 = b94a9134257079c16192066b6e3e50d63d58dec6632524114e6bce3415db5abfe0c89108cf2fd6478a97079f5190f1c5 Output.14 = ac7c1a00228f6a7a0620d00dca7dd38e53c71d31aace470703e4d8911b071b5ae517af60ff9f2aa570b18d35b2dcf8af0ee14ba646f2be35571c7cec44ec88d4 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -6126,6 +6170,7 @@ Output.13 = dbeb1de34b0e6f1c96cf4afd1e1230e434bcb1a5497f797871e16aa3f60f8dbcb4b3 Entropy.14 = c1fdb2167e6db331a3e796c83c8b10352650c20cdcc41b859f8b0059f2638bdceca6120928c3311b6b8d764a67b47192 Output.14 = b9ec753ca46bdc1058f5b77a9d1d9d7090d0b70f8b9995658b8d5abcb68462a09c59cf404bc4a625037b52ba10e336c2bbd049a507fdb95e32d09904a2482f97 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -6191,6 +6236,7 @@ AdditionalInputA.14 = c839973b79c3eea5db7107ca7cae1c012cdd59a50e58b7461ed7921178 AdditionalInputB.14 = 3cde5a2f6e19fb4a4493830016cd86afcb7a8db49a2abf6077ebb5314dd12a2d1fe9d3601c125c41c3e9af4603ee8f8b Output.14 = e61a4d439b4bb1ccdc810ef7a0019e5e88321ab6687f6564d5f70c0afb1633d50da63d6d1b1919b724b57ee926d63a80ac20f1ff06c4932456c70e8b64db43f8 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -6241,6 +6287,7 @@ Entropy.14 = 7ce9977cb80634f0503deee2afb8230c57408c83bf5bf41d2d62d4daa4c492fa60b PersonalisationString.14 = d862039cc2c297d63529a33f38a6e5660a06919a044c7e746ff238b65321d2a233a9a9c7b3534c932a8881ad38d31f65 Output.14 = f17b61f1c3caae331160b714504b9c058ac345f07a5a26034dbfd7fef5013b52cae3e2cd357095b623065ec5cb557001887b17f9b6f9476d5449ac7d81d5abd3 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -27303,6 +27350,7 @@ AdditionalInputA.14 = 639824768081b8f8d09b9b4eb51c0bd1ea5666067ade2628d45e727213 AdditionalInputB.14 = 7492ada1c96f7b2de329cd54651bde17b4fc69471280931180bbdecaa2889435 Output.14 = 5c37c829eee0a9acf2ec0af816c7974a09994e744c070f58d4fcc216491a35be0d32854cc4bf6956ea5c43370c02084dd30a66fda089f5c47b4975d59a01a022 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -27353,6 +27401,7 @@ Entropy.14 = 8ecdbf1cba26eae45f70ccfec0e42d6139be57f131ff60898a3b63968acf28ac ReseedEntropy.14 = 8d860dcf67fbee47f33ed5273ff81956335d9152085f184f8427ad4234f95661 Output.14 = 8049f3fe2e62883f71cc43873b9775bf60a97c070370f9757c51488b050c00959d085ddd8f8e3702aa4cd6ff19b6c62685afb7792eb003c07bbcc9f4a026d138 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -27448,6 +27497,7 @@ AdditionalInputA.14 = 9e0abd6fee611320de52bc48e56f5f17bf180e596d258031e3666066bc AdditionalInputB.14 = 5612694e4260dc91ba87ee97656f1436cec1f711536bdbf61064026673bb398b Output.14 = 02bb0c1e3abb2993383cc9cf2f32c148d785dde27df3a8dbd3ecc73ea4e884cd427061423e0736a95dd3202e6336cfac40311b8f08aaa88a90baa2f93999694b +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -27513,6 +27563,7 @@ PersonalisationString.14 = 48882b0a263582f0c6bb8288ba894d7141e665aa0c084c7d99eaa ReseedEntropy.14 = 34cc10a3d71398efec3c5854ef82a77a0b6bfcaf841ad9a1d5c7bf05aeed9082 Output.14 = cac26b07204eea9a41e4289302d0da8f36ea200dacd2435f1bb1c1235cb362497eeb87aea2889aa1093d13d2cee25eb11e28229c39acdf894122425b5948cae2 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -27623,6 +27674,7 @@ AdditionalInputA.14 = 1550ac6da1742834c705b4dad61c37fc33e7d786f76b553ab324bf543f AdditionalInputB.14 = 77ef7c3f819de78c243351a71bbb460936064738fcb75acfc214c884ff172311 Output.14 = 1030bfc7cc645d6e2d6b2a3f2e97979ab999d70252c15504d71d02c5842c34cf63b94c512e162726acfb1492ccb525ea56e4ca1b54daaac2284e558cb4936931 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -27673,6 +27725,7 @@ Entropy.14 = ac5668ac054f732d2bcd88561642c5a7ca98c68e341cf0cf18873fea93ef33fe ReseedEntropy.14 = 4a4d088beb9843e4622cdb0c5a6851587f2b472dc5d734211409bacec7b2ac06 Output.14 = b2013a363f3ee01ab8573f3e3eed32285108c3ed3bf231c066176ed901e4d6ffaaf0cfd12d63d7c19f6c460baf434a1d6a552c62274bcb7469f7009c0beab972 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -27768,6 +27821,7 @@ AdditionalInputA.14 = cc92f09a3b12f29d9e73253c261e828196fa540a9024632665c6c25a41 AdditionalInputB.14 = 53113703a3362b3eefb0c12587fa25a620e09e0cb63acb3f7b74471618cc0d05 Output.14 = eef4850d91b63508bdf3257c4b66c8c022a6869cc8d9473e5f579d103c67225c04e3994f14c31ff0e328c1adddc8d8f6b1f2e70409325a353eec19c420352b7c +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -27833,6 +27887,7 @@ PersonalisationString.14 = a48f64c672f37649b12630157e15b9364ee7548984d94171b2a29 ReseedEntropy.14 = c4933f8a2af99389732cbd0120b697b9ad99e4821f4610b66c18d9da0e28bd00 Output.14 = 77dc9c1b636acd5b76a3453b168479ce947f4fc1401ccad4dc61d4630370ce21d29017244cee50644e3654e702b623e20ff49861890781a6bdb68e5cf3a7216b +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -27943,6 +27998,7 @@ AdditionalInputA.14 = 2537ee73b566f7febc51963ea96691994fdb150d42db58204f95be45b4 AdditionalInputB.14 = 2f4dd1698f26af2a921d4f4aceda1c15ac71fff62ff7bb5ea6a993a29a8dc199 Output.14 = f1b46b0276bbd75eec0792e9998ce83022c8ff2f00ee9947760c6b2bed3f6a19bff58a0a92093a57b5ac949cc4028fe31e2a6262125994e6e30dbb4b7faa6d4a +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -27993,6 +28049,7 @@ Entropy.14 = d083e222d8159740044707c76bd9ec4436202ac778f63646e5b1e88f21ddc13f ReseedEntropy.14 = b7b714550798c888a5026b0b7801c0923ae60a2858cabb6d6972d66115f40eda Output.14 = 227a88583bb137f082967af04c27cb464a6332720b759b435d4a7e26349f56f4bb447695c06295e838a6c86fc3867006217c94bb5cc99b3c44bfe541fc77503c +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -28088,6 +28145,7 @@ AdditionalInputA.14 = ee0d3e9c178d53f9957ec0877ac719694197e8bdffedf8fe59c57a0cf6 AdditionalInputB.14 = 2545d30f8b974a21fa54146a14a566bc0156a015bdde60f3f2b9e186f6181f5d Output.14 = 7cd2003034f235e209cb0d73ab442234016a04c830752721998146c2f6f27d92300b47fa3ee72b46378092feb175583894b6f7004362f724ef145fe03c941d42 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -28153,6 +28211,7 @@ PersonalisationString.14 = 41b9b8e2d9a7945ffcf2631bf7d668648993c0f4859ea22de4279 ReseedEntropy.14 = cecd9d0ac5cb7ea4cda4566b873bcefc2db068ee41774a6861a21bc69cbe1814 Output.14 = 9d7209b625d5df31a949fbf15bf6e4515e42e6eb03909dd6d7ff4e001a8408c704901ca2b2121c079e36c28aed7a786aa356b6f3c75b87d4c78a2d06371de356 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -28263,6 +28322,7 @@ AdditionalInputA.14 = adc0707f3a06e767ea80f0882ebc015b79f0228547d22eb5a635b244a7 AdditionalInputB.14 = 8372a1277f0eb84cadd53df4a6cc619cfca029f84d9bea48beca8cc8060528cc Output.14 = 86cde22dae3a1af947d76cd15e4df0c83a11769d34610d1991945350acd4f0aaef9ef70b5bbd57fab74fac6be8cbc028b9bab63aa5de62d9f1f95d949e9d093e +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -28313,6 +28373,7 @@ Entropy.14 = e3d8fcb8c049e442d2bd07104c46f0602a1f60f87bdc02dbecdcfcf4006b5b0a ReseedEntropy.14 = e25327867ff27456eff9f4ae4375c7a85788b400dcae03ae8c892472c8a05221 Output.14 = 754063c679269931fdab8f90deaa967969f20b1805d93fe5b1928512cd2fe98984974b0bb1d7494d81f53e073f1a3a9378ea27307a154dc8a1fb1d3e17998f85 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -28408,6 +28469,7 @@ AdditionalInputA.14 = ff296cd83f439529d436254c490013f26fac4ab407e158a06b3c9d4e9e AdditionalInputB.14 = 63dee758f80f00738dee68e5f8a361cbbb371bcfa1b67ffb073c45e3c84b85fb Output.14 = 295446b08f879c3e46f0c57dac85767d94805fcdf7beb1eee75d40f643254691adef0e8300cf27deb90a72805cce91a4433d263ecacee0583b222b81c0bbe401 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -28473,6 +28535,7 @@ PersonalisationString.14 = 345b74cf00947dc1eedbbacd5e4030d5639f5e3c0b9fb986fdc0c ReseedEntropy.14 = 3150b6ab1fb005ceb8323c6982fc3af3092077241dcf4993fe91696bd5b8b747 Output.14 = bff83f45e0a4223489b08409497471427e7b82f834082137497bc552127446a8a3f52a730914650cd753098162f7d253bbd625983430d1f16fcdb0f78a1348a8 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 0 @@ -28583,6 +28646,7 @@ AdditionalInputA.14 = b643013474a37b208a6f6c44cc56b1caea69e1289d8897d53f40423d9a AdditionalInputB.14 = b1e07a0f9740c49335ab5244e3b7aa567c7234e01253fa1c31372ac43b1d6519 Output.14 = 6e5fb213d4bef40b3f274f956960a1e0d28e5399bfcf2709fe98de2b54ff26766835b6ed538b887cc617529d057f6005db0227dae7627728504cb8cf3530eb2e +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -28633,6 +28697,7 @@ Entropy.14 = ac8e24b8704e2011076ff9175fa1c12d9beeed66c9a975037ef6f1f519efa2230ca ReseedEntropy.14 = cbe05b235ab45735f0fa0ed945ec38ec3801f2caed0bd8f96dfb34cc75ef1a6a4122f5a8305f915e Output.14 = 91c49803af71477a06a6a493b75aa36817aa15b58afe7598750b2fe4d663f05ecf0b8c1b5737cd611e2d56ce95a029bc4fbc307f5478f0b796b259e01a48920b +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -28728,6 +28793,7 @@ AdditionalInputA.14 = a491fa45d161efa71ccdb405d6ef3153700b28966582e1052cea992218 AdditionalInputB.14 = 4a0cd52d005056df60803fb353728f3b3fd27964e5c96965ac472ff8bb4dedc4dd7d1ca04b124f0a Output.14 = 0f78e45be38a6a46c2914449beb9df52394067b720f390225f930c3313916f00293c7f7f173cd89d2c30c72bc07482f066708bda7a29af420490821c98c995f4 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -28793,6 +28859,7 @@ PersonalisationString.14 = a35f706fe78dab179bdb83495408764805175744bc020388a8a60 ReseedEntropy.14 = 4d632ef30482e6d5949cf52407d42caea7cd745e70d76d3449852a7ddb3f92e19840cd0217e1112f Output.14 = 3340cd5e74c52918b391156702851b25327072f075e16b8c9378972b081b2ca8cfa7665b7052cc44f480f0c188342357cc6c8cb616a0dadefc4e1ed40ba42b0a +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -28903,6 +28970,7 @@ AdditionalInputA.14 = 5f7205d87d0a9868234eeb8c4ae42cd47c03983b77dfaa84637b4080df AdditionalInputB.14 = fb6d486fd7586036003ffce8865e479498fe530f9ae29e01f98d4a2f7b665b6a9329450b0fb6ffb1 Output.14 = 0d3d8c9ff86fb56bf362787f474f838066fa7483a958c23f752be6e21cb42fee11d8dc53396508f9fd5122d04e41d0e0c949d50c46d51d0ac824b6f46b5df088 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -28953,6 +29021,7 @@ Entropy.14 = 0e681f881afa243f5de75a046205f733a32a1bb39e2abd057c07d8d5e81589d537e ReseedEntropy.14 = cb16a4907b39f647eec2b388704d6a2b89836cdd8d1c0c7ff27cddbbb0d01e306dbd01ec58334700 Output.14 = e48aab2c01335ba4f6d377c3c993932d4fe2ef60254eff315491b81acd1c22b3a33c59b8b78c479b7cd4fdd31f7d15864a48ac706e32174de36f9239aba4b6ad +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -29048,6 +29117,7 @@ AdditionalInputA.14 = 37ab678301ab45deca791b4c5b1a792c5422f2e3be57bcf77d92468e25 AdditionalInputB.14 = cb7a6611c7fd8ffb884ab41766bf4a57878f187dbb09d7b0e77db4ed2ccfbcf3c640a9348dec4e1f Output.14 = b194fd786cfab66885cfe7b03daf642dc60efd7399f6c48d3df50337b40c40349b94ca509053451c34d6b838ce1905b5cddbcf5df1be2a9783404bd0b72b523d +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -29113,6 +29183,7 @@ PersonalisationString.14 = 003b5e534bb565f4e1eacb22f2a2a65093dd0c782a27805f0c4c4 ReseedEntropy.14 = f2c16713da96ef435d96c63fbbc57d49c44d99c679c1af53a12cadea98d31981a7d06991efeec73f Output.14 = 67c409157d60f8703da237c4c8b4f124298bc95f68cd5510304c2167145fb7c4beeadbc6d7ff9b261b420e93cf9fb135d9946d5f4c4829557e7dcd713143115b +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -29223,6 +29294,7 @@ AdditionalInputA.14 = 6f6d6ab0d0c02ecfbaa3ba6d8f38a8acb08699d08f3035ce7fd03343b7 AdditionalInputB.14 = fba0d6f6ca8f1a587782c5319766209059a23cb3e7476b2d060ad06f2db9e09728cdbe0f8a86c14c Output.14 = 9e88544b8486d3445c0bf47d0f55bb8d3f2abf5d5b2816df7abcf3f419dc37ca332bc00fb8c40152750b4c46054e8a281190f6e3007b844c63f6cbd1dd9acb01 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -29273,6 +29345,7 @@ Entropy.14 = 8f5235da708cb15781db85ddc141eacc654d93f8c211ae718df22ed7bae7ba5f2d5 ReseedEntropy.14 = e6cf01b0cf9931ded0ae50bd0e1092cf79221397f2850d31390db33ae05072ad0e67cde6f3c438ba Output.14 = 7a00675e1a9b524dadc1b356b22c46c6747147ed736639739bbf761ed9b917670238ec001387b7cf3c91a58a81ec09c1487313058b6c26ce61d5785269a1d8e3 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -29368,6 +29441,7 @@ AdditionalInputA.14 = 18a09894ed824809e66ee447f9413505035c8e85db5b9c6e597bf6a2e3 AdditionalInputB.14 = 75ec329e54639306dc853b73498dbc002abceadb355e12ae69fea16cc3ae892272544990d2938be9 Output.14 = 4c08126a7fe978f25982672ee2044a9dfe31919a2003853a74d9132b46a2278547af5980d037401275ff86528bff41fa80180e823bb88cda6029e06d2b009e81 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -29433,6 +29507,7 @@ PersonalisationString.14 = d811d476960f2d5032cc3fb7002be155c6314e03ae7788dc886d0 ReseedEntropy.14 = 8fad4aec11507a394be8bf8cf24c4f2442c45948b5ddf28ebe33f9643ae5d21337ec8dedc9b23e1a Output.14 = 6d353a66b4cd16ffc5469b1c16951ba00b075db4f1282df1cba7267b9e191e21f604dda9eb48921f927f1d7b4548d5bcc580829c422ef0d5b2127d5eff4b020c +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -29543,6 +29618,7 @@ AdditionalInputA.14 = eb4fa0ae2bd5ff9ab19545d30350fab09719db12f428ccc3fea36da4a0 AdditionalInputB.14 = f1d0853fc6fecca6730079b5e64840bdcbc2ccf4a9e20aa08e8ee2e48c785838b154c66845e2423b Output.14 = a29949eb92716b0682cd27f62ca00cfbad717fc976c55dddd854ded44a53ea2cd0dc0a97db8b6011d583f8fcb522b7f8c3d2fdd68ebdc083e23d5f5737dfb572 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -29593,6 +29669,7 @@ Entropy.14 = 963fe575c96b319a3418cc7548484ab827df1f7ba56b0da8131fd19f7712add1d29 ReseedEntropy.14 = e1470ee367e55bd8dd82dea6f7fbd905b98d596306807f8aae529807b36aa0655bd260e1e2bab75c Output.14 = a1e6286529fab40e3db9b57741bf6e5b4904590d05569a7d571baf77842065be742e2c26c14e8599e46a520fa39b81ebe32dd857556d9f55e4bd37c1952afc0d +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -29688,6 +29765,7 @@ AdditionalInputA.14 = bf76973791b52d9387e2a36f3ab3620bb983dcd2399fef3cc6bf4cf86c AdditionalInputB.14 = 2089acf7aca43a77d8459d4f384919575ed88c7c4759b9dd7033a132a85c2ec6c71025c166083bc7 Output.14 = 81309a10ac3f02d3fee049a5ddb9f02f64dff3d6b75259d561921a8349b30054059b2af81c6f7d50189a0bb6d360da06bcbdc944997d6f8b051f23998c8c36ae +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -29753,6 +29831,7 @@ PersonalisationString.14 = a477a42a221cd2cbcf790ca70fb6a5f18a91c297617561acd1bc5 ReseedEntropy.14 = 108f6f37621ace418e2155f70dda4c2b5d6aafa9269f6aa98a5455e3a1d188e64ec022c454c68620 Output.14 = 05e4896494b02861a51357463f705e812a14f57eb8630cf1fb025c42ec9dd54de3f5fa1b38d1f3d890aad74d5ad1683d0b5981da4d3a939d05fd5435b1d50f38 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 0 @@ -29863,6 +29942,7 @@ AdditionalInputA.14 = 6aec5f8c3dc54924104e04635ab80b1f782869bc5c1557f7d89daa1e1b AdditionalInputB.14 = 668d732a98f7ae8cdc9235d63e705955c09600a490021a19a34c1befba8cb613ee7d8e4c5774aba4 Output.14 = 1dfb0a6bf411580aa55044f26c598d2620965fc94a769001f10b1909228616146bc9d02f749d094786805e3db859da9e6a572833af5cefdb147873ec6023b028 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -29913,6 +29993,7 @@ Entropy.14 = 1accff5a19861164c5d2cf542cf41a789f143c7956518ae158d4449ff0c257a0096 ReseedEntropy.14 = f2fa58209759d84bf38a1656bae655669767a902ade22a830df56b32ef9e1c992335eb4cb27eeb142bfd21b5d31451de Output.14 = f214b4055d182cb258d9e9b61251bebc9bf090db662c4e36023cc156964fbbe1cedf691cd0c3d7db4262fb65a5d34b942f909b0f31fc18009766413523dcaf40 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -30008,6 +30089,7 @@ AdditionalInputA.14 = e33d181f3159fb0874eff5ef8ddd2b51a60b13ccf046f7e637ed27bed8 AdditionalInputB.14 = 3ecf6233820e6cceddac7b024c490c5ee14c73d5b598c92cda30940471b6ed450019120689aaf157fd87b71b13afea25 Output.14 = 9d793dd96b870dfa0267623bd1c2d8bd3e2c63e9f211340f630fea01358011394154145a10659c4d98274a525c48a90da0126a99b85ed5b4b903195f0dddc762 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -30073,6 +30155,7 @@ PersonalisationString.14 = 8c40c5317f29b64da7f4025cda90ae3e99ba1ed350482048f8411 ReseedEntropy.14 = cb7933c3c803644d4ab7c35b941319bebf6784f98c04754c69359e10c9693b57ae12e38b08ca8a9f0f15142c4476f0bc Output.14 = e95d375c7b3354190721d598e8fde7aef16fb2a9dc963ed76eef6a12abe2001622725a8e1545c73c9a85995e6b07806e2ac39b179b595bcfd96b2189b5d10497 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -30183,6 +30266,7 @@ AdditionalInputA.14 = 588eb722d4066ce1e9148d2e7a6d43d1d8b4886bd97f36f24599dcdedb AdditionalInputB.14 = 1b4e904a6b861201028506075d7d7fecb81158ea3749421d4d4710ba0fcb157b5019dbca199c8302d34745cb0c2330b1 Output.14 = d155941b54ab48dc1866641c034b117d6dd8a7d068d29201105d845315dbc747afd8fb1f9ba5c976c75ff8c7052aff7b342c1489bc0c9f8a7d898b88ed0d5746 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -30233,6 +30317,7 @@ Entropy.14 = 68e91e73623fa6a3ce22f424e9db971459dfbe06601ccff96f1726fa18e61d5cdc1 ReseedEntropy.14 = 249b56dcdc4c5c8eaf796c8685a740fd4ea2455c135e0d7b8e50532fd87c95b781c8f3775c213c2714eecef140125b78 Output.14 = a15d3d61408ddea3b9753c854c693ca1a91cf49d172160bf15f512f345bb1bda9aa7bc4fcce177fdfebb3fea4cc6404c6024527ea662669a5eb78753822bfdd3 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -30328,6 +30413,7 @@ AdditionalInputA.14 = ed3f47e59a12b36a42616b338c7a77a18e333d38abb9da4e36914b69f3 AdditionalInputB.14 = 6e39b249f1b8111ff12fa24f9f2320df2dc8752e1541f556b5cedfff409b6a858490c27e052a63504c7131b438f44356 Output.14 = 650bee69393d5d7793c8a5a40cae79bd470d15fdacab7b51b251f51dc5d3e383d28d808c7f9e018c71eccc80371a9e0267ba4053ec0e4c071d110942c43149c0 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -30393,6 +30479,7 @@ PersonalisationString.14 = 531b64be5d25937f30bed886f2021855db1b63777febe6695eb4f ReseedEntropy.14 = 350112071b8315afa26fa3d9be6b6dec59ba7fed2387556cdec43ab8def92050d2f0fd34ef0c837c022c337f227b2169 Output.14 = 47ad3d7ef4e7bc4696d039b6e424669200b5f6c687f813c270483793518adf6698aa40a781208878017bf77afeb2f98794d21578623888eb98135ef0e5121c57 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -30503,6 +30590,7 @@ AdditionalInputA.14 = 02a4bfd4a825e4d811770127c6f5a568deff4d7989300a0bd23220a586 AdditionalInputB.14 = f9775f8fb1b767c4639e2c3fe9f0820e03e28780641ecbf832451baea5e1ef83cf9e078cc325b1fc7a8a14bf07cc4ff5 Output.14 = ba473979f23358b95ff49610a7b91936b7d1da44bf8891cc19ac6ceb9f0241a8c3771a2efb403275bf599aad30b9e4604e90729241763801387ab239ae543625 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -30553,6 +30641,7 @@ Entropy.14 = e23a7f95c3cf3fddddec66cb16e1fbc38495ebe98b3e14d8f351e58bc457cd38b79 ReseedEntropy.14 = 36410abe456d7a51948098897ec205f75f22ee09cfcc94ca88fbaff8d159fc779a8e420d11fc1ac09518237bfdb74462 Output.14 = 3c14a63a9c74dd02051c0147637401649a68452c28af90e9628f1ac87df1d27671397ba34f493997ef634284b74b3b28b2e7d4171eb025e470f39dfd12636a5f +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -30648,6 +30737,7 @@ AdditionalInputA.14 = aff406d3d514ec118c9a8f470db34922b8bb262f78c1ee6ecbc647eaa2 AdditionalInputB.14 = 50d8e7887df0785c331a381b6f11057ed720abaece80b7f8358386fabf5da24a912b8f1563301fbcd7ad240c03a5e444 Output.14 = be0045c0bee70daf5a57e5b449fde2e9320a0e0d429950ec3b8ec14ca2acdd7ca2a365bebf11f45f356c34f7e52a8c39ac2e141815134bab3b79ce3dc1d2a44f +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -30713,6 +30803,7 @@ PersonalisationString.14 = cfbbe01cda290c89b2841f37952cfc1d9a4222fb425e9453de307 ReseedEntropy.14 = dc9c22b1006462af08615eca5998ea81a81411be226a241c38d480e7ae0ab5bb34721f0ab9226633d655675ffd953420 Output.14 = e544668dbca5b35bb59ab04945649cead8d822a1d8ce125e3ae5db8b23e3bcc05bf6921ce95b85766b92c13c59ae83d908471e03e020fdeb59e5cea817a48802 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -30823,6 +30914,7 @@ AdditionalInputA.14 = bd203cdd94307bab1a53734a3a451f0b038614892186b26877b2c1c849 AdditionalInputB.14 = 631cf0317b713d07ce74f7b05ff4e7a158c769993d357325f8e9d16b25076bc9b0febbbd66bf23fbc9c27286dc1663e7 Output.14 = 401176185d33ef08d0b65a5b853d57583250dd2efaf44ca0f987b45f89eafeb52d2f4346bf9b9d0b7dd4f7126e7d89dd32f53b737cef79ab5dd0794fb8a4c89d +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -30873,6 +30965,7 @@ Entropy.14 = 91fa80b727040295b850119e9fb7e4cce4551ae234f29616af15572557d1555de04 ReseedEntropy.14 = 9937f776ddae1dd4a6ed76cc1795d450e14d1e462c30a9e1a85334b3ca148451b94e00055b3ed227f0a2fc247db4db6d Output.14 = e659a7de7a1b1b15a56170a1d6334dec91b6fffc47fb7ae1f2b3af03cbc25f7bec0cb6afadb76af9d36216825ee0e13aa3915bc515325c27270858654175a81d +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -30968,6 +31061,7 @@ AdditionalInputA.14 = 54dd28543c859fd4dc1e4f0a44ec9aa2b758d51379c0a9c75805356793 AdditionalInputB.14 = 3803a58e41fb766847b9f568ecd7f1993091c4689fcf70f754d345ec7a3f45d1fecbfcc52cd60b47b5a486acb155e213 Output.14 = 3cfb2eda22c4f01893b4760b785d330cb771938ed6f2f929030fe625780fb91fc2f9952409b99f011cb5e7e0b4a7d461be80e94e91111ace0604a7a41719f3b3 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -31033,6 +31127,7 @@ PersonalisationString.14 = e7a492e06f2079eb6428f4d39fb18aa0ece5d1edc5f2e1403737b ReseedEntropy.14 = 17837fdc7d5600fa487fa07331c4db6e3d65d522537aae0715a5936f5cb81953965fdda82e5f2b0a1f20dc8beb76beca Output.14 = 2cf0d9cfb60234b23086dc1649e6fa99c4104de9853d19508105535c960468777a936543f6b31ed0d3c52d135671a23d3ea08fb7f29c9dcb3f151163587c39db +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 0 @@ -52485,6 +52580,7 @@ AdditionalInputB.14 = 373b7d3c6e3c07907a45e6292da02991c252b4f368ac894e44fe2741d6 EntropyPredictionResistanceB.14 = 72901d3c6324cb6eea7e62879721c4ab437fcac453cc43f179388851b6d160f3 Output.14 = effddd2d7c39df20550e03ad21ccba6f6775a92726af567a80bcc91523f3646ec156cbaabd4fdb13c63105f2b771f94fbdec6a2670f8fb263cdec3ac1b775774 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 1 @@ -52550,6 +52646,7 @@ EntropyPredictionResistanceA.14 = 43d53e48de3c247857132224a448147672dec7cffe1016 EntropyPredictionResistanceB.14 = de28c574f0d771f2211acb54b43a60ef79973081f06da6819219612c67bd94b7 Output.14 = 3e6e82f2edb3fcd74559b46d319b09cfc3441c06bac7a1260647ed7f9327485d553873d8b58c08410574161e0ff9d5bb2ed4cfea533bdbcd47ec627ac405d3f6 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 1 @@ -52645,6 +52742,7 @@ AdditionalInputB.14 = f298b8789db7c5b8e0354764d0b30013453c3c5c77bfec04264203d767 EntropyPredictionResistanceB.14 = 9a4dfac99270a67b45256a4da4ac0df15693a4a19fb68d08c0a2061a9e190749 Output.14 = a7746e689fbe9eeed34b0ba524851742a5fefe1ff5ab84c6b9a118da64a8ad8fc9ff601ccbe6a5b7e90c5da8cdc8d9fba741d22a0aa1d8ce4fb9cd6148eb06da +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 1 @@ -52725,6 +52823,7 @@ EntropyPredictionResistanceA.14 = 9dfd31e3adc822b675c0a9c8702df12de4c3354ccdb538 EntropyPredictionResistanceB.14 = 2a1b1519d22d40ef4ec23c6d97dc148cfe171fb5f8b1c305ec6d8e83a1ef9064 Output.14 = ac054570b081cf53b39b0a2faa21ee9b554c05ff9055843ac0eb9031d1de324701ad4cf2875623e0bf4184de4aea20070be1cb586880ac87fbb7e414b4b128d0 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 1 @@ -52835,6 +52934,7 @@ AdditionalInputB.14 = 6fd46ca18d10326f5734d0160163bc42d3daa55e3c74a2e0fc7380fd84 EntropyPredictionResistanceB.14 = 16f3bd62634368535da170a7f117bbf8b896ba1bfac5ab682247b1b55452e844 Output.14 = f84c05b144b114fbd2f80a21862a44f3641fbe980957e3fab736976db37b8bca823d7f848f32f4aca60268c020a2e85a5ee0f31fb746f0dff066b83d32563df9 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 1 @@ -52900,6 +53000,7 @@ EntropyPredictionResistanceA.14 = 8090391380ed44d3423fdf8d47891a2027110da4c2334e EntropyPredictionResistanceB.14 = 8288a190ae9118c57b033808bb3f895d4dfbf2dc7ce9b9016e339548fee10a6f Output.14 = 73d122b8854f2610a833a78af28baf4a2dae48dd1ed685e4f98947092e3aaa56a65fdc9acd8a875c16b2a91c757ff7cd6ee777292fbcb0220795c9519cf44052 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 1 @@ -52995,6 +53096,7 @@ AdditionalInputB.14 = 440e9b55a68dd27df4ef8d0dfeb8c2156c2250cc1ab574432c2b62baca EntropyPredictionResistanceB.14 = 3cd2f704ace560337fcbcc07d2b027c37380b35b26b26e40b9d62dd654e44193 Output.14 = e55b536cca2b2148af20e887ad6b1c6ab5c285fe5271e188c5fe5f7f037bab8d6d2502ab71d768d4f05b1bef7f27440ce8f64311ff7147dbb55719bf7371bbd4 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 1 @@ -53075,6 +53177,7 @@ EntropyPredictionResistanceA.14 = d0caa71a0c2e2f218bdded7a08864addea822aaab598b5 EntropyPredictionResistanceB.14 = 31fcf2f4f7580ea3b79e738830d42a218935ac5c6583febabc14bb5463fe4609 Output.14 = ae6cbc3e108ba64b18244ac14eefb670caa16784e175ffc1f41126cdbe791e0e3de26d58123aae6843613b478b9ed94173fa27c7400bb071e0a9829b9a8fca19 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 1 @@ -53185,6 +53288,7 @@ AdditionalInputB.14 = 55156a604966212f7cf20379b79cdfee41a9fe462c9f7e17e5a082c5dc EntropyPredictionResistanceB.14 = c64dc7f4e7fc14ada0905e271e0de491a7b8e4931d26823e572132329e00652a Output.14 = 7d96dfe0f6fe3eac2de3a3a8729d36afb1767aeae2ac3c79db0c523226cacac3cac6d5a87d4f152e8e7274069cc9f12bb7edb293f04e9bbd5a8f0ab142fc373b +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 1 @@ -53250,6 +53354,7 @@ EntropyPredictionResistanceA.14 = 25aeb73bc04139a647b60a0e506db2109581f58b704f00 EntropyPredictionResistanceB.14 = a2e5839c59fc255576a2fd462c719895314a033823f11f419446d02702bf004f Output.14 = fb833a40a658217ad75391aa8311b3e872bbc2e1cb150da87cc6e3494423c5a992593b68f609d30387a0384f64079236a1038969d011bea6f8adb052c5b57eec +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 1 @@ -53345,6 +53450,7 @@ AdditionalInputB.14 = 4e6c1d082917ac9eda7f032c61867736b5be7b3045555f6ef10c584875 EntropyPredictionResistanceB.14 = bcad225d779bd3653a616a8d667030c556117b2adb88e4a6a4e0d0561ae94f42 Output.14 = 14cf6fa5cfb8f9c74add5b2dca5e30395a1045ed1e1cf4e91ccbdf8ab80d1c0f1d93481651535e4089638b04fdf95f52aec1fff6565b21d8a2a32ea814952411 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 1 @@ -53425,6 +53531,7 @@ EntropyPredictionResistanceA.14 = 24e9ce22a727e4540d7d85e056bf6448063d5f13dae559 EntropyPredictionResistanceB.14 = 9a5f15c36078cfa0c768868816d5bd0b1d33c492fa9554498b6625639a293dcc Output.14 = 54c02aa8e6ccc1f109a5f215f488fe9ca7c7ceb3d1b0d9e9256ac4f5d4195cc8c36f8d8ddff55ea10f86d0eb5bdb5b116339b9c0229eb7e96814012a2ed5eb0a +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 1 @@ -53535,6 +53642,7 @@ AdditionalInputB.14 = 34e517ff4f40e3c0c699710134cdeed029baea8e142db0bac9c5aba6a0 EntropyPredictionResistanceB.14 = 09d8b16346fbf20ca073688ab3e917602686e07dff338142841410068e640296 Output.14 = c1d0095376ac846921d2bba5f4d50d231851311792c66d125d5701d6cc466e181c893dfc9999c21063f69f0cdb9850c3a34755926c67e3af75e801e7c21f3da9 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 1 @@ -53600,6 +53708,7 @@ EntropyPredictionResistanceA.14 = c52074e8343f57c0f56c9aa4bc3a6bcc9dff30b21905ae EntropyPredictionResistanceB.14 = f09a47309a1ddfeb54eea6dfa7b15ab0e6f183e2478a3889de89091c2bac0c25 Output.14 = efd931fe77e202d2aba86f6407126a859c881abc86c8f8342deeabf527ed6dc679e5dfcdd212ddc3f2e779d043f058893d7b23c6b69334ba0132db6ce82a167c +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 1 @@ -53695,6 +53804,7 @@ AdditionalInputB.14 = 0bf212302b4d20c6d2b799c9fd692b14b5672897fc45b416addaf55501 EntropyPredictionResistanceB.14 = d0b9c12bd6b178f89a238afb0fce43d45dfd2467b3a1cf9b1aa31960179f125c Output.14 = 7e5720126ce4ef83b785d9649915cf76ed6ef318422950b6540cef9a0ca90c40203b3a365b8a5c40d63475f7b37f5366b7f2ed6e18885e361ba89d46350028e4 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 1 @@ -53775,6 +53885,7 @@ EntropyPredictionResistanceA.14 = 3695bd2e5b30b1d3957dd0a116bddba53a24dbe647dea6 EntropyPredictionResistanceB.14 = 4079d6610bbc715e62777ab699e3ac6b6c4d097aad4debf668a54d15744d9ec1 Output.14 = d0aaa51fb084825f8bf0476c703f1133829a93dee1f8061222f3502ff1bdfd550edfdc275f3aec8a8fc5f9e5f71246362fdbcc65a00e7cc52ff353cfa3b3759a +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-128-CTR PredictionResistance = 1 @@ -53885,6 +53996,7 @@ AdditionalInputB.14 = b44a499fdf9330170ebede64cf8fb19f4a8317596d80d8f9c9d1009322 EntropyPredictionResistanceB.14 = a4341ae5155601af7ccfd9bc573968f99ff82ae2605a462af7e6ed6fd5f2cab6 Output.14 = de6541dae09137dfe17fa3bc785c8f45d3d36cb621d76c53f9031b2853ee0657a1edba0f6f06dade6a5a62faec54cf69bbf15db2244909114b0486f75da3cf16 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 1 @@ -53950,6 +54062,7 @@ EntropyPredictionResistanceA.14 = ddcd35394681d6f0170aa6bd8932b602745f41117eecb8 EntropyPredictionResistanceB.14 = 09a5d5925616379b5221b347659afa11da4326b630b57f3b78db9812e667ed3fbad25fcce6307486 Output.14 = e04e5432f671015350f0cc912f5e83e969e00584c6178cc82394cf85ce3dee6ca87b6cb02e27a21e03f83c24c761f521830645fefd4474c634e1124a4d93da30 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 1 @@ -54045,6 +54158,7 @@ AdditionalInputB.14 = cc7df42c7f93a63b8a8389c66a336519cf27cc6e61a06a67c33077c954 EntropyPredictionResistanceB.14 = 1c59550710b2efa9f009e44c0aa724ad3451da29323f60d68d025693510fc01670c282b38bff3249 Output.14 = de2abced63a11a9c7c034fae31d8fd57239a76a8d8382d9a507e5230c1b0c5bf063a99f00cd4428db196597427900f56ac2ff8d556d3af3d119a590b594c2e90 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 1 @@ -54125,6 +54239,7 @@ EntropyPredictionResistanceA.14 = 756f29305af9f4d3ceca4399594d07636df0b2ecfaa064 EntropyPredictionResistanceB.14 = 1880252ad93c994dff31fb2a10fab8c265cf6f6a36f010fc35e4d858bbb783e3a682afc3fb98fe6d Output.14 = 2f7872a704eb276afad3efb131e67c4b9508fffdbb704e8c85c07e6132745941a8889ffc37baa637a1b7b7b0b84fbfdb8fbc00e7f1eff50baf2d062d8434bba2 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 1 @@ -54235,6 +54350,7 @@ AdditionalInputB.14 = 3d91e9e7ca5683312545bdb4613dba83182b0c906f3a1d65a2610709e8 EntropyPredictionResistanceB.14 = c9255e2fabf84b9edd45737f5de13e5661acc03623a3f9268efcaf7f5562cf839bcceda229e06f11 Output.14 = 28ac3acb17dfdba1d5abb3e2515dc16b42bd207d2743c51b3a2e5edceb0021d964fadd50d499e2df1623c2832a9e552331e915395d65e95f3d523d40d1d8a15c +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 1 @@ -54300,6 +54416,7 @@ EntropyPredictionResistanceA.14 = ea4ffce516fba5a28325206d639d1b3a0f7c61798947a5 EntropyPredictionResistanceB.14 = d7e649cdf563e960640b50927a92abcaa306d4e1315eadb0316bb65d7f9166577bab34bf012a6f9c Output.14 = e92c34e544c5342445228ae6740616889856eda4ce82fb7f1c15d1951953f5509ae754624ad9f159dd5e1908da3c97d2a66945b8a8746634dc70b7f31718c4ab +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 1 @@ -54395,6 +54512,7 @@ AdditionalInputB.14 = 16d262848510e407c7680cfcd3fcc27b8647fcc0155426b3e7b54bc473 EntropyPredictionResistanceB.14 = f6d98f69302da7ad42b8e580a9d755e929fe39fb0436140388fc7160d94f6167c0e150566fe5310f Output.14 = 9c7766b3ebb27f65539f3dd6001ae45c85bba6d6c09e600f0b9cf5e02f30b0f8584e696c2fee0239d5e4d5b623700ca98c94e7ca82fbb8b4643549f29d2df244 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 1 @@ -54475,6 +54593,7 @@ EntropyPredictionResistanceA.14 = 828357ad5c99f114394f578f56cd7e9a5da671636bce00 EntropyPredictionResistanceB.14 = 6f256e9f5f7a84ba4fd6eb19b6ae20b27c26660e51982bc4cf8e28a2dc43cdb723cc8a727c2ea91d Output.14 = c176910a6a7c96982841c0b603b423b2fa67c267b5388d858a4d8dcd69d6b67cb96816892162147e38cc602afa459fc5623da0862b74f1e8f569bf3b1024d881 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 1 @@ -54585,6 +54704,7 @@ AdditionalInputB.14 = 205f0f79d140c6ffef742bf3cda512a3fb84af66d058e5a34752cfd0e4 EntropyPredictionResistanceB.14 = 1989becc20da39682e67b961dc4a2f10a73b037b21cf055f1f12e8f59f047200dab4907e5e8b96aa Output.14 = fa20e0054f9edef75b34aa4e76b16dd6d9d54de5e350c879e16541cb80a4e64c3f392a0108c792ec8fcec84721cd71ccae15de31f3eff57e09f024506857c3e9 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 1 @@ -54650,6 +54770,7 @@ EntropyPredictionResistanceA.14 = fcab2000ecec66a23af1381d36e1df97a4341c329f375b EntropyPredictionResistanceB.14 = d75022692bbe5beeca5d81942443cf0dd78b770b7542cb8fd1be65e4908816ea43fa903a7a66fe0b Output.14 = d5f91235a90cafc96e39e2a1e636d9a2386c5214d8616941bb9f4c2fd375da49d33fabec2faca971d6520bab482e33f6f2752b2d054f9c3bb1f50d072978ea2f +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 1 @@ -54745,6 +54866,7 @@ AdditionalInputB.14 = 1a72cab51be3633be268e4533fe4ad482e5178cb3b15c6d8090ae9e888 EntropyPredictionResistanceB.14 = 6587fd55057566c3fcdbd85aa2b693d885234144a6ac9000b8640c8530da8e2e72abfca6980d7119 Output.14 = a0496a05e5238f171f18870973c9e7b9b3fff44df1fc1ccfa398ef73aeb41829a39339fd032591abcce4cd9402297f7c2e38fd2486eaa8c20134fc0122af978f +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 1 @@ -54825,6 +54947,7 @@ EntropyPredictionResistanceA.14 = b459eeb404a1480b64e7d572bced365bf822878085363d EntropyPredictionResistanceB.14 = a057871a394e93e58ba191c239e21858a3127a6b748a4505eda487dc6a5293304aad36d52da132b6 Output.14 = 96b24ef7b19370cb3ec40a4763de926977ecbe6af2fba201e983e7bbd71b23fa95bd315933ce2fb5a10f4a121cc56b125233f09ff920cc380df7ab5513403457 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 1 @@ -54935,6 +55058,7 @@ AdditionalInputB.14 = 02a318a1579714ddac239f968564fa2768d5099c237237ac15aba9bddc EntropyPredictionResistanceB.14 = 0d18ee1fdb9dc23c66aea587fa59cc9c65da7690a7a780bc64727fa3fb22602301911ed3f99fd712 Output.14 = 992397ec168448c4521560085f3956d2fc583bda1924b29fddd081dfcc056a0dcaaf3edd1a84158b6b7e5737d37535fbbd6258319b7458c5524cd0061a8850e8 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 1 @@ -55000,6 +55124,7 @@ EntropyPredictionResistanceA.14 = ad927a71c6390c5613a7c14780abe6d266b2d126aa49f2 EntropyPredictionResistanceB.14 = 152ec7c0d26eab6de29d3d2ef321281297bd2591be887318712ccdbbd3ecfc1c9250f99a226fc9b8 Output.14 = 0ad1101454cfe091f1456383eeb1e7a968328da150f1166b89e7c202daf5e42324314c43fd1da6de3feb9ffcf82cf217bbcdf5c96864c227246306f0c975c4c8 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 1 @@ -55095,6 +55220,7 @@ AdditionalInputB.14 = 3f5221732e417fe4234626d8b4fe5dce8d0974a7551c4e7b9eb827f32c EntropyPredictionResistanceB.14 = 1d81b5e14e9f995cf19771d54877e97b2d4f551c36033874fcf3a4814312d7064acc2556ea5e0fdc Output.14 = c6d9cb21922398c6a63e4d17f0f69f1d4c1b4998d73828d43ea1f69acad5b1d94800a6976c09a8b5befa2b0c82877874eaed15027f9f7dad3bffa005e49758a0 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 1 @@ -55175,6 +55301,7 @@ EntropyPredictionResistanceA.14 = 21db28b5cb9724d93c58f787b155f0131c39b5606e6a96 EntropyPredictionResistanceB.14 = 4aa587edcb940c3a9328a0ef2f195effc1cf027b549ff1ec5d5cac0e996196eacd16108498b27366 Output.14 = 69dc6c36459e005275e344886624ca61a42cba3387dcee79392ae96a311313dc7e33283605fb46aa1d881bccaec6336a61545dac52166cbf8174b8dca3ebfbc6 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-192-CTR PredictionResistance = 1 @@ -55285,6 +55412,7 @@ AdditionalInputB.14 = 3dc3ef9447ffddf64c3ca0569afcf8e5d491a9571b9a1fa251e0684d3a EntropyPredictionResistanceB.14 = 140636342e9ebb2bae8a87b5d8193a59b75b12318e7094975bed5ce2d23a58b4a021496e820a1b35 Output.14 = b72e486984d1273fa7865a2a43a830b625e394cccf169610ad2714b5b64ef6473f53e62aaffc85bfa2b155bf81830abfc528a80c17f2e325bb7ac9197e5a1099 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 1 @@ -55350,6 +55478,7 @@ EntropyPredictionResistanceA.14 = 6f16ff94cb8ade7a928b9a59af32ea79944e6890a003b0 EntropyPredictionResistanceB.14 = c73fe23a8ba2bb780178342598252e9ce3de907c4fc1cd632b353cf959ff610f23a8a2b0424ad137aec7da42f8c9f2da Output.14 = 8f7261edf6d10824218ad0b10881e3c1251637bbb71d0f35280caec7de254e07147f33288b5c60794060b59e6f5cc2938e4c29de1e4d5d4d3bde3f27c3fab92d +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 1 @@ -55445,6 +55574,7 @@ AdditionalInputB.14 = da29846d4d48e3eeac71ab07fae9b9dbb6c5d83cffb75c67be10bb15e6 EntropyPredictionResistanceB.14 = 0d9037cf745b3cf41628eb1538bb71b59116da1049ecd36d12d344c5a17e471c8c4e72cfdc7ca0538c81085952241d68 Output.14 = 7a7ed6e632630ffcf32f0373deb2c67c6dcb77f04f1991f89d5d25a3a8c390ac8ac373b66c5da990c3fe28cd93f3a4f8e5594cae25498ed73f5f001b83179b0c +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 1 @@ -55525,6 +55655,7 @@ EntropyPredictionResistanceA.14 = 2b3877ed4d1b3174d36e784ad7b6b7991dd52979ca5b1c EntropyPredictionResistanceB.14 = 91d421c3eb04de94099a7467254bad70e236d5c27616f766e85b4de3965001db854e61a80bfec2eacb4ff93ecafb8b83 Output.14 = ed703d9273bb9462ac400ee8d587ea3c4d6c27aa014defcb6ca6fe885272bcb4b6ba0822f42941071bf635b41d997c631b680d91b23ee48351041dc274900821 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 1 @@ -55635,6 +55766,7 @@ AdditionalInputB.14 = 4f23641093342d946d3a956c456dba18bd42de21cb2494f6310da7d20a EntropyPredictionResistanceB.14 = 843e7cac38b659a611dc4af4bd228ebc0cd9073ee98350d04da61f77db66c0c70872153d9fa2af4bc583ac2cf79d506e Output.14 = 6754a72f7fe23ea607ef0ae61a61eb3afc562c5227670572b7ff2dcecf3dcb4194829d29fcf9b100412aa0ee87611ab534896f80f47cff40b7f76e0ea46b3d41 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 1 @@ -55700,6 +55832,7 @@ EntropyPredictionResistanceA.14 = b8ef0d478028f0c55dd13861281489e6c124870f0f28c8 EntropyPredictionResistanceB.14 = c12649a0f249c7f5ddb550eb527a0f720e5eaf04e6e3b96dc24881eba10ce466f67e3fe51a0342cb1a2192a555798169 Output.14 = d8c63ecb23f16ee925282b7744e8cc2c2c1deb56581cf27152118b5790cdbe682a34d91523bf0c7be4ff263aba2ffdda35e4d36a5122461b89b43069932b30a9 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 1 @@ -55795,6 +55928,7 @@ AdditionalInputB.14 = e97f7fc9e287ae947d3e937d60ece684f0c8dd9e133cbd7265b2b3e073 EntropyPredictionResistanceB.14 = 94904fbdfaf6b1d8931c15a37277814dcacc6343d48b80a1c624f8aa3733e05a52bf1f1266e2b90da5d562d7ffcbc274 Output.14 = ef2fcb4a9113e062d6cd37f51a9944645c3cce0b06e2d11a2c778bdb559a2f627c8a0e7f419660f461456064c3508df1db945af6085abaf7719e868a912df8dd +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 1 @@ -55875,6 +56009,7 @@ EntropyPredictionResistanceA.14 = c436b73aae532ffb950c6ed83753aa6df0571f11fd8e0a EntropyPredictionResistanceB.14 = d3ed7671eb3c2e0c115ec9d6d684964d39533d767413b63e0bf7c956b47205f8d5001a9650e7a1c7381f110c9ecfe92c Output.14 = f99b7d88ccfe1c84c9949c3548630ea2a9ec033543c693c5bf72a82f404c5eec5b2a09afb6c95f10b48fe4608092e7213285af83ba1304acfef846060a1cf860 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 1 @@ -55985,6 +56120,7 @@ AdditionalInputB.14 = 58a98d14625f59f7adf6a703b2e1ee21fb83f22f3694f7f06548c85804 EntropyPredictionResistanceB.14 = aec90f26f7c7853f3917de516f1ee0f85a0f3d0eb4967f6d2694552a93a25ca7fbdb4554de8acc0e60af0c5b0829cb9a Output.14 = 18d3f2396fa92b0b9e6bc7a5c0f9f8e10857c0063b4fdd8ee76d12e1205eb5e4fbe1b07ffc0ec5045eaaad608a558d1107f931c0290392166bed2d09849880a5 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 1 @@ -56050,6 +56186,7 @@ EntropyPredictionResistanceA.14 = 1e5191f18e3c049b3aa304604a42b13e87b61ab808a1f2 EntropyPredictionResistanceB.14 = a04435fab8cffaaef34f6738f2682adef4790e8e2655d5943bd5370009ede99a6da3c9ca4dc7105a1352f9bd295be419 Output.14 = 31b0234431f4ff22f0c1f5c220a5890c7efabc06974357a1ab8a79d1caa66b46b62f0b5a5b0d8010923dd86ced2f039effa2031619aafbb3d7dc9362ef04bdf3 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 1 @@ -56145,6 +56282,7 @@ AdditionalInputB.14 = b1e3c770adbc772d94edef6188d0f07ea1c25fb41dd20eefb552dead33 EntropyPredictionResistanceB.14 = ffd6fd3031397d33e382f40b6338e7e3640b9b35800d890581fad4784366a1533f38398f255dc316bde222850794e46a Output.14 = 826dc7b1c39fb4955f614fab27697ed5fa1ed8686c701ef5e03776a814bbcdf9afe49343cb53944241c30b201be6d181edd20d55fe0374a43d68205d8ef758ff +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 1 @@ -56225,6 +56363,7 @@ EntropyPredictionResistanceA.14 = 83acc7bc2f89de95c84a4450d509e7de3512ad839f832b EntropyPredictionResistanceB.14 = 95a26a2f946c03f51012bc6cda0797af89a8500394cc7f11866a861608eb97fcd2e37df3f681dc3c1b3f48bdeae119cd Output.14 = a7b6c0c8bebd7eca9357a2be02063a603c103d68a793e792497ecf66592835f1f9607dae7b98be1049514ec5ea4cdd0b41d5cbf986a3a04314515b341f0924ab +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 1 @@ -56335,6 +56474,7 @@ AdditionalInputB.14 = c0e16d4fc85cfb1c3a4f69806041c5a270d4af742292dcebeccba75e1b EntropyPredictionResistanceB.14 = a52c99a12f63c6ae4bc101ff221d7fd1b4dd79df76e38992ba3fdf380bdbad5e6aa15d0ab638e90874d81bdb2e983aba Output.14 = e728957b292565f906de0cee5bf91fbe2e189857ca5d5efefb5953a8e9f46630756ea01abf8e6fc499bc8e2e5c29c62669bc07ccfbdc7951215f8ba7f1bc815e +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 1 @@ -56400,6 +56540,7 @@ EntropyPredictionResistanceA.14 = cd66ebf08c99f9c04c1effc078717b4f24422f111591a0 EntropyPredictionResistanceB.14 = 60c6f9f07f75f1a80188b32d07c2895872c4e8b92a19ac6c2a29bc807f99fb4af75b6aed8e6f75c9a6b1559b48f128e9 Output.14 = 2d20709ea0ff7a624ea1e37d80c65c25eaed85af45ef1a092ea7b97c49c912a0f0fc62d29ff4e4182c6bb12676cab3711c2b8db265cd9f81569a300b99fac43e +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 1 @@ -56495,6 +56636,7 @@ AdditionalInputB.14 = dbe91ffe3bfb719bebbb0e3bb60aa907ca6e0411c05a7ded766674cd4d EntropyPredictionResistanceB.14 = ca5099749aa7f195e0fde5262c56ad35c1d52069001fbb6580d478f50d1d69f6941d7ea4fa66e4741cad701a67f92933 Output.14 = a135641f33e2aa5975a3be70b05e0b8c48372ef7c6768eed8e6c2b4e91d9153eead217ea47bf96b1412af4e08c3114d2c85f2e29fbe93c26014677bd14266ecf +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 1 @@ -56575,6 +56717,7 @@ EntropyPredictionResistanceA.14 = c3444261962386b57d6c5f125dc3043678afe1962d55d9 EntropyPredictionResistanceB.14 = 1fd895068aec8df2684784007949e0370578676c6537a09dd90567b95f6138809e70bcc9fc9efc03dfd83f0367784bde Output.14 = 894f3bc0fcbdb76b01df80f05d0ca636bd51438f5ee28250f27e8e47968c9c86a847970090d51b0a60984ebb5079017a5c5bac394e9644befc566edd4768d919 +FIPSversion = <3.5.8 RAND = CTR-DRBG Cipher = AES-256-CTR PredictionResistance = 1 diff --git a/test/recipes/30-test_pairwise_fail.t b/test/recipes/30-test_pairwise_fail.t index eaf0dbbb424f8..1b3269a9824b6 100644 --- a/test/recipes/30-test_pairwise_fail.t +++ b/test/recipes/30-test_pairwise_fail.t @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2023-2025 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2023-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -22,7 +22,7 @@ use lib bldtop_dir('.'); plan skip_all => "These tests are unsupported in a non fips build" if disabled("fips"); -plan tests => 9; +plan tests => 8; my $provconf = srctop_file("test", "fips-and-base.cnf"); run(test(["fips_version_test", "-config", $provconf, ">=3.1.0"]), @@ -37,17 +37,11 @@ SKIP: { } SKIP: { - skip "Skip EC test because of no ec in this build", 2 + skip "Skip EC test because of no ec in this build", 1 if disabled("ec"); ok(run(test(["pairwise_fail_test", "-config", $provconf, "-pairwise", "ec"])), "fips provider ec keygen pairwise failure test"); - - skip "FIPS provider version is too old", 1 - if !$fips_exit; - ok(run(test(["pairwise_fail_test", "-config", $provconf, - "-pairwise", "eckat"])), - "fips provider ec keygen kat failure test"); } SKIP: { diff --git a/test/recipes/65-test_cmp_msg.t b/test/recipes/65-test_cmp_msg.t index d104576a9d60e..ac6648296749d 100644 --- a/test/recipes/65-test_cmp_msg.t +++ b/test/recipes/65-test_cmp_msg.t @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2007-2021 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2007-2026 The OpenSSL Project Authors. All Rights Reserved. # Copyright Nokia 2007-2019 # Copyright Siemens AG 2015-2019 # @@ -20,17 +20,22 @@ use lib srctop_dir('Configurations'); use lib bldtop_dir('.'); my $no_fips = disabled('fips') || ($ENV{NO_FIPS} // 0); +my $no_ec = disabled('ec'); plan skip_all => "This test is not supported in a no-cmp build" if disabled("cmp"); -plan tests => 2 + ($no_fips ? 0 : 1); #fips test +plan tests => 2 + ($no_fips ? 0 : 1) + ($no_ec ? 0 : 1); #fips test and ec test my @basic_cmd = ("cmp_msg_test", data_file("new.key"), data_file("server.crt"), data_file("pkcs10.der")); +unless ($no_ec) { + ok(run(test(["cmp_extracerts_dos_test"]))); +} + ok(run(test([@basic_cmd, "none"]))); ok(run(test([@basic_cmd, "default", srctop_file("test", "default.cnf")]))); diff --git a/test/recipes/70-test_rio_poll_builder.t b/test/recipes/70-test_rio_poll_builder.t new file mode 100644 index 0000000000000..e76c2f280a781 --- /dev/null +++ b/test/recipes/70-test_rio_poll_builder.t @@ -0,0 +1,19 @@ +#! /usr/bin/env perl +# 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 + +use OpenSSL::Test; +use OpenSSL::Test::Utils; + +setup("test_rio_poll_builder"); + +plan skip_all => "RIO poll builder tests require QUIC" + if disabled("quic"); + +plan tests => 1; + +ok(run(test(["rio_poll_builder_test"]))); diff --git a/test/recipes/70-test_sslrecords.t b/test/recipes/70-test_sslrecords.t index 299ecb60bea1f..e2738cf8bb676 100644 --- a/test/recipes/70-test_sslrecords.t +++ b/test/recipes/70-test_sslrecords.t @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2016-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -208,7 +208,12 @@ sub run_tests $proxy_start_success = $proxy->start(); if ($run_test_as_dtls == 1) { - ok($proxy_start_success == 0, "Unrecognised record type in DTLS1.2"); + # DTLS alerts are best-effort (RFC 6347 section 4.2.7): the client's + # fatal alert may be lost, so we cannot rely on observing it. What we + # verify is that the client rejected the connection, i.e. exited with a + # failure. Whether we happened to see the alert is only diagnostic. + ok($proxy->clientexit != 0, "Unrecognised record type in DTLS1.2"); + note("client fatal alert observed") if $fatal_alert; } else { ok($fatal_alert, "Unrecognised record type in TLS1.2"); } @@ -228,7 +233,8 @@ sub run_tests $proxy->ciphers("AES128-SHA:\@SECLEVEL=0"); $proxy_start_success = $proxy->start(); if ($run_test_as_dtls == 1) { - ok($proxy_start_success == 0, "Unrecognised record type in DTLSv1"); + ok($proxy->clientexit != 0, "Unrecognised record type in DTLSv1"); + note("client fatal alert observed") if $fatal_alert; } else { ok($fatal_alert, "Unrecognised record type in TLSv1.1"); } diff --git a/test/recipes/80-test_cms.t b/test/recipes/80-test_cms.t index ab86ef4bf2f63..b27a03d601627 100644 --- a/test/recipes/80-test_cms.t +++ b/test/recipes/80-test_cms.t @@ -53,7 +53,7 @@ my ($no_des, $no_dh, $no_dsa, $no_ec, $no_ec2m, $no_rc2, $no_zlib) $no_rc2 = 1 if disabled("legacy"); -plan tests => 36; +plan tests => 38; ok(run(test(["pkcs7_test"])), "test pkcs7"); @@ -796,6 +796,18 @@ sub zero_compare { return (-e "$opts{output}.txt" && -z "$opts{output}.txt"); } +sub read_file_text { + my ($file) = @_; + open(my $fh, "<", $file) or return undef; + binmode $fh; + local $/; + my $data = <$fh>; + close($fh); + # Normalise line endings as -out is written in text mode on Windows. + $data =~ s/\r\n/\n/g if defined $data; + return $data; +} + subtest "CMS => PKCS#7 compatibility tests\n" => sub { plan tests => scalar @smime_pkcs7_tests; @@ -1004,6 +1016,56 @@ subtest "CMS Decrypt message encrypted with OpenSSL 1.1.1\n" => sub { } }; +subtest "CMS parse authenticatedData authAttrs and unauthAttrs\n" => sub { + plan tests => 3; + + # BouncyCastle authenticatedData (HMAC-SHA256, KEK) carrying both an + # authenticated and an unauthenticated attribute. Per RFC 5652 these are + # SET OF Attribute, so with the CMS_AuthenticatedData template fixed to use + # X509_ATTRIBUTE they are rendered as attributes (object:/set:) rather than + # as an X509_ALGOR (algorithm:/parameter:) they were misparsed into before. + my $exit = 0; + my $dump = join "\n", + run(app(["openssl", "cms", @defaultprov, "-cmsout", "-noout", + "-print", "-inform", "PEM", + "-in", catfile($datadir, "authenticated_attrs.pem")]), + capture => 1, + statusvar => $exit); + + is($exit, 0, "parse authenticatedData with attributes"); + ok($dump =~ /authAttrs:.*?object:.*?1\.3\.6\.1\.4\.1\.5949\.99\.1.*?UTF8STRING:auth-attr-value/s, + "authAttrs parsed as SET OF Attribute"); + ok($dump =~ /unauthAttrs:.*?object:.*?1\.3\.6\.1\.4\.1\.5949\.99\.2.*?UTF8STRING:unauth-attr-value/s, + "unauthAttrs parsed as SET OF Attribute"); +}; + +subtest "CMS decrypt authEnvelopedData with authenticated attributes\n" => sub { + plan tests => 4; + + # BouncyCastle AES-128-GCM authEnvelopedData (KEK) carrying authAttrs; + # a clean decrypt confirms the authAttrs are verified as the AEAD AAD. + 1 while unlink "authattrs.txt"; + ok(run(app(["openssl", "cms", @defaultprov, "-decrypt", "-inform", "PEM", + "-secretkey", "000102030405060708090A0B0C0D0E0F", + "-secretkeyid", "C0FEE0", + "-in", catfile($datadir, "authenveloped_attrs.pem"), + "-out", "authattrs.txt" ])), + "decrypt authEnvelopedData with authAttrs"); + is(read_file_text("authattrs.txt"), "Hello AuthEnvelopedData world\n", + "decrypted authEnvelopedData plaintext matches expected"); + + # A flipped authAttrs byte must fail the tag check and leave -out empty. + 1 while unlink "bad_authattrs.txt"; + ok(!run(app(["openssl", "cms", @defaultprov, "-decrypt", "-inform", "PEM", + "-secretkey", "000102030405060708090A0B0C0D0E0F", + "-secretkeyid", "C0FEE0", + "-in", catfile($datadir, "bad_authenveloped_attrs.pem"), + "-out", "bad_authattrs.txt" ])), + "reject authEnvelopedData with tampered authAttrs"); + ok(!-s "bad_authattrs.txt", + "tampered authEnvelopedData leaks no plaintext to -out"); +}; + subtest "CAdES <=> CAdES consistency tests\n" => sub { plan tests => (scalar @smime_cms_cades_tests); diff --git a/test/recipes/80-test_cms_data/authenticated_attrs.pem b/test/recipes/80-test_cms_data/authenticated_attrs.pem new file mode 100644 index 0000000000000..4f3d212698011 --- /dev/null +++ b/test/recipes/80-test_cms_data/authenticated_attrs.pem @@ -0,0 +1,8 @@ +-----BEGIN CMS----- +MIAGCyqGSIb3DQEJEAECoIAwgAIBADFDokECAQQwBQQDwP7gMAsGCWCGSAFlAwQB +BQQoWM396pUOzWW6mFsNvr+XXTLufCrvzG3jiTOX+l3LpSXbXHhhpadw5DAMBggq +hkiG9w0CCQUAoQsGCWCGSAFlAwQCATCABgkqhkiG9w0BBwGggCSABB5IZWxsbyBB +dXRoZW50aWNhdGVkRGF0YSB3b3JsZAoAAAAAAACiIDAeBgkrBgEEAa49YwExEQwP +YXV0aC1hdHRyLXZhbHVlBCB9kCl8ic3e5461oodeDSyR7heZxtdN7G/N+oqerDIj +PqMiMCAGCSsGAQQBrj1jAjETDBF1bmF1dGgtYXR0ci12YWx1ZQAAAAAAAA== +-----END CMS----- diff --git a/test/recipes/80-test_cms_data/authenveloped_attrs.pem b/test/recipes/80-test_cms_data/authenveloped_attrs.pem new file mode 100644 index 0000000000000..75c8eab00b886 --- /dev/null +++ b/test/recipes/80-test_cms_data/authenveloped_attrs.pem @@ -0,0 +1,7 @@ +-----BEGIN CMS----- +MIAGCyqGSIb3DQEJEAEXoIAwgAIBADEzojECAQQwBQQDwP7gMAsGCWCGSAFlAwQB +BQQYknpV85muZoLZSPkwi5Ll1Z1HwzAeZThVMIAGCSqGSIb3DQEHATAeBglghkgB +ZQMEAQYwEQQMkCQb305essfGO2nqAgEQoIAEHvYjM7EK9qZAHgoohdcbSHXe0lGJ +/Hjk3nkK5VsHxgAAAAChFjAUBgkrBgEEAYaNHwExBwwFaGVsbG8EENeGq4IXAd1O +iv8hMl+lHZOiFjAUBgkrBgEEAYaNHwIxBwwFd29ybGQAAAAAAAA= +-----END CMS----- diff --git a/test/recipes/80-test_cms_data/bad_authenveloped_attrs.pem b/test/recipes/80-test_cms_data/bad_authenveloped_attrs.pem new file mode 100644 index 0000000000000..e14946c96d881 --- /dev/null +++ b/test/recipes/80-test_cms_data/bad_authenveloped_attrs.pem @@ -0,0 +1,7 @@ +-----BEGIN CMS----- +MIAGCyqGSIb3DQEJEAEXoIAwgAIBADEzojECAQQwBQQDwP7gMAsGCWCGSAFlAwQB +BQQYknpV85muZoLZSPkwi5Ll1Z1HwzAeZThVMIAGCSqGSIb3DQEHATAeBglghkgB +ZQMEAQYwEQQMkCQb305essfGO2nqAgEQoIAEHvYjM7EK9qZAHgoohdcbSHXe0lGJ +/Hjk3nkK5VsHxgAAAAChFjAUBgkrBgEEAYaNHwExBwwFaWVsbG8EENeGq4IXAd1O +iv8hMl+lHZOiFjAUBgkrBgEEAYaNHwIxBwwFd29ybGQAAAAAAAA= +-----END CMS----- diff --git a/test/recipes/80-test_cmsapi.t b/test/recipes/80-test_cmsapi.t index 3d1dae8464646..1f5f7ae233ee9 100644 --- a/test/recipes/80-test_cmsapi.t +++ b/test/recipes/80-test_cmsapi.t @@ -20,5 +20,6 @@ ok(run(test(["cmsapitest", srctop_file("test", "certs", "servercert.pem"), srctop_file("test", "certs", "serverkey.pem"), srctop_file("test", "recipes", "80-test_cmsapi_data", "encryptedData.der"), srctop_file("test", "recipes", "80-test_cmsapi_data", "encDataWithTooLongIV.pem"), - srctop_file("test", "recipes", "80-test_cmsapi_data", "cms_pwri_kek_oob.der")])), + srctop_file("test", "recipes", "80-test_cmsapi_data", "cms_pwri_kek_oob.der"), + srctop_file("test", "smime-certs", "smec1.pem")])), "running cmsapitest"); diff --git a/test/recipes/80-test_ssl_new.t b/test/recipes/80-test_ssl_new.t index 44c674e46753d..44183f6756f09 100644 --- a/test/recipes/80-test_ssl_new.t +++ b/test/recipes/80-test_ssl_new.t @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2015-2025 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2015-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 @@ -42,7 +42,7 @@ if (defined $ENV{SSL_TESTS}) { @conf_srcs = glob(srctop_file("test", "ssl-tests", "*.cnf.in")); # We hard-code the number of tests to double-check that the globbing above # finds all files as expected. - plan tests => 31; + plan tests => 32; } map { s/;.*// } @conf_srcs if $^O eq "VMS"; my @conf_files = map { basename($_, ".in") } @conf_srcs; @@ -96,6 +96,7 @@ my %conf_dependent_tests = ( "28-seclevel.cnf" => disabled("tls1_2") || $no_ecx, "30-extended-master-secret.cnf" => disabled("tls1_2"), "32-compressed-certificate.cnf" => disabled("comp") || disabled("tls1_3"), + "33-compressed-spki.cnf" => disabled("tls1_2") || disabled("tls1_3") || $no_ec, ); # Add your test here if it should be skipped for some compile-time @@ -131,6 +132,7 @@ my %skip = ( "26-tls13_client_auth.cnf" => disabled("tls1_3") || ($no_ec && $no_dh), "29-dtls-sctp-label-bug.cnf" => disabled("sctp") || disabled("sock"), "32-compressed-certificate.cnf" => disabled("comp") || disabled("tls1_3"), + "33-compressed-spki.cnf" => disabled("tls1_2") || disabled("tls1_3") || $no_ec, ); foreach my $conf (@conf_files) { diff --git a/test/rio_poll_builder_test.c b/test/rio_poll_builder_test.c new file mode 100644 index 0000000000000..f4acb7b9c20ba --- /dev/null +++ b/test/rio_poll_builder_test.c @@ -0,0 +1,45 @@ +/* + * 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 "../ssl/rio/poll_builder.h" +#include "testutil.h" + +static int test_duplicate_fd(void) +{ +#if RIO_POLL_METHOD == RIO_POLL_METHOD_POLL + RIO_POLL_BUILDER rpb; + struct pollfd *pfds; + int ret = 0; + + if (!TEST_true(ossl_rio_poll_builder_init(&rpb))) + return 0; + + if (!TEST_true(ossl_rio_poll_builder_add_fd(&rpb, 0, 1, 0)) + || !TEST_true(ossl_rio_poll_builder_add_fd(&rpb, 0, 0, 1))) + goto out; + + pfds = rpb.pfd_heap != NULL ? rpb.pfd_heap : rpb.pfds; + if (!TEST_size_t_eq(rpb.pfd_num, 1) + || !TEST_int_eq(pfds[0].events, POLLIN | POLLOUT)) + goto out; + + ret = 1; +out: + ossl_rio_poll_builder_cleanup(&rpb); + return ret; +#else + return TEST_skip("poll() backend is not in use"); +#endif +} + +int setup_tests(void) +{ + ADD_TEST(test_duplicate_fd); + return 1; +} diff --git a/test/rpktest.c b/test/rpktest.c index 338c33f80cb5b..f81a60c2f6411 100644 --- a/test/rpktest.c +++ b/test/rpktest.c @@ -1,5 +1,5 @@ /* - * Copyright 2023-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2023-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -38,6 +38,37 @@ static OSSL_PROVIDER *defctxnull = NULL; static const unsigned char cert_type_rpk[] = { TLSEXT_cert_type_rpk, TLSEXT_cert_type_x509 }; static const unsigned char SID_CTX[] = { 'r', 'p', 'k' }; +/* + * Wire form of a SignatureSchemeList that lists rsa_pkcs1_sha256 + * and ed448 -- between them they cover the issuer signature on + * every cert this file loads from test/certs + * (sha256WithRSAEncryption for the RSA/ECDSA/Ed25519 leaves and + * ED448 for the Ed448 leaf), so the extension is harmless when + * the handshake is non-RPK and the server's check_cert_usable() + * has to walk the list against a real cert. When RPK is + * negotiated check_cert_usable() returns early without inspecting + * the list, and when the slot is an RPK-listed key-only slot but + * X509 was negotiated check_cert_usable() returns 0 on the x == + * NULL path -- the inevitable outcome, now discovered earlier. + * + * Payload: length, rsa_pkcs1_sha256, ed448 + */ +static const unsigned char sigalgs_cert_payload[] = { + 0x00, 0x04, + 0x04, 0x01, + 0x08, 0x08 +}; + +static int sigalgs_cert_add_cb(SSL *s, unsigned int ext_type, + unsigned int context, + const unsigned char **out, size_t *outlen, + X509 *x, size_t chainidx, int *al, void *add_arg) +{ + *out = sigalgs_cert_payload; + *outlen = sizeof(sigalgs_cert_payload); + return 1; +} + static int rpk_verify_client_cb(int ok, X509_STORE_CTX *ctx) { int err = X509_STORE_CTX_get_error(ctx); @@ -255,18 +286,43 @@ static int test_rpk(int idx) /* NEW */ SSL_CTX_set_verify(cctx, SSL_VERIFY_PEER, rpk_verify_client_cb); - if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, - NULL, NULL))) + /* + * Send signature_algorithms_cert in every ClientHello, and in + * every TLS 1.3 CertificateRequest. The OpenSSL stack doesn't + * construct this extension by default in either direction, so + * register a custom add hook on both ends. This exercises the + * three distinct paths through check_cert_usable() on whichever + * side receives the extension: + * - RPK was negotiated for this side's cert -- early return 1, + * list contents ignored. + * - RPK was offered but X509 was negotiated and this side's + * slot holds only a private key -- x == NULL, return 0 + * (any peer-sent signature_algorithms_cert against a key-only + * slot would otherwise trigger a crash). + * - X509 negotiated with a real cert -- walk the list, find + * a match against the issuer's signature algorithm. + * The server's registration only fires on TLS 1.3 connections + * where the server requests a client certificate (case 2, 9, + * 10 etc.); on TLS 1.2 the sigalgs travel inside the + * CertificateRequest body, not as a separate extension. + */ + if (!TEST_true(SSL_CTX_add_custom_ext(cctx, + TLSEXT_TYPE_signature_algorithms_cert, + SSL_EXT_CLIENT_HELLO, + sigalgs_cert_add_cb, NULL, NULL, + NULL, NULL)) + || !TEST_true(SSL_CTX_add_custom_ext(sctx, + TLSEXT_TYPE_signature_algorithms_cert, + SSL_EXT_TLS1_3_CERTIFICATE_REQUEST, + sigalgs_cert_add_cb, NULL, NULL, + NULL, NULL)) + || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, + NULL, NULL)) + || !TEST_int_gt(SSL_dane_enable(serverssl, NULL), 0) + || !TEST_int_gt(SSL_dane_enable(clientssl, "example.com"), 0) + || !TEST_int_eq(SSL_use_PrivateKey_file(serverssl, privkey_file, SSL_FILETYPE_PEM), 1)) goto end; - if (!TEST_int_gt(SSL_dane_enable(serverssl, NULL), 0)) - goto end; - if (!TEST_int_gt(SSL_dane_enable(clientssl, "example.com"), 0)) - goto end; - - /* Set private key and certificate */ - if (!TEST_int_eq(SSL_use_PrivateKey_file(serverssl, privkey_file, SSL_FILETYPE_PEM), 1)) - goto end; /* Only a private key */ if (idx == 1) { if (idx_server_server_rpk == 0 || idx_client_server_rpk == 0) { diff --git a/test/secmemtest.c b/test/secmemtest.c index 05b0bbc85796d..8bac1be2eca0b 100644 --- a/test/secmemtest.c +++ b/test/secmemtest.c @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2015-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 @@ -81,7 +81,7 @@ static int test_sec_mem(void) * If init fails, then initialized should be false, if not, this * could cause an infinite loop secure_malloc, but we don't test it */ - if (TEST_false(CRYPTO_secure_malloc_init(16, 16)) && !TEST_false(CRYPTO_secure_malloc_initialized())) { + if (!TEST_true(CRYPTO_secure_malloc_init(16, 16)) && !TEST_false(CRYPTO_secure_malloc_initialized())) { TEST_true(CRYPTO_secure_malloc_done()); goto end; } diff --git a/test/ssl-tests/33-compressed-spki.cnf b/test/ssl-tests/33-compressed-spki.cnf new file mode 100644 index 0000000000000..fd9816a27ef5d --- /dev/null +++ b/test/ssl-tests/33-compressed-spki.cnf @@ -0,0 +1,76 @@ +# Generated with generate_ssl_tests.pl + +num_tests = 2 + +test-0 = 0-tls12-compressed-spki +test-1 = 1-tls13-compressed-spki +# =========================================================== + +[0-tls12-compressed-spki] +ssl_conf = 0-tls12-compressed-spki-ssl + +[0-tls12-compressed-spki-ssl] +server = 0-tls12-compressed-spki-server +client = 0-tls12-compressed-spki-client + +[0-tls12-compressed-spki-server] +Certificate = ${ENV::TEST_CERTS_DIR}/server-ec-compressed-cert.pem +CipherString = DEFAULT +ClientCAFile = ${ENV::TEST_CERTS_DIR}/p384-root.pem +MaxProtocol = TLSv1.2 +MinProtocol = TLSv1.2 +PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ec-compressed-key.pem +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/p384-root.pem +VerifyMode = Require + +[0-tls12-compressed-spki-client] +Certificate = ${ENV::TEST_CERTS_DIR}/server-ec-compressed-cert.pem +CipherString = ECDHE-ECDSA-AES128-GCM-SHA256 +MaxProtocol = TLSv1.2 +MinProtocol = TLSv1.2 +PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ec-compressed-key.pem +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/p384-root.pem +VerifyMode = Peer + +[test-0] +ExpectedClientCertType = P-256 +ExpectedProtocol = TLSv1.2 +ExpectedResult = Success +ExpectedServerCertType = P-256 + + +# =========================================================== + +[1-tls13-compressed-spki] +ssl_conf = 1-tls13-compressed-spki-ssl + +[1-tls13-compressed-spki-ssl] +server = 1-tls13-compressed-spki-server +client = 1-tls13-compressed-spki-client + +[1-tls13-compressed-spki-server] +Certificate = ${ENV::TEST_CERTS_DIR}/server-ec-compressed-cert.pem +CipherString = DEFAULT +ClientCAFile = ${ENV::TEST_CERTS_DIR}/p384-root.pem +MaxProtocol = TLSv1.3 +MinProtocol = TLSv1.3 +PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ec-compressed-key.pem +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/p384-root.pem +VerifyMode = Require + +[1-tls13-compressed-spki-client] +Certificate = ${ENV::TEST_CERTS_DIR}/server-ec-compressed-cert.pem +CipherString = DEFAULT +MaxProtocol = TLSv1.3 +MinProtocol = TLSv1.3 +PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ec-compressed-key.pem +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/p384-root.pem +VerifyMode = Peer + +[test-1] +ExpectedClientCertType = P-256 +ExpectedProtocol = TLSv1.3 +ExpectedResult = Success +ExpectedServerCertType = P-256 + + diff --git a/test/ssl-tests/33-compressed-spki.cnf.in b/test/ssl-tests/33-compressed-spki.cnf.in new file mode 100644 index 0000000000000..06302a46a99ed --- /dev/null +++ b/test/ssl-tests/33-compressed-spki.cnf.in @@ -0,0 +1,81 @@ +# -*- mode: perl; -*- +# 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 + + +## End-to-end check that compressed-form EC leaf certificates +## (server-ec-compressed-cert.pem, P-256 named curve, SPKI bit-string +## leading byte 0x02 or 0x03, anchored to the P-384 EC root) work at +## both TLS 1.2 and TLS 1.3 in both directions: the client presents +## the same compressed leaf to a server that requires client +## authentication, exercising X.509 acceptance of compressed point +## form on both sides simultaneously. The ec_point_formats extension +## no longer affects X.509 cert selection or acceptance, so neither +## peer opts into LegacyECPointFormats; the default ec_point_formats +## lists ('uncompressed' only) and the compressed leaves coexist. + +package ssltests; +use OpenSSL::Test::Utils; + +our @tests = (); + +unless (disabled("ec") || disabled("tls1_2") || disabled("tls1_3")) { +@tests = ( + { + name => "tls12-compressed-spki", + server => { + "Certificate" => test_pem("server-ec-compressed-cert.pem"), + "PrivateKey" => test_pem("server-ec-compressed-key.pem"), + "VerifyCAFile" => test_pem("p384-root.pem"), + "ClientCAFile" => test_pem("p384-root.pem"), + "VerifyMode" => "Require", + "MinProtocol" => "TLSv1.2", + "MaxProtocol" => "TLSv1.2", + }, + client => { + "Certificate" => test_pem("server-ec-compressed-cert.pem"), + "PrivateKey" => test_pem("server-ec-compressed-key.pem"), + "VerifyCAFile" => test_pem("p384-root.pem"), + "MinProtocol" => "TLSv1.2", + "MaxProtocol" => "TLSv1.2", + "CipherString" => "ECDHE-ECDSA-AES128-GCM-SHA256", + }, + test => { + "ExpectedResult" => "Success", + "ExpectedProtocol" => "TLSv1.2", + "ExpectedServerCertType" => "P-256", + "ExpectedClientCertType" => "P-256", + }, + }, + + { + name => "tls13-compressed-spki", + server => { + "Certificate" => test_pem("server-ec-compressed-cert.pem"), + "PrivateKey" => test_pem("server-ec-compressed-key.pem"), + "VerifyCAFile" => test_pem("p384-root.pem"), + "ClientCAFile" => test_pem("p384-root.pem"), + "VerifyMode" => "Require", + "MinProtocol" => "TLSv1.3", + "MaxProtocol" => "TLSv1.3", + }, + client => { + "Certificate" => test_pem("server-ec-compressed-cert.pem"), + "PrivateKey" => test_pem("server-ec-compressed-key.pem"), + "VerifyCAFile" => test_pem("p384-root.pem"), + "MinProtocol" => "TLSv1.3", + "MaxProtocol" => "TLSv1.3", + }, + test => { + "ExpectedResult" => "Success", + "ExpectedProtocol" => "TLSv1.3", + "ExpectedServerCertType" => "P-256", + "ExpectedClientCertType" => "P-256", + }, + }, +); +} diff --git a/test/sslapitest.c b/test/sslapitest.c index 0cdeb473cdfba..ece9a59c822a4 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10821,12 +10821,29 @@ static int test_pluggable_signature(int idx) #endif #ifndef OPENSSL_NO_TLS1_2 + +#define CERT_TYPE_C "\x0" /* TLSEXT_cert_type_x509 */ +#define CERT_TYPE_S "\x2" /* TLSEXT_cert_type_rpk */ + +#ifndef OPENSSL_NO_CT +#define CB_ARG "callback arg" + +/* ARGSUSED */ +static int validation_cbk(const CT_POLICY_EVAL_CTX *ctx, + const STACK_OF(SCT) *scts, void *arg) +{ + return 1; +} +#endif + static int test_ssl_dup(void) { SSL_CTX *cctx = NULL, *sctx = NULL; SSL *clientssl = NULL, *serverssl = NULL, *client2ssl = NULL; int testresult = 0; BIO *rbio = NULL, *wbio = NULL; + unsigned char *ctype; + size_t ctype_len; if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), TLS_client_method(), @@ -10843,6 +10860,27 @@ static int test_ssl_dup(void) || !TEST_true(SSL_set_max_proto_version(clientssl, TLS1_2_VERSION))) goto end; + if (!TEST_true( + SSL_set1_client_cert_type(clientssl, + (const unsigned char *)CERT_TYPE_C, sizeof(CERT_TYPE_C) - 1))) + goto end; + + if (!TEST_true( + SSL_set1_server_cert_type(clientssl, + (const unsigned char *)CERT_TYPE_S, sizeof(CERT_TYPE_S) - 1))) + goto end; + +#ifndef OPENSSL_NO_CT + if (!TEST_true(SSL_set_ct_validation_callback(clientssl, validation_cbk, CB_ARG))) + goto end; +#endif + +#ifndef OPENSSL_NO_OCSP + if (!TEST_true( + SSL_set_tlsext_status_type(clientssl, TLSEXT_STATUSTYPE_ocsp))) + goto end; +#endif + client2ssl = SSL_dup(clientssl); rbio = SSL_get_rbio(clientssl); if (!TEST_ptr(rbio) @@ -10869,6 +10907,28 @@ static int test_ssl_dup(void) if (!TEST_true(create_ssl_connection(serverssl, client2ssl, SSL_ERROR_NONE))) goto end; + if (!TEST_true(SSL_get0_client_cert_type(client2ssl, &ctype, &ctype_len))) + goto end; + + if (!TEST_mem_eq(ctype, ctype_len, CERT_TYPE_C, sizeof(CERT_TYPE_C) - 1)) + goto end; + + if (!TEST_true(SSL_get0_server_cert_type(client2ssl, &ctype, &ctype_len))) + goto end; + + if (!TEST_mem_eq(ctype, ctype_len, CERT_TYPE_S, sizeof(CERT_TYPE_S) - 1)) + goto end; + +#ifndef OPENSSL_NO_CT + if (!TEST_true(SSL_ct_is_enabled(client2ssl))) + goto end; +#endif + +#ifndef OPENSSL_NO_OCSP + if (!TEST_long_eq(SSL_get_tlsext_status_type(client2ssl), TLSEXT_STATUSTYPE_ocsp)) + goto end; +#endif + SSL_free(clientssl); clientssl = SSL_dup(client2ssl); if (!TEST_ptr(clientssl) @@ -11965,6 +12025,51 @@ static int test_tls13_record_padding(int idx) SSL_CTX_free(cctx); return testresult; } + +static int un_ext_add_cb(SSL *s, unsigned int ext_type, + unsigned int context, const unsigned char **out, size_t *outlen, X509 *x, + size_t chainidx, int *al, void *add_arg) +{ + static const unsigned char data[] = { 0xaa }; + *out = data; + *outlen = sizeof(data); + return 1; +} + +static int un_ext_parse_cb(SSL *s, unsigned int ext_type, + unsigned int context, const unsigned char *in, size_t inlen, X509 *x, + size_t chainidx, int *al, void *parse_arg) +{ + return 1; +} + +/* + * Test that a handshake succeeds when the peer sends an extension type we do + * not recognise. The client registers a custom extension in its ClientHello + * that the server knows nothing about, so on the server tls_collect_extensions() + * takes the "unknown extension" branch. + */ +static int test_tls13_unknown_extension(void) +{ + SSL_CTX *s = NULL, *c = NULL; + SSL *s_ssl = NULL, *c_ssl = NULL; + int test; + + test = TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), + TLS_client_method(), TLS1_3_VERSION, TLS1_3_VERSION, &s, &c, cert, privkey)) + && TEST_true(SSL_CTX_add_custom_ext(c, 0xfefe, SSL_EXT_CLIENT_HELLO, + un_ext_add_cb, NULL, NULL, un_ext_parse_cb, NULL)) + && TEST_true(create_ssl_objects(s, c, &s_ssl, &c_ssl, NULL, NULL)) + /* The server must tolerate the unknown extension and complete. */ + && TEST_true(create_ssl_connection(s_ssl, c_ssl, SSL_ERROR_NONE)); + + SSL_free(s_ssl); + SSL_free(c_ssl); + SSL_CTX_free(s); + SSL_CTX_free(c); + return test; +} + #endif /* OSSL_NO_USABLE_TLS1_3 */ #if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_DYNAMIC_ENGINE) @@ -12576,6 +12681,70 @@ static int test_data_retry(void) return testresult; } +/* + * Test that a BIO returning 0 without a retry flag for a write with a positive + * length is not treated as a successful write. + */ +static int test_data_write_zero_no_retry(int tst) +{ + SSL_CTX *cctx = NULL, *sctx = NULL; + SSL *clientssl = NULL, *serverssl = NULL; + BIO *bzero = BIO_new(bio_s_no_retry_zero()); + const SSL_METHOD *smeth = TLS_server_method(); + const SSL_METHOD *cmeth = TLS_client_method(); + unsigned char inbuf[1] = { 0 }; + size_t written; + unsigned long errcode; + int err, min_version = 0, max_version = 0, testresult = 0; + + if (tst == 1) { +#if !defined(OPENSSL_NO_DTLS) && !defined(OPENSSL_NO_DTLS1_2) + smeth = DTLS_server_method(); + cmeth = DTLS_client_method(); + min_version = max_version = DTLS1_2_VERSION; +#else + BIO_free(bzero); + return TEST_skip("DTLS 1.2 not supported"); +#endif + } + + if (!TEST_ptr(bzero)) + goto end; + + if (!TEST_true(create_ssl_ctx_pair(libctx, smeth, cmeth, min_version, + max_version, &sctx, &cctx, cert, privkey))) + goto end; + + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, + NULL))) + goto end; + + if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) + goto end; + + SSL_set0_wbio(clientssl, bzero); + bzero = NULL; + + ERR_clear_error(); + if (!TEST_false(SSL_write_ex(clientssl, inbuf, sizeof(inbuf), &written))) + goto end; + + err = SSL_get_error(clientssl, 0); + errcode = ERR_get_error(); + if (!TEST_int_eq(err, SSL_ERROR_SYSCALL) + || !TEST_ulong_eq(errcode, 0)) + goto end; + + testresult = 1; +end: + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + BIO_free_all(bzero); + return testresult; +} + struct resume_servername_cb_data { int i; SSL_CTX *cctx; @@ -14312,6 +14481,7 @@ int setup_tests(void) #ifndef OSSL_NO_USABLE_TLS1_3 ADD_TEST(test_read_ahead_key_change); ADD_ALL_TESTS(test_tls13_record_padding, 6); + ADD_TEST(test_tls13_unknown_extension); #endif #if !defined(OPENSSL_NO_TLS1_2) && !defined(OSSL_NO_USABLE_TLS1_3) ADD_ALL_TESTS(test_serverinfo_custom, 4); @@ -14323,6 +14493,7 @@ int setup_tests(void) ADD_TEST(test_rstate_string); ADD_ALL_TESTS(test_handshake_retry, 16); ADD_TEST(test_data_retry); + ADD_ALL_TESTS(test_data_write_zero_no_retry, 2); ADD_ALL_TESTS(test_multi_resume, 5); ADD_ALL_TESTS(test_select_next_proto, OSSL_NELEM(next_proto_tests)); #if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_NEXTPROTONEG) @@ -14370,6 +14541,7 @@ void cleanup_tests(void) bio_s_mempacket_test_free(); bio_s_always_retry_free(); bio_s_maybe_retry_free(); + bio_s_no_retry_zero_free(); OSSL_PROVIDER_unload(defctxnull); OSSL_LIB_CTX_free(libctx); } diff --git a/test/x509_test.c b/test/x509_test.c index 37928c5f008fe..62e7de79a818d 100644 --- a/test/x509_test.c +++ b/test/x509_test.c @@ -10,6 +10,7 @@ #define OPENSSL_SUPPRESS_DEPRECATED /* EVP_PKEY_get1/set1_RSA */ #include +#include #include #include #include @@ -299,6 +300,101 @@ static int test_x509_revoked_delete_last_extension(void) return ret; } +/* + * nameConstraints extnValue contents with one empty directoryName subtree. + * Empty X509_NAME has canon_enc == NULL / canon_enclen == 0. + * + * SEQUENCE { [0|1] { SEQUENCE { [4] { SEQUENCE {} } } } } + */ +static const unsigned char nc_excluded_empty_dirname[] = { + 0x30, 0x08, 0xa1, 0x06, 0x30, 0x04, 0xa4, 0x02, 0x30, 0x00 +}; +static const unsigned char nc_permitted_empty_dirname[] = { + 0x30, 0x08, 0xa0, 0x06, 0x30, 0x04, 0xa4, 0x02, 0x30, 0x00 +}; + +/* Decode a raw nameConstraints extnValue into a NAME_CONSTRAINTS object. */ +static NAME_CONSTRAINTS *nc_empty_dirname_from_der(const unsigned char *der, + unsigned int der_len) +{ + NAME_CONSTRAINTS *nc = NULL; + ASN1_OCTET_STRING *os = NULL; + X509_EXTENSION *ext = NULL; + + os = ASN1_OCTET_STRING_new(); + if (!TEST_ptr(os) + || !TEST_true(ASN1_OCTET_STRING_set(os, der, der_len))) + goto end; + ext = X509_EXTENSION_create_by_NID(NULL, NID_name_constraints, + 1 /* critical */, os); + if (!TEST_ptr(ext)) + goto end; + nc = X509V3_EXT_d2i(ext); + +end: + X509_EXTENSION_free(ext); + ASN1_OCTET_STRING_free(os); + return nc; +} + +/* Build a minimal certificate with a non-empty subject DN. */ +static X509 *nc_empty_dirname_subject(const char *cn) +{ + X509 *x = NULL; + X509_NAME *nm = NULL; + + if (!TEST_ptr(x = X509_new())) + goto err; + nm = X509_NAME_new(); + if (!TEST_ptr(nm) + || !TEST_true(X509_NAME_add_entry_by_txt(nm, "CN", MBSTRING_ASC, + (const unsigned char *)cn, -1, -1, 0)) + || !TEST_true(X509_set_subject_name(x, nm))) + goto err; + X509_NAME_free(nm); + return x; + +err: + X509_NAME_free(nm); + X509_free(x); + return NULL; +} + +/* Check an empty directoryName constraint against a non-empty subject DN. */ +static int nc_check_empty_dirname(const unsigned char *der, unsigned int der_len, + int expected) +{ + int ok = 0; + NAME_CONSTRAINTS *nc = NULL; + X509 *x = NULL; + + if (!TEST_ptr(nc = nc_empty_dirname_from_der(der, der_len)) + || !TEST_ptr(x = nc_empty_dirname_subject("leaf.example")) + || !TEST_int_eq(NAME_CONSTRAINTS_check(x, nc), expected)) + goto end; + + ok = 1; + +end: + X509_free(x); + NAME_CONSTRAINTS_free(nc); + return ok; +} + +/* Empty excluded directoryName matches the subject DN: excluded violation. */ +static int test_nc_empty_dirname_excluded(void) +{ + return nc_check_empty_dirname(nc_excluded_empty_dirname, + sizeof(nc_excluded_empty_dirname), X509_V_ERR_EXCLUDED_VIOLATION); +} + +/* Empty permitted directoryName matches the subject DN: permitted. */ +static int test_nc_empty_dirname_permitted(void) +{ + return nc_check_empty_dirname(nc_permitted_empty_dirname, + sizeof(nc_permitted_empty_dirname), X509_V_OK); +} + OPT_TEST_DECLARE_USAGE("\n") int setup_tests(void) @@ -337,6 +433,8 @@ int setup_tests(void) ADD_TEST(test_x509_crl_delete_last_extension); ADD_TEST(test_x509_revoked_delete_last_extension); ADD_TEST(test_x509_verify_with_new); + ADD_TEST(test_nc_empty_dirname_excluded); + ADD_TEST(test_nc_empty_dirname_permitted); return 1; } diff --git a/tlsfuzzer b/tlsfuzzer deleted file mode 160000 index 61f45d9701294..0000000000000 --- a/tlsfuzzer +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 61f45d9701294fd87ef92d2a7e3dfb076653a562 diff --git a/tlslite-ng b/tlslite-ng deleted file mode 160000 index 77ef321dde1a9..0000000000000 --- a/tlslite-ng +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 77ef321dde1a9e6bcf94d73c80f8789a770d8031 diff --git a/util/missingcrypto.txt b/util/missingcrypto.txt index 16ca0e49dfa0c..ad0f165fa6ba6 100644 --- a/util/missingcrypto.txt +++ b/util/missingcrypto.txt @@ -590,8 +590,6 @@ LONG_it(3) MD2_options(3) MD4_Transform(3) MD5_Transform(3) -NAME_CONSTRAINTS_check(3) -NAME_CONSTRAINTS_check_CN(3) NAME_CONSTRAINTS_it(3) NAMING_AUTHORITY_it(3) NCONF_WIN32(3) diff --git a/util/other.syms b/util/other.syms index ba188d46c7960..0bb7b92bd69bf 100644 --- a/util/other.syms +++ b/util/other.syms @@ -2,10 +2,12 @@ # that don't appear in lib*.num -- because they are define's, in # assembly language, etc. # +OPENSSL_armcap environment OPENSSL_ia32cap environment OPENSSL_ppccap environment -OPENSSL_s390xcap environment OPENSSL_riscvcap environment +OPENSSL_s390xcap environment +OPENSSL_sparcv9cap environment OPENSSL_MALLOC_FD environment OPENSSL_MALLOC_FAILURES environment OPENSSL_instrument_bus assembler @@ -783,6 +785,7 @@ SSL_VALUE_CLASS_FEATURE_REQUEST define SSL_VALUE_CLASS_FEATURE_PEER_REQUEST define SSL_VALUE_CLASS_FEATURE_NEGOTIATED define SSL_VALUE_QUIC_IDLE_TIMEOUT define +SSL_VALUE_QUIC_MAX_PENDING_CONNS define SSL_VALUE_QUIC_STREAM_BIDI_LOCAL_AVAIL define SSL_VALUE_QUIC_STREAM_BIDI_REMOTE_AVAIL define SSL_VALUE_QUIC_STREAM_UNI_LOCAL_AVAIL define diff --git a/util/perl/TLSProxy/Proxy.pm b/util/perl/TLSProxy/Proxy.pm index c3db4e28db0f8..729b351b3f0af 100644 --- a/util/perl/TLSProxy/Proxy.pm +++ b/util/perl/TLSProxy/Proxy.pm @@ -1,4 +1,4 @@ -# Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2016-2026 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -177,6 +177,7 @@ sub init server_port => 0, serverpid => 0, clientpid => 0, + clientexit => 0, execute => $execute, cert => $cert, debug => $debug, @@ -215,6 +216,7 @@ sub clearClient $self->{clientflags} = ""; $self->{sessionfile} = undef; $self->{clientpid} = 0; + $self->{clientexit} = 0; $is_tls13 = 0; $ciphersuite = undef; @@ -585,6 +587,7 @@ sub clientstart $pid = $self->{clientpid}; print "Waiting for s_client process to close: $pid...\n"; waitpid($pid, 0); + $self->{clientexit} = $?; return $success; } @@ -722,6 +725,11 @@ sub clientpid my $self = shift; return $self->{clientpid}; } +sub clientexit +{ + my $self = shift; + return $self->{clientexit}; +} #Read/write accessors sub filter diff --git a/wycheproof b/wycheproof deleted file mode 160000 index 2196000605e45..0000000000000 --- a/wycheproof +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2196000605e45d91097147c9c71f26b72af58003