Subject: [Ohai] Some notes on draft-pauly-ohai-svcb-config

From: Ben Schwartz <[email-masked]>
Date: Thu, 17 Mar 2022 12:13:19 -0400

# MITM

This draft acknowledges some security problems but I don't think it really
gets to the heart of the matter.  In an ordinary configuration, this
setup enables the Oblivious Proxy to fully impersonate literally any
origin, bypassing the WebPKI entirely, if DNS resolution is not fully
secured and independent of the proxy.  I don't think this is consistent
with the security goals of OHAI.

Some possible solutions:
* Mandate DNSSEC
* Wrap the KeyConfig with a signature by the origin and a certificate chain.
* Provide only ohttp-path, and require clients to fetch the KeyConfigs
directly from the origin.
  - Then ask the proxy to query the KeyConfigs too, and use only KeyConfigs
that appear in both lists, to ensure that they are not targeted to this
user.  You would also need to require a long cache lifetime and hope that
the proxy is actually caching.

# Key Consistency

>   One mitigation specific to this mechanism is
>   validating that SVCB or HTTPS records including the "oblivious-
>   configs" are protected by DNSSEC [DNSSEC].  This prevents attacks
>   where a unique response is generated for each client of a resolver.

No, it's straightforward to DNSSEC-sign unique responses for each query.  I
think the mitigation you're looking for is "TTL much greater than 0".  The
longer the TTL, the less ability the origin has to target individual users
behind a shared cache.  If this is what you want, you may want to recommend
requiring the response to have ECS scope "/0" to confirm that the keys are
not targeted to the client's IP range (depending on whether the DNS query
is using ODoH...).

The addition of ohttp-path further complicates key consistency checks.  Now
I also need to check that I haven't been served a unique path.

If you need an out-of-band key consistency check, then there is no benefit
to distributing keys in the SVCB record.  You might as well just place an
"ohttp" flag in the SVCB record and let the client learn the rest out of
band.

# Deactivation

All indications here are strictly opt-in.  A hostile origin (which is the
key threat actor in OHTTP) could simply erase these keys to disable OHTTP.
Who does this design defend against?  I would like to see a threat model.

At a glance, it seems like the threat model involves a "non-tracking"
origin who distrusts its future self (e.g. due to potential third-party
coercion), and wants to ensure that there is a public signal if it ceases
to be non-tracking in order to enable a non-technical reaction.

Alternatively, perhaps you believe OHTTP will act as a performance
optimization if the client will otherwise use a slower proxying method?  In
that case, this is not a security enhancement, so we should discuss use
cases (and performance goals) instead.

# DDR

DDR (in "Discovery Using Resolver IP Addresses" mode) is an especially poor
use case for this, for several reasons:

0. Obviously it is inapplicable if the resolver has an RFC1918 address.
1. The client cannot benefit from DNS-caching-based key consistency,
because there is no shared intermediary cache.  As above, the need for an
out-of-band key consistency check makes the values in SVCB redundant.
2. The only origin host known to the client is an IP address (the original
IP address provided over DHCP).  This means that DDR records that involve
redirection to a different IP address (e.g. a nontrivial TargetName) will
not work, because the Oblivious Proxy will only know the original IP
address.  Also, cross-IP fallback mechanisms such as Happy Eyeballs cannot
be used at the proxy, which sees only one IP address on each request.

There should at least be more caveats here, if it is mentioned at all.

# ODoH

Do you intend to keep odoh-configs and ohttp-configs?  They seem redundant
and confusing to me.  Can we drop odoh-configs?

# Mandatory

>    When present in an HTTPS record, the "ohttp-configs" MUST be included
>   in the mandatory parameter list, to ensure that implementations that
>   do not understand the key do not interpret this service as a generic
>   HTTP service.

Why?  Why can't a service accept both HTTP and OHTTP requests on the same
"service"?

# Path

Why are ohttp-configs and ohttp-path separate?  This seems to increase the
complexity of the HTTP-DNS interface required to populate these records.
Can we define a merged OHTTPConfig struct?

# Unicode

> In both wire format and presentation format, this is a UTF-8
encoded string that contains the path segment of a URI.

URIs are not Unicode; they are byte-strings defined by an ABNF rule.  This
text is presumably here because of "dohpath", but "dohpath" encodes a
segment of a URI Template, not a URI, and URI Templates are Unicode.

---

From: Tommy Pauly <[email-masked]>
Date: Thu, 17 Mar 2022 10:57:26 -0700

Hi Ben,

Responses inline.

> On Mar 17, 2022, at 9:13 AM, Ben Schwartz <bemasc=[email-masked]> wrote:
> 
> # MITM
> 
> This draft acknowledges some security problems but I don't think it really gets to the heart of the matter.  In an ordinary configuration, this setup enables the Oblivious Proxy to fully impersonate literally any origin, bypassing the WebPKI entirely, if DNS resolution is not fully secured and independent of the proxy.  I don't think this is consistent with the security goals of OHAI.

Can you explain how the oblivious proxy would be able to impersonate an origin here? If the client is receiving the oblivious target config from the DNS records, and is the one issuing the requests, how does the proxy get to launch this attack? Are you assuming that your proxy also controls the DNS records the client receives?

> * Provide only ohttp-path, and require clients to fetch the KeyConfigs directly from the origin.
>   - Then ask the proxy to query the KeyConfigs too, and use only KeyConfigs that appear in both lists, to ensure that they are not targeted to this user.  You would also need to require a long cache lifetime and hope that the proxy is actually caching.

Understanding if the config is trusted and the keys are consistent is indeed work that the client needs to do. The document mentions DNSSEC as a possible direction, but it could use other mechanisms.
> No, it's straightforward to DNSSEC-sign unique responses for each query.  I think the mitigation you're looking for is "TTL much greater than 0".  The longer the TTL, the less ability the origin has to target individual users behind a shared cache.  If this is what you want, you may want to recommend requiring the response to have ECS scope "/0" to confirm that the keys are not targeted to the client's IP range (depending on whether the DNS query is using ODoH…).

I’m not sure that checking what the response claims as the ECS scope (if not DNSSEC-signed) would be effective. I suppose you’re assuming DNSSEC being mandated?

Note that there are other ways for a client to check key consistency.
> 
> The addition of ohttp-path further complicates key consistency checks.  Now I also need to check that I haven't been served a unique path.
> 
> If you need an out-of-band key consistency check, then there is no benefit to distributing keys in the SVCB record.  You might as well just place an "ohttp" flag in the SVCB record and let the client learn the rest out of band.

No, that’s not true that this doesn’t have value without inherent key consistency. Learning which OHTTP target and config should be used, particularly for the DDR case, is important. If your key consistency mechanism is just a lookup of what config to use that the client manually does, I see your point, but there are certainly other options. For example, the client could work with the proxy to check the consistency of its config key ID and config hash with the key ID being used by other clients going through the proxy, etc.
> 
> # Deactivation
> 
> All indications here are strictly opt-in.  A hostile origin (which is the key threat actor in OHTTP) could simply erase these keys to disable OHTTP.  Who does this design defend against?  I would like to see a threat model.

Correct, that’s the same as all discovery of servers over DNS. 

The model to consider here is this:
- Client has a default public oblivious DNS server it uses
- If it learns from the local network resolver using DDR that the network has a preferred oblivious DNS server that follows some regional policies, it can use that instead
- If an attacker blocks the discovery, the client still uses its default oblivious server
> 
> At a glance, it seems like the threat model involves a "non-tracking" origin who distrusts its future self (e.g. due to potential third-party coercion), and wants to ensure that there is a public signal if it ceases to be non-tracking in order to enable a non-technical reaction.
> 
> Alternatively, perhaps you believe OHTTP will act as a performance optimization if the client will otherwise use a slower proxying method?  In that case, this is not a security enhancement, so we should discuss use cases (and performance goals) instead.
> 
> # DDR
> 
> DDR (in "Discovery Using Resolver IP Addresses" mode) is an especially poor use case for this, for several reasons:

I disagree—this is the motivating use case.
> 0. Obviously it is inapplicable if the resolver has an RFC1918 address.

Correct, trying to run an oblivious target on a local RFC1918 address doesn’t make sense. However, that doesn’t mean that a local resolver couldn’t advertise an ODoH service, as long as the client has some other way to verify if it trusts that service.

> 1. The client cannot benefit from DNS-caching-based key consistency, because there is no shared intermediary cache.  As above, the need for an out-of-band key consistency check makes the values in SVCB redundant.

The key consistency checks wouldn’t be in a DNS cache, correct — but they could be in the oblivious proxy, etc.

> 2. The only origin host known to the client is an IP address (the original IP address provided over DHCP).  This means that DDR records that involve redirection to a different IP address (e.g. a nontrivial TargetName) will not work, because the Oblivious Proxy will only know the original IP address.  Also, cross-IP fallback mechanisms such as Happy Eyeballs cannot be used at the proxy, which sees only one IP address on each request.

I think you’re misunderstanding — the client isn’t going to be using the verification mechanisms of checking the IP addresses from “direct” DDR.

In the case of oblivious DNS servers, the client might not be able to directly use the verification mechanisms described in [DDR <https://www.ietf.org/archive/id/draft-pauly-ohai-svcb-config-00.html#DDR>], which rely on checking for known resolver IP addresses or hostnames in TLS certificates, since clients do not generally perform TLS with oblivious targets.

There’s no reason that the oblivious proxy couldn’t try different IP addresses for the oblivious target name.

> Do you intend to keep odoh-configs and ohttp-configs?  They seem redundant and confusing to me.  Can we drop odoh-configs?

The point is to allow for backwards compatibility.
> Why?  Why can't a service accept both HTTP and OHTTP requests on the same "service"?

I don’t see how it would be safe to assume that configuration for a generic HTTP service and OHTTP service are the same. It also means that you can’t tell if a service that supports oblivious access also supports non-oblivious access Take the DNS server case—that would then make it look like every service that advertises ODoH also supports direct DoH on the same name, which may not at all be true.

> 
> # Path
> 
> Why are ohttp-configs and ohttp-path separate?  This seems to increase the complexity of the HTTP-DNS interface required to populate these records.  Can we define a merged OHTTPConfig struct?

Why would they be the same? Trying to merge a binary configuration and an URL path seems unnecessary, and also the DDR case already has a path.

—Tommy

> 
> # Unicode
> 
> > In both wire format and presentation format, this is a UTF-8 encoded string that contains the path segment of a URI.
> 
> URIs are not Unicode; they are byte-strings defined by an ABNF rule.  This text is presumably here because of "dohpath", but "dohpath" encodes a segment of a URI Template, not a URI, and URI Templates are Unicode.
> -- 
> Ohai mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/ohai

---

From: Ben Schwartz <[email-masked]>
Date: Thu, 17 Mar 2022 15:45:23 -0400

On Thu, Mar 17, 2022 at 1:57 PM Tommy Pauly <tpauly=
[email-masked]> wrote:

> Hi Ben,
>
> Responses inline.
>
> On Mar 17, 2022, at 9:13 AM, Ben Schwartz <
> bemasc=[email-masked]> wrote:
>
> # MITM
>
> Can you explain how the oblivious proxy would be able to impersonate an
> origin here? If the client is receiving the oblivious target config from
> the DNS records, and is the one issuing the requests, how does the proxy
> get to launch this attack? Are you assuming that your proxy also controls
> the DNS records the client receives?
>

Yes.  HTTPS authentication normally uses a Dolev-Yao attack model in which
any threat actor is assumed to control the network plane.  In the absence
of DNSSEC, this means that any threat actor should be presumed to control
the DNS responses.  This is true even if the client has a secure channel to
a trusted resolver, as the attacker could be upstream of the resolver,
poisoning the cache.

I would also note that mandatory DNSSEC is only sufficient if it is
validated end-to-end.  When DNS data has the ability to override the WebPKI
(as in DANE and here), delegating DNSSEC to the resolver becomes equivalent
to adding the resolver as a root CA, which is not the expected trust
relationship.

>   - Then ask the proxy to query the KeyConfigs too, and use only
> KeyConfigs that appear in both lists, to ensure that they are not targeted
> to this user.  You would also need to require a long cache lifetime and
> hope that the proxy is actually caching.
>
>
> Understanding if the config is trusted and the keys are consistent is
> indeed work that the client needs to do. The document mentions DNSSEC as a
> possible direction, but it could use other mechanisms.
>

I don't think we can reasonably leave this as TBD.  Authentication is at
the core of this, and needs to be interoperable for this specification to
be usable.

> No, it's straightforward to DNSSEC-sign unique responses for each query.
> I think the mitigation you're looking for is "TTL much greater than 0".
> The longer the TTL, the less ability the origin has to target individual
> users behind a shared cache.  If this is what you want, you may want to
> recommend requiring the response to have ECS scope "/0" to confirm that the
> keys are not targeted to the client's IP range (depending on whether the
> DNS query is using ODoH…).
>
>
> I’m not sure that checking what the response claims as the ECS scope (if
> not DNSSEC-signed) would be effective. I suppose you’re assuming DNSSEC
> being mandated?
>

No, DNSSEC is not involved.

The ECS scope controls the resolver's caching behavior.  If the resolver
returns a /0 scope, the resolver is promising to return this result out of
cache to anyone else who performs the same query (if caching is enabled and
until this entry expires or is evicted).  If the client trusts the resolver
with its key consistency, this is a decent heuristic.

>
>
> The addition of ohttp-path further complicates key consistency checks.
> Now I also need to check that I haven't been served a unique path.
>
> No, that’s not true that this doesn’t have value without inherent key
> consistency. Learning *which* OHTTP target and config should be used,
> particularly for the DDR case, is important. If your key consistency
> mechanism is just a lookup of what config to use that the client manually
> does, I see your point, but there are certainly other options.
>

There are, but this is by far the simplest option.

> For example, the client could work with the proxy to check the consistency
> of its config key ID and config hash with the key ID being used by other
> clients going through the proxy, etc.
>

AFAIK, no such mechanism has been proposed to the WG.  I would want to see
such a proposal before designs that are predicated on it.

Personally, I imagine the client downloading the KeyConfig once from the
proxy cache (for consistency), and once directly (for authenticity).  That
leaves no need for out-of-band key distribution.

> - If it learns from the local network resolver using DDR that the network
> has a preferred oblivious DNS server that follows some regional policies,
> it can use that instead

That's a fascinating use case, raising all kinds of questions about agency
and control.  I agree that this approach seems "privacy-safe" from a DNS
perspective.  However, I wonder if it actually accomplishes the intended
goal.  For example, I can set up an ODoH server that replaces all IP
addresses with unique answers from an IPv6 subnet that I control, NATed to
the intended destination.  I won't know which clients made which DNS
queries, but I will still see exactly which client IPs establish
connections via each of my IPs, which allows me to identify which queries
they performed.

We could defeat this by DNSSEC, but only if all sensitive domains are
signed.  Alternatively, we could defeat this if the client uses a proxy for
all network traffic ... but if the client has such a general purpose proxy,
it could access a DoH server via the proxy, leaving ODoH as purely a
performance optimization.

> DDR (in "Discovery Using Resolver IP Addresses" mode) is an especially
> poor use case for this, for several reasons:
>
>
> Correct, trying to run an oblivious target on a local RFC1918 address
> doesn’t make sense. However, that doesn’t mean that a local resolver
> couldn’t advertise an ODoH service, as long as the client has some other
> way to verify if it trusts that service.
>
> I think you’re misunderstanding — the client isn’t going to be using the
> verification mechanisms of checking the IP addresses from “direct” DDR.
>
> In the case of oblivious DNS servers, the client might not be able to
> directly use the verification mechanisms described in [DDR
> <https://www.ietf.org/archive/id/draft-pauly-ohai-svcb-config-00.html#DDR>
> ], which rely on checking for known resolver IP addresses or hostnames in
> TLS certificates, since clients do not generally perform TLS with oblivious
> targets.
>

There are two problems with this:

1. The oblivious proxy doesn't know the target name.  In DDR, the only name
that is required to be present in the resolver's certificate is the initial
discovery name, i.e. the IP address for "Discovery Using Resolver IP
Addresses".  The only host conveyed to the oblivious proxy is the URI host,
which it is required to validate via TLS.  Therefore, the client must send
the IP address in the URI.

2. The client doesn't trust the target name.  In DDR's threat model, the
"discovery seed" is the validation identity, learned over a channel that is
ostensibly secure.  The SVCB TargetName is learned over an untrusted
channel, and cannot safely be used as a validation identity.

> The point is to allow for backwards compatibility.

As a matter of process, I don't think this is correct.  At a minimum, it
should be clearly marked as obsolete.

> I don’t see how it would be safe to assume that configuration for a
> generic HTTP service and OHTTP service are the same.
>

I'm not.  The question is: why does the draft forbid this in cases where
they are the same?

> It also means that you can’t tell if a service that supports oblivious
> access also supports non-oblivious access
>

You can tell by the presence of "mandatory=ohttp-configs" on
service endpoints that are OHTTP-only.

> Take the DNS server case—that would then make it look like every service
> that advertises ODoH also supports direct DoH on the same name, which may
> not at all be true.
>

Sure, if a service endpoint is OHTTP-only, it should say so.

> Why would they be the same? Trying to merge a binary configuration and an
> URL path seems unnecessary, and also the DDR case already has a path.
>

Populating a single SvcParamKey is simpler than populating multiple keys.
The KeyConfig and path are, in this model, essentially an atomic unit.
They are both opaque to the inner HTTP layer, and are used together to form
the message/ohttp-req message.  The KeyConfig is scoped to the path; it is
meaningless without it.  The consistency checks apply to them as a pair,
not independently.

Personally, I think the right thing to put in SVCB is just a flag, but in
architectures where one sends both of these things, I think they are best
represented as a unit.