Skip to content

The OpenSSL we ship is out of support, and its assembly cannot carry branch protection - #231

Merged
xroche merged 3 commits into
masterfrom
openssl-3.5-branch-protection
Sep 21, 2026
Merged

xroche merged 3 commits into
masterfrom
openssl-3.5-branch-protection

Conversation

@xroche

@xroche xroche commented Sep 21, 2026 •

Copy link
Copy Markdown
Owner

OpenSSL 3.0 has left support, so the statics we ship receive no more fixes. 3.5 is the current LTS.

The bump is also the only way to finish #229. That change gave arm64 pointer authentication and branch target identification, but libhttrack.so got landing pads and no .note.gnu.property. The linker ANDs that note over every input, and 3.0.15's assembly cannot carry one, because crypto/arm_arch.h gained BTI support only in 3.2.0. At 3.5.8 all 982 libcrypto.a members are marked, and libhttrack.so now reports BTI, PAC.

3.5 also raises the default TLS security level from 1 to 2, which the engine inherits because it never calls SSL_CTX_set_security_level. Level 2 refuses 1024-bit DH groups and SHA-1 signature algorithms, so crawls of old sites that work today would fail. -DOPENSSL_TLS_SECURITY_LEVEL=1 pins what 3.0.15 shipped, read back from the built libssl.a.

The version lived in four places. Two passed it to the script without the matching hash, so they would have checked 3.0.15 against 3.5.8's digest and failed. The script now owns the version alone. The OpenSSL cache keyed on the version too, so a new compile flag at an unchanged version would have restored a stale build. It keys on the recipe now.

Two gaps remain. The engine should set the security level itself, which belongs to the httrack repo. And 3.5 leads its group list with X25519MLKEM768, so the ClientHello grows past 1.4 KB and some old stacks mishandle that.

xroche and others added 2 commits September 21, 2026 21:31
OpenSSL 3.0 has left support, so the statics we ship receive no more fixes.
3.5 is the current LTS and is maintained to 2030.

The bump is also the only way to finish what #229 started. That change gave
arm64 pointer authentication and branch target identification, but
libhttrack.so came out with landing pads and no .note.gnu.property. The linker
ANDs that note over every input, and the OpenSSL statics carried none. 3.0.15
cannot carry one, because its crypto/arm_arch.h has no BTI or PAC support, so
no flag makes its assembly emit pads. Those macros arrived in 3.2.0.

I built both to check. At 3.0.15 with the flag, 859 of 872 libcrypto.a members
take the note, and the 13 without it are exactly the arm64 assembly. That is
enough to clear the note for the whole library. At 3.5.8 all 982 take it, the
engine still compiles and links, and libhttrack.so now reports BTI and PAC
with retaa still at 0.

x86_64 gets no control-flow flag, because lld drops the CET note on that
target, which #230 measured.

The image recipe now also builds on a pull request, without publishing. A
broken OpenSSL build used to reach master before anything ran it.

Signed-off-by: Xavier Roche <xroche@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
3.5 raises OPENSSL_TLS_SECURITY_LEVEL from 1 to 2, and ssl_cert.c reads that
macro to set each context's default. The engine never calls
SSL_CTX_set_security_level, so it inherits whatever the library shipped with.

Level 2 lifts the floor from 80 bits to 112. That refuses a 1024-bit DH group
and a SHA-1 signature algorithm, which servers untouched since Logjam still
offer. HTTrack exists to copy old sites, so the bump would have broken crawls
that work today. The certificate-side tightenings do not bite, because the
engine verifies no certificate by design, but these two checks run whatever
verify_mode says.

The macro sits behind an #ifndef, so -DOPENSSL_TLS_SECURITY_LEVEL=1 pins what
3.0.15 shipped. I read it back out of the built libssl.a. ssl_cert_new stores 1
with the define and 2 without it, at the same instruction. Branch protection is
unaffected, and all 982 libcrypto.a members still carry the note.

Pinning also stops the next bump moving it again. The engine should set the
level itself rather than inherit it, but that change belongs to the httrack
repo.

Signed-off-by: Xavier Roche <xroche@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@xroche
xroche enabled auto-merge (squash) September 21, 2026 19:39
android.yml and codeql.yml each set OPENSSL_VERSION and passed it to the script
without the matching OPENSSL_SHA256. After the bump they would have fetched
3.0.15 and checked it against 3.5.8's digest, so both jobs would fail. They now
pass no version at all and the script's default rules.

The cache key moves with them. It keyed on the version, so a new compile flag at
an unchanged version would have restored a stale OpenSSL and hidden the flag. It
now keys on a hash of the recipe, which the branch protection flag needs.

A version override that carries no hash is refused outright, because the default
hash belongs to the default version.

Signed-off-by: Xavier Roche <xroche@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@xroche
xroche merged commit eb133a3 into master Sep 21, 2026
7 checks passed
@xroche
xroche deleted the openssl-3.5-branch-protection branch September 21, 2026 20:03
xroche added a commit that referenced this pull request Sep 21, 2026
Two ways an arm64 library can lose its branch protection, both silent. A
library built without `-mbranch-protection` still loads and passes every
test. An `-march` bump to armv8.3-a turns the PAC hints into `retaa`,
which faults on an ARMv8.0 core.

On every arm64 `.so` the check wants no `retaa` or `retab`, one
`paciasp` in the instruction column, and one feature note naming BTI and
PAC. It refuses an empty walk, a directory it could not read, and a
failing tool, because each of those otherwise reads as a pass.

I ran it against real libraries on both sides. The ones built before
#231 fail on `libhttrack.so`, whose note the unmarked OpenSSL statics
cleared, and the ones built after it pass.

A real build only produces the passing case, so the test drives the
failures through stubs that copy the real tools' output, lowercase
`aarch64 feature` included. Six mutations of the checker each turn
exactly one case red.

The note assertion is right only now. Before #231 it was absent from a
correctly built `libhttrack.so`.

---------

Signed-off-by: Xavier Roche <xroche@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant