Skip to content

[Web] Fix non-deterministic TLS bridge failures from non-minimal DER serial numbers - #3550

Merged
adamziel merged 2 commits into
trunkfrom
adamziel/curl-asn1-bridge
Apr 28, 2026
Merged

[Web] Fix non-deterministic TLS bridge failures from non-minimal DER serial numbers#3550
adamziel merged 2 commits into
trunkfrom
adamziel/curl-asn1-bridge

Conversation

@adamziel

@adamziel adamziel commented Apr 28, 2026

Copy link
Copy Markdown
Collaborator

What

The TLS-over-fetch bridge synthesizes X.509 certs in the browser so PHP's libcurl can talk to real HTTPS hosts through fetch(). The ASN.1 INTEGER encoder in certificates.ts was prepending a 0x00 byte when needed to keep a value positive, but it never stripped redundant leading 0x00 bytes — so the encoded serial number sometimes wasn't valid DER.

With a 4-byte random serial, about 1 session in 256 produced something like [0x00, 0x12, 0x34, 0x56], encoded as 02 04 00 12 34 56. That violates DER's minimal-length rule (X.690 §8.3.2), and OpenSSL refuses to parse the cert with:

error:0D0E20DD:asn1 encoding routines:c2i_ibuf:illegal padding

Once a session generated a bad cert, every HTTPS request through the bridge surfaced as cURL error (35) in PHP until the page was reloaded. The original report blamed wpcomstaging.com, but it was a coincidence — any host could trigger it.

Fix

In ASN1Encoder.integer(), strip leading 0x00 bytes whose successor has the high bit clear (they're unnecessary), then apply the existing high-bit prepend for sign disambiguation.

Test

A new case in certificates.spec.ts pins a serial number with the offending shape and round-trips the cert through openssl x509. Failed before the fix, passes after.

The TLS-over-fetch bridge synthesizes X.509 certs in the browser. The
ASN.1 INTEGER encoder prepended a 0x00 byte when needed to keep an
integer positive, but never stripped redundant leading 0x00 bytes.
With a 4-byte random serial number, roughly 1 session in 256 generated
a serial starting with 0x00 followed by a byte under 0x80 — invalid
DER per X.690 §8.3.2. OpenSSL bails out with "asn1 encoding
routines:c2i_ibuf:illegal padding", which surfaces in PHP as cURL
error 35 on every HTTPS request for the rest of the session. Strip
the unnecessary leading zeros before applying the existing sign-bit
prepend, and add a regression test that pins a problematic serial.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Fixes intermittent TLS bridge failures caused by invalid DER encoding of synthesized X.509 certificate serial numbers (non-minimal ASN.1 INTEGER encoding).

Changes:

  • Update ASN.1 INTEGER encoding to strip redundant leading 0x00 bytes while preserving positive sign encoding rules.
  • Add an integration-style regression test that generates a cert with an “offending” serial number and verifies OpenSSL can parse it.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
packages/php-wasm/web/src/lib/tls/certificates.ts Ensures DER-minimal INTEGER encoding for serial numbers by removing redundant leading zero padding.
packages/php-wasm/web/src/lib/tls/certificates.spec.ts Adds an OpenSSL round-trip regression test for the previously failing serial-number byte pattern.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/php-wasm/web/src/lib/tls/certificates.spec.ts Outdated
Comment thread packages/php-wasm/web/src/lib/tls/certificates.spec.ts
- Sync the inline comment in the new spec with the actual openssl command (-noout -serial).
@adamziel adamziel changed the title Fix random TLS bridge failures from non-minimal DER serial numbers Apr 28, 2026
@adamziel
adamziel merged commit d5e9d5f into trunk Apr 28, 2026
48 checks passed
@adamziel
adamziel deleted the adamziel/curl-asn1-bridge branch April 28, 2026 18:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment