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.

Michael Hamill
Senior Software Engineer II
[email protected]
www.wellhive.com


WELLHIVE CONFIDENTIALITY NOTICE: The contents of this email message and any 
attachments are intended solely for the addressee(s). Unless otherwise 
indicated, it contains information that is confidential, privileged and/or 
exempt from disclosure under applicable law. If you are not the named 
addressee, you are not authorized to read, print, retain, copy or disseminate 
this message or any part of it. If you have received this message in error, 
please notify the sender immediately by e-mail and delete all copies of the 
message. 

Reply via email to