Require https for the online key service

Every request to the key service carries base64 AACS key material in its body —
the unit-key file, the MKB, content samples, the volume ID — and a bearer token
in a header when one is configured. Over http:// all of that goes to any on-path
observer, and the token is replayable.

There is no plaintext deployment to preserve. The address guard already rejects
loopback, RFC1918, ULA and link-local, so an http:// URL can only ever reach the
public internet, which is the worst case for cleartext; a self-hosted keyserver
on a LAN is impossible under that guard whatever its scheme. A non-https URL now
skips the online source with a warning rather than transmitting, so a
misconfiguration falls through to the local keydb and says why instead of
leaking quietly.
This commit is contained in:
Matthew Jackson
2026-07-29 16:36:43 -07:00
parent 7408a916bf
commit e963104dcf
+22
View File
@@ -219,6 +219,28 @@ impl OnlineSource {
if self.base_url.is_empty() {
return Vec::new();
}
// Refuse to transmit over plaintext. The request body always carries
// base64 AACS key material (inf/mkb/units/vid) and, when configured, a
// bearer token in a header — so an `http://` POST hands both to any
// on-path observer, and the token is replayable.
//
// There is no legitimate plaintext deployment to preserve here: the
// address guard below rejects loopback, RFC1918, ULA and link-local, so
// an `http://` URL can only ever reach the PUBLIC internet — the single
// worst case for cleartext. A self-hosted keyserver on a LAN is already
// impossible by that guard, whatever its scheme.
//
// Falls through to the next key source (a local keydb) rather than
// failing the rip, and says why — misconfiguration should be visible,
// not silently indistinguishable from "this disc has no key".
if !self.base_url.starts_with("https://") {
tracing::warn!(
target: "freemkv::keysource",
"key-service URL is not https:// — refusing to send key material \
and credentials in cleartext; skipping the online source"
);
return Vec::new();
}
let mkb = ctx.mkb().unwrap_or(&[]);
// An over-cap MKB cannot be forwarded — bound the body. Log it: a silent
// empty return here is indistinguishable from "no key", so surface the