76 lines
3.9 KiB
Markdown
76 lines
3.9 KiB
Markdown
# Proposal
|
|
|
|
## Why
|
|
|
|
The previous change (`advertise-valid-ipps-certificate`) made the container
|
|
*generate* a certificate with the right subject alternative names, but clients
|
|
still get a certificate they do not trust. From the workstation,
|
|
`curl https://podp.local:631/` fails with `SSL certificate problem: unable to get
|
|
local issuer certificate`, and the certificate the server presents has
|
|
`CN=host.containers.internal` — not the certificate the entrypoint installed.
|
|
|
|
The reasoning in the previous change ("CUPS 2.4 keeps serving
|
|
`ServerCertificate`, so also write `<host name>.crt`") was wrong. Reading the
|
|
CUPS 2.4.2 sources:
|
|
|
|
- `ServerCertificate`/`ServerKey` are no longer supported. In `cupsd.conf` they
|
|
log "Please move … to the cups-files.conf file"; in `cups-files.conf` they log
|
|
"is no longer supported" and are ignored (`scheduler/conf.c`). The certificate
|
|
directory is `ServerKeychain` (default `ssl` → `/etc/cups/ssl`).
|
|
- On a server TLS handshake, `_httpTLSStart()` (`cups/tls-openssl.c`) ignores
|
|
the requested (SNI) name. It takes the **local socket address** the client
|
|
connected to, reverse-resolves it, and loads `<name>.crt` from the keychain
|
|
directory. A name that is not alphanumeric, `-` or `.` is mangled to `_`
|
|
(`http_make_path()`), and a numeric IPv6 result is used verbatim because CUPS
|
|
only rejects numeric names that start with a digit.
|
|
|
|
So with host networking the client's connection to the LAN address
|
|
`192.168.100.20` makes cupsd look for `/etc/cups/ssl/host.containers.internal.crt`
|
|
(the name Podman writes into `/etc/hosts` for the host address). That file did
|
|
not exist — only `<host name>.crt` and `<Avahi FQDN>.crt` were written — so cupsd
|
|
minted its own, which does not cover `podp.local`. IPv6 connections get a
|
|
certificate named after the IPv6 literal for the same reason. The previous
|
|
change's verification only checked `localhost`, where cupsd falls back to the
|
|
default common name and happened to find the copy.
|
|
|
|
## What Changes
|
|
|
|
- Derive the certificate copies from what cupsd actually looks up: write
|
|
`<name>.crt`/`<name>.key` for every DNS name in the SAN list **and** for every
|
|
local address (the address literal, mangled the way `http_make_path()` does,
|
|
plus whatever name the address reverse-resolves to). This covers the Podman
|
|
`host.containers.internal` name for the LAN address and the IPv6 literals.
|
|
- Keep the SAN list and the regeneration logic unchanged: the certificate
|
|
content was already correct and reissuing it is not desirable.
|
|
- Correct the comments, the README and the spec so they no longer claim
|
|
`ServerCertificate` is what makes cupsd serve our certificate. The directive
|
|
is kept only for CUPS versions older than 2.4.
|
|
|
|
Non-goals: generating a publicly trusted certificate or a private CA, adding the
|
|
local addresses to the certificate's IP SANs (that needs `CERT_EXTRA_NAMES` and
|
|
is out of scope), and changing the plain `_ipp` service.
|
|
|
|
## Capabilities
|
|
|
|
### New Capabilities
|
|
<!-- None: this hardens the certificate requirement added by the previous change. -->
|
|
|
|
### Modified Capabilities
|
|
- `printserver/cups`: the requirement that the secure AirPrint certificate
|
|
matches the advertised name gains a scenario for serving that certificate for
|
|
the address a client connected to, not only for the name it asked for.
|
|
|
|
## Impact
|
|
|
|
- `entrypoint.sh`: `install_default_cert_copy` now enumerates the local
|
|
addresses and cupsd's filename mangling; `ensure_cupsd_cert_directives`
|
|
comment corrected.
|
|
- `README.md`: certificate section explains how CUPS selects the certificate.
|
|
- `openspec/specs/printserver/cups/spec.md`: one scenario added to the
|
|
certificate requirement.
|
|
- Clients: fully validating clients (macOS/iOS AirPrint, `curl`) complete the
|
|
secure connection once they trust the certificate; plain IPP is unaffected.
|
|
- Existing deployments: an existing `/etc/cups` volume is fixed on the next
|
|
start; the certificate itself is not reissued, so clients that already trust
|
|
it keep trusting it.
|