rdata: store wire-encoded form of ECH configs

Previously the hickory-dns representation of ECH configs found in
SVCB/HTTPS records held and exposed its own non-standard representation
of the encoded ECH configs. Notably, it stripped the TLS-encoded list
length prefix from the remaining data. Similarly, it's presentation
format was the BASE64 encoding of this non-standard form.

Downstream consumers are likely to want the wire-encoding format
unmodified, because ECH is of most use to TLS libraries where they will
have already implemented a generic TLS-encoded list decoder that expects
the length prefix. In practice, popular tools like `dig`
are also encoding the presentation format BASE64 of the data in DNS for
some popular test servers with the prefix included.

This commit updates hickory-dns's representation to not do the
pre-processing it was before. This is trivial for a consumer to do if
they need it, and avoids having to restore it manually in order to use
other pre-existing TLS encoder/decoders with the value from hickory-dns.

Again, since ECH adoption is in very early days it doesn't seem
worthwhile to try and come up with a backwards compatible interface for
those that need the old behaviour. It should be straightforward to
remove the length prefix manually if required.
This commit is contained in:
Daniel McCarney
2024-04-15 18:44:49 -04:00
committed by Dirkjan Ochtman
parent ffc51d7369
commit 5e23b5e587

View File

@@ -836,14 +836,8 @@ impl<'r> BinDecodable<'r> for EchConfigList {
/// Base 64 is used here to simplify integration with TLS server software.
/// To enable simpler parsing, this SvcParam MUST NOT contain escape sequences.
fn read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self> {
let redundant_len = decoder
.read_u16()?
.map(|len| len as usize)
.verify_unwrap(|len| *len <= decoder.len())
.map_err(|_| ProtoError::from("ECH value length exceeds max size of u16::MAX"))?;
let data =
decoder.read_vec(redundant_len)?.unverified(/*up to consumer to validate this data*/);
decoder.read_vec(decoder.len())?.unverified(/*up to consumer to validate this data*/);
Ok(Self(data))
}
@@ -856,11 +850,6 @@ impl BinEncodable for EchConfigList {
/// Base 64 is used here to simplify integration with TLS server software.
/// To enable simpler parsing, this SvcParam MUST NOT contain escape sequences.
fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
let len = u16::try_from(self.0.len())
.map_err(|_| ProtoError::from("ECH value length exceeds max size of u16::MAX"))?;
// redundant length...
encoder.emit_u16(len)?;
encoder.emit_vec(&self.0)?;
Ok(())
@@ -878,10 +867,6 @@ impl fmt::Display for EchConfigList {
/// TLS server software. To enable simpler parsing, this SvcParam MUST NOT
/// contain escape sequences.
/// ```
///
/// *note* while the on the wire the EchConfig has a redundant length,
/// the RFC is not explicit about including it in the BASE64 encoded value,
/// hickory-dns will encode the data as it is stored, i.e. without the length encoding.
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "\"{}\"", data_encoding::BASE64.encode(&self.0))
}