Bug#1140227: apt: HTTPS acquire fails under OpenSSL FIPS-only mode (missing ERR_clear_error before SSL_read/write)
Julian Andres Klode <[email protected]> Fri, 19 Jun 2026 09:37:09 +0200
| Newsgroups | gmane.linux.debian.apt.devel |
|---|---|
| Message-ID | <20260619093301.GA105152__13383.3507121139$1781854778$gmane$org@debian.org> |
Control: reassign -1 openssl
On Wed, Jun 17, 2026 at 09:00:09AM -0400, Michael Hamill wrote:
> Package: apt
> Version: 3.0.3
> Severity: important
>
> Dear Maintainer,
>
> With OpenSSL configured in FIPS-only mode (only the "base" and "fips"
> providers
> active; the "default" provider disabled), "apt-get update"/"install"
> against an
> HTTPS repository intermittently fails with:
>
> Err:N https://...repo...
> OpenSSL error: error:0308010C:digital envelope routines::unsupported
> Error reading from server - read (5: Input/output error)
>
> Root cause
> ----------
> During the TLS handshake, libssl performs an implicit EVP_MD_fetch() for the
> legacy MD5 / MD5-SHA1 digests (used for pre-TLS-1.2 handshake signing and
> the
> TLS 1.0/1.1 PRF). Under a FIPS-only provider configuration those digests are
> unavailable (they exist only in the default provider), so the fetch fails
> and
> leaves "error:0308010C ... unsupported" on the thread's OpenSSL error queue.
>
> This is benign: the handshake completes fine. "openssl s_client" to the same
> host under the identical FIPS config connects successfully with the very
> same
> failed MD5/MD5-SHA1 fetches (verifiable with an LD_PRELOAD trace of
> EVP_MD_fetch).
>
> The actual failure is that apt does not clear the OpenSSL error queue
> before its
> TLS I/O. In methods/connect.cc, TlsFd::Read() and TlsFd::Write() call
> SSL_read()/SSL_write() and then HandleError() -> SSL_get_error() WITHOUT a
> preceding ERR_clear_error(). When SSL_read() later returns <= 0 for a benign
> reason, SSL_get_error() consults the non-empty error queue, returns
> SSL_ERROR_SSL, and apt reports the stale MD5 error as a fatal read failure
> (errno = EIO -> "Error reading from server").
>
> This violates the documented precondition in SSL_get_error(3): "The current
> thread's error queue must be empty before the TLS/SSL I/O operation is
> attempted, [...] as the SSL_get_error() function uses the error queue
> [...]."
>
> PostgreSQL fixed the identical class of bug (stale FIPS-mode error-queue
> entry
> misreported later) by calling ERR_clear_error() "on the way in"; libpq
> already
> does this around its OpenSSL I/O.
>
> This did not occur before Debian 13 / apt 3.0: apt 2.6 (bookworm) used
> GnuTLS
> for its TLS transport, which does not touch OpenSSL's providers or error
> queue.
>
> Reproduction (Debian 13)
> ------------------------------
> Minimal, self-contained Dockerfile. The build itself fails at the final RUN
> (installing Docker from an HTTPS repo) -- "docker build ." is the whole
> repro:
>
> FROM debian:13-slim
> SHELL ["/bin/bash", "-o", "pipefail", "-c"]
>
> # FIPS-only OpenSSL: install the FIPS provider, then activate base +
> fips and
> # disable the default provider.
> RUN apt-get update --yes \
> && apt-get install --yes --no-install-recommends \
> ca-certificates openssl openssl-provider-fips \
> && MODULES_DIR="$(openssl version -m | cut -d'"' -f2)" \
> && openssl fipsinstall -out /etc/ssl/fipsmodule.cnf -module
> "${MODULES_DIR}/fips.so"
> RUN sed -i 's|^#\s*\.include\s\+fipsmodule.cnf|.include
> /etc/ssl/fipsmodule.cnf|' /etc/ssl/openssl.cnf \
> && sed -i 's/^default\s*=\s*default_sect/# default = default_sect/'
> /etc/ssl/openssl.cnf \
> && sed -i 's/^#\s*fips\s*=\s*fips_sect/fips = fips_sect\nbase =
> base_sect\n\n[base_sect]\nactivate = 1/' /etc/ssl/openssl.cnf
> # ("openssl list -providers" now shows only base + fips.)
>
> # Install Docker from its official HTTPS apt repo (any HTTPS repo
> triggers it;
> # this is just a convenient public one). This RUN fails:
> # OpenSSL error: error:0308010C ... Error reading from server
> # E: Package 'docker-ce' has no installation candidate
> RUN apt-get install --no-install-recommends -y ca-certificates curl
> gnupg \
> && install -m 0755 -d /etc/apt/keyrings \
> && curl -fsSL https://download.docker.com/linux/debian/gpg | gpg
> --dearmor -o /etc/apt/keyrings/docker.gpg \
> && echo "deb [signed-by=/etc/apt/keyrings/docker.gpg]
> https://download.docker.com/linux/debian trixie stable" \
> > /etc/apt/sources.list.d/docker.list \
> && apt-get update \
> && apt-get install --no-install-recommends -y docker-ce docker-ce-cli
> containerd.io
>
> Build it:
>
> docker build .
>
> The build fails at the final RUN with the error:0308010C / "Error reading
> from
> server" message above. (The underlying trigger is a read returning <= 0
> while
> the stale error is queued, so in principle a fluke pass is possible; in
> practice
> fetching the Docker repo over HTTPS this way fails on essentially every
> build,
> matching what we see in CI. If a build does pass, rebuild with --no-cache.)
>
> For contrast, the connection itself is fine and the failed MD5 fetch is
> benign --
> both of these succeed under the identical FIPS config:
>
> # same handshake, succeeds, proving MD5 is not actually needed:
> openssl s_client -connect download.docker.com:443 -servername
> download.docker.com </dev/null
> # and apt works if the default provider is made available:
> OPENSSL_CONF=/dev/null apt-get update # (with the docker.list
> source above)
>
> System information
> ------------------
> Debian release: 13 (trixie), amd64
>
> Versions of relevant packages:
> apt 3.0.3
> libssl3t64 3.5.6-1~deb13u2 (OpenSSL; apt's TLS backend in 3.0)
> openssl 3.5.6-1~deb13u2
> libc6 2.41-12+deb13u3
>
> Reproduced in a stock debian:13-slim container (see Dockerfile above).
>
> Suggested fix
> -------------
> Clear the OpenSSL error queue immediately before each
> SSL_read()/SSL_write() in
> methods/connect.cc, mirroring libpq:
>
> ssize_t Read(void *buf, size_t count) override {
> assert(ssl);
> + ERR_clear_error();
> return HandleError(SSL_read(ssl, buf, count));
> }
> ssize_t Write(void *buf, size_t count) override {
> assert(ssl);
> + ERR_clear_error();
> return HandleError(SSL_write(ssl, buf, count));
> }
>
> This makes apt robust to any benign leftover OpenSSL error, not just the
> FIPS/MD5 case.
Thanks for your bug report.
This seems to be a bug in OpenSSL, and the proposed workaround is
wholly inappropriate. This also points out there is _another_ bug
somewhere, as we _should_ have raised this error _before_ we enter
the Read/Write functions.
You'll find you often need to patch OpenSSL to use it in a FIPS
setting, and relying on the packaged version is insufficient.
Thanks!
--
debian developer - deb.li/jak | jak-linux.org - free software dev
ubuntu core developer i speak de, en