Skip to content

Bug 5558: Add AKI to client-first SslBump certificates - #2506

Open
ccijunk wants to merge 2 commits into
squid-cache:masterfrom
ccijunk:fix-client-first-bump-aki
Open

ccijunk wants to merge 2 commits into
squid-cache:masterfrom
ccijunk:fix-client-first-bump-aki

Conversation

@ccijunk

@ccijunk ccijunk commented Sep 24, 2026 •

Copy link
Copy Markdown

Summary

Certificates generated by SslBump in client-first mode carried
no Authority Key Identifier (AKI) extension:

  • mimicAuthorityKeyId() returned early whenever
    mimicCert was absent, and
  • its only caller sat inside the
    if (properties.mimicCert.get()) branch of
    buildCertificate().

In client-first bump Squid completes the client handshake
before contacting the origin, so properties.mimicCert is
null and the generated leaf had no AKI at all. Strict X.509
validators therefore reject every forged leaf on every bumped
connection, even though the chain is otherwise fully trusted:

  • Python 3.13+ with VERIFY_X509_STRICT (the default for
    conda 26+) fails the TLS handshake with Missing Authority Key Identifier;
  • openssl verify -x509_strict reports error 85 at 0 depth lookup: Missing Authority Key Identifier.

The failure is mode-dependent and therefore unintended: the
same proxy, signing CA and client produce a valid certificate
in server-first mode and an invalid one in client-first mode.

The origin certificate is not needed to build the extension.
The value of the keyIdentifier field is taken from
issuerCert; mimicCert only decided the shape (whether
to write keyIdentifier, and whether to also write
authorityCertIssuer plus authorityCertSerialNumber).
Per RFC 5280 section 4.2.1.1, the keyIdentifier field is
required in certificates generated by a conforming CA
(except for self-signed certificates), and that exception
does not apply because the signing CA has a Subject Key
Identifier.

Changes

  • Rename mimicAuthorityKeyId() to addAuthorityKeyId():
    Squid mimics the extension presence, but the extension
    value is always built from the signing CA rather than
    copied, so the old name was misleading.
  • Move the !addKeyId && !addIssuer check to the top level
    of the function so it covers all current and future paths.
  • Call mimicExtensions() unconditionally from
    buildCertificate() and make mimicExtensions() tolerate
    a nil mimicCert, instead of adding a second, conditional
    call site.
  • Fix the mimicExtensions() description comment (it
    said extensions were copied "from cert to
    mimicCert" - backwards).

The mimicking path behavior is unchanged: with mimicCert
present the same fields are read from the origin
certificate, the same early return applies, and the
value-construction section is untouched.

Testing

With a client-first bump configuration (ssl_bump bump step1):

  • openssl x509 -text on the captured leaf shows
    Authority Key Identifier: keyid:<signing CA's SKI>,
    matching the Subject Key Identifier of the CA certificate
  • openssl verify -x509_strict -CAfile squid-ca.pem leaf.pem returns OK
  • A Python 3.14 client using VERIFY_X509_STRICT
    completes the TLS handshake through the proxy
  • server-first mode output is unchanged (mimic path
    untouched)
  • Full source build (Ubuntu 22.04, gcc 11, OpenSSL 3.0)

Note: the AKI is the only extension that needs to be added -
the generated leaf still lacks key usage, extended key usage,
basic constraints and a Subject Key Identifier, and strict
validation does not object to any of those.

mimicAuthorityKeyId() returned early whenever mimicCert was absent, and its
only caller sat inside the "if (properties.mimicCert.get())" branch of
buildCertificate(). In client-first bump Squid completes the client
handshake before contacting the origin, so properties.mimicCert is null and
generated certificates carried no Authority Key Identifier at all.

RFC 5280 section 4.2.1.1 requires the keyIdentifier field in certificates
generated by a conforming CA (except for self-signed certificates), and
that exception does not apply because the signing CA has a Subject Key
Identifier. Strict validators therefore reject the forged leaves: Python
3.13+ with VERIFY_X509_STRICT fails the handshake, and
openssl verify -x509_strict reports
"error 85 at 0 depth lookup: Missing Authority Key Identifier".

The origin certificate is not needed to build the extension. The value of
the keyIdentifier field is taken from issuerCert; mimicCert only decided
the shape (whether to write keyIdentifier, and whether to also write
authorityCertIssuer plus authorityCertSerialNumber). This change:

* Renames mimicAuthorityKeyId() to addAuthorityKeyId() to reflect that the
  extension presence (not its value) is what gets mimicked; the value is
  always built from the signing CA.
* Moves the "!addKeyId && !addIssuer" check to the top level of the
  function so that it covers all current and future paths.
* Calls mimicExtensions() unconditionally from buildCertificate() and makes
  mimicExtensions() tolerate a nil mimicCert, instead of adding a second,
  conditional call site.
* Fixes the mimicExtensions() description comment.

The mimicking path behavior is unchanged: with mimicCert present the same
fields are read from the origin certificate, the same early return applies,
and the value-construction section is untouched.
@squid-anubis squid-anubis added the M-failed-description https://github.com/measurement-factory/anubis#pull-request-labels label Sep 24, 2026
@squid-anubis

This comment was marked as resolved.

@ccijunk ccijunk changed the title Add Authority Key Identifier to client-first SslBump certificates Add AKI to client-first SslBump certificates Sep 24, 2026
@squid-anubis

This comment was marked as resolved.

@squid-anubis

This comment was marked as resolved.

@squid-anubis squid-anubis removed the M-failed-description https://github.com/measurement-factory/anubis#pull-request-labels label Sep 24, 2026
Comment thread src/ssl/gadgets.cc Outdated
Comment thread src/ssl/gadgets.cc Outdated
Comment thread src/ssl/gadgets.cc Outdated
@rousskov
rousskov self-requested a review September 24, 2026 12:48
@rousskov

Copy link
Copy Markdown
Contributor

@ccijunk, thank you for sharing this fix! Please add yourself to the CONTRIBUTORS file as a part of this PR (or let us know if you prefer not to do that -- a manual action will be needed to bypass the corresponding CI check in that case).

P.S. No need to squash or rebase your PR branch as you add commits. PR commits will be squashed automatically when merging your PR.

@rousskov rousskov changed the title Add AKI to client-first SslBump certificates Bug 5558: Add AKI to client-first SslBump certificates Sep 24, 2026
Fold nid into the for-loop parameters instead of declaring it in an
enclosing scope, and use auto for the newly declared ext variable,
as requested in PR review.
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.

4 participants