Re: [Txauth] XYZ-08 vs XAuth-08

Justin Richer <jricher@mit.edu> Sun, 14 June 2020 17:21 UTC

Return-Path: <jricher@mit.edu>
X-Original-To: txauth@ietfa.amsl.com
Delivered-To: txauth@ietfa.amsl.com
Received: from localhost (localhost [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id EA4393A0817 for <txauth@ietfa.amsl.com>; Sun, 14 Jun 2020 10:21:23 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -1.898
X-Spam-Level:
X-Spam-Status: No, score=-1.898 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001] autolearn=ham autolearn_force=no
Received: from mail.ietf.org ([4.31.198.44]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id R_ELkRIUqVmV for <txauth@ietfa.amsl.com>; Sun, 14 Jun 2020 10:21:22 -0700 (PDT)
Received: from outgoing.mit.edu (outgoing-auth-1.mit.edu [18.9.28.11]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id EC7083A07DA for <txauth@ietf.org>; Sun, 14 Jun 2020 10:21:21 -0700 (PDT)
Received: from [192.168.1.14] (static-71-174-62-56.bstnma.fios.verizon.net [71.174.62.56]) (authenticated bits=0) (User authenticated as jricher@ATHENA.MIT.EDU) by outgoing.mit.edu (8.14.7/8.12.4) with ESMTP id 05EHLIhP016851 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 14 Jun 2020 13:21:19 -0400
Content-Type: text/plain; charset="utf-8"
Mime-Version: 1.0 (Mac OS X Mail 13.4 \(3608.80.23.2.2\))
From: Justin Richer <jricher@mit.edu>
In-Reply-To: <20200614044940.GE11992@kduck.mit.edu>
Date: Sun, 14 Jun 2020 13:21:18 -0400
Cc: Dick Hardt <dick.hardt@gmail.com>, txauth@ietf.org
Content-Transfer-Encoding: quoted-printable
Message-Id: <BB3CAA77-7B3C-4D89-B09E-6CCB84DE43EC@mit.edu>
References: <CAD9ie-uH5Zun_jhiqnoP=Gye19TVyvgqa4b+Z=a3_Y830yqLtg@mail.gmail.com> <44332CBC-83B1-411C-B518-EE2F3D030301@mit.edu> <CAD9ie-sSr3NBe=d4y02J7kYzkHnm=VRQgfbr5oH3_zfKyzcKuQ@mail.gmail.com> <A1F8BEC9-A312-494B-8CE5-BE0422CA1C91@mit.edu> <CAD9ie-vA13jLONjNwbVbvwVgKYEQCCQTtDdfg66fs7hjtoBR7Q@mail.gmail.com> <01A1051E-30AB-419B-A0F1-C9AED6BFA357@mit.edu> <CAD9ie-s_shGvafWoMwMEpvkJLQpUV5iS-eWKVtHMM5dxuyckPg@mail.gmail.com> <3D57381A-DA98-4DD7-8960-A6D94A643E43@mit.edu> <20200614044940.GE11992@kduck.mit.edu>
To: Benjamin Kaduk <kaduk@mit.edu>
X-Mailer: Apple Mail (2.3608.80.23.2.2)
Archived-At: <https://mailarchive.ietf.org/arch/msg/txauth/HHdgKgdlciXnlJPC9zXrFqzxwbQ>
Subject: Re: [Txauth] XYZ-08 vs XAuth-08
X-BeenThere: txauth@ietf.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <txauth.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/txauth>, <mailto:txauth-request@ietf.org?subject=unsubscribe>
List-Archive: <https://mailarchive.ietf.org/arch/browse/txauth/>
List-Post: <mailto:txauth@ietf.org>
List-Help: <mailto:txauth-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/txauth>, <mailto:txauth-request@ietf.org?subject=subscribe>
X-List-Received-Date: Sun, 14 Jun 2020 17:21:24 -0000

Hi, Ben --

> On Jun 14, 2020, at 12:49 AM, Benjamin Kaduk <kaduk@mit.edu> wrote:
> 
> One more point, while I'm catching up on the thread...
> 
> On Tue, Jun 09, 2020 at 12:10:40PM -0400, Justin Richer wrote:
>> 
>> 
>>> On Jun 8, 2020, at 5:33 PM, Dick Hardt <dick.hardt@gmail.com> wrote:
>>> 
>>> That is not entirely correct. A pre-registered client can still pass its key by value, and a dynamic client can still use a (dynamically-acquired) handle. In all cases, the client is identifying itself by its key. The difference is how the server looks up that key — it’s either from the handle, or it’s from the key value itself. 
>>> 
>>> I don't understand this. 
>>> 
>>> How is the Client authenticating that it is a specific pre-registered client?
>> 
>> The client is identified by its key. There is no external client identifier. I think you’re confused because you’re still thinking in terms of OAuth 2’s client ID based model and I am trying to move us past that. It took me time to realize that we really can let it go, so hopefully this is helpful in explaining why.
>> 
>> When a credential is cryptographically random enough to be unique, it can be used as its own identifier, particularly when you don’t need to identify the entity outside of the context that it can present and prove its credential. To stretch a metaphor, passwords don’t always need usernames. This is, after all, the driving design pattern behind OAuth access tokens. An access token doesn’t have a “username” portion to it, even though it would have been trivial to require the client to send its client ID alongside the access token. Why does that work? Because our model of what the RS does with the access token is built around it answering the questions: is this token valid and does it allow what’s being requested? If the RS needs to know which client was issued the token, it can discover that information without being told separately from the token -- perhaps it’s in the token itself or it’s in an introspection response. And in a lot of cases, the RS doesn’t care about the client software, it just wants to know if the token’s any good. Even in constrained tokens such as MTLS, PoP, and DPoP, we aren’t really authenticating the client at the RS so much as making sure the right key is presented alongside the right token. 
>> 
>> XYZ takes that same approach with the client talking to the AS and uses the credential (key) to identify the client as well as authenticate and protect the request. We can’t just say “OAuth 2 had client IDs and people are used to it so it must be good and we have to keep using it”. We need to ask WHY OAuth 2 needs client IDs and if that still makes sense. I argue that it doesn’t make sense anymore and we need to step back and look at a better model. OAuth 2 needs a client ID because it gets passed in the front channel and the client’s credentials can’t be used there. The access token doesn’t need an equivalent because it’s passed in the back channel and can be used directly. Now that the client no longer needs to be identified, but not authenticated, through untrusted third parties (such as the browser), we don’t need to have a separate identifier as part of the protocol. With an intent-based protocol, that starts in the back channel, you don’t need a client identifier anymore. Once the AS finds that key, the AS can then figure out what policies, rights, and restrictions are attached to that key. In many implementations, there’s going to be some kind of “registered client” object in a database somewhere that drives those policies. That’s the classical OAuth model, and it works in many cases. But in other cases, the key is going to just be a value used to protect the request chain (and possibly the token itself), and the policy is going to be built up by other things like a device posture or signature on the calling software or verified user information. It’s not just about client authentication, even though it can be used for it. DPoP, PKCE, and DynReg have shown us the value in dynamic systems, in different ways. 
>> 
>> On top of that, PAR is showing us that a lot of the constraints that we have in OAuth 2 don’t really apply anymore. For instance, Redirect URI restrictions can be relaxed because now you CAN identify and authenticate the software sending it, which isn’t true with a front-channel-first approach. All of the things that are required in OAuth 2 start to become redundant, and it leads to things like requiring that “client_id” still always be passed in the front channel even though the information could be looked up from an internal request_uri reference using PAR and JAR together.
>> 
>> That’s why a key handle isn’t exactly the same as a client ID and I did not call it a client ID in the XYZ protocol. It’s a shortcut to refer to the key material for certain optimized cases, but ultimately it’s pointing to a key. This has an interesting and beneficial side effect — if you HAVE a client ID as part of your internal data model, it can FUNCTION as a key handle because it’s a unique value the AS can use to look up key information. It’s not “authenticating the client”, it’s pointing to a key which in turn identifies and authenticates the software making the call. The fact that it’s a “client ID” is an artifact of the implementation, which in this case has an OAuth 2 legacy to work with. 
>> 
>> If we’re going to move past the constraints of OAuth 2 we need to stop thinking so strictly in its terms and models. There are better ways to approach this now and client IDs are not required by this protocol model.
> 
> The idea of a client (or other entity) being identified precisely by its
> public key is very reminiscent of HIP (RFC 7401, 7402) that has a similar
> stance.  (There, it's billed as a security feature, since you are literally
> guaranteed by the protocol to be talking to the entity you think you are.)
> One of the difficulties with using HIP, though, is that just the pubkey is
> not always a terribly useful identifier, and we tend to want to tie into
> other naming systems (e.g., the DNS in the case of HIP) so that we know
> that the party we're talking to at the HIP layer is also the
> person/organization we want to be talking to.  In the case of HIP, the need
> to bind a different type of name to the public key brings back a lot of the
> issues that using the key as the identifier was supposed to solve (and in
> my opinion is part of why HIP is not more broadly deployed).  I don't see
> this need for a binding of external name/identity to an XYZ public key as a
> fatal flaw, though -- the way in which introduction are done combined with
> the AS's database seems to allow things to work reasonably.  I just want to
> make sure that we're thinking about how the public key will be bound to
> external identities, and make sure that our story for doing so is sound.
> 

Yes, I feel the same way. The idea behind XYZ’s ability to introduce the key either by value leads to a model where the key is always what points to the policy of what’s allowed, but the way that the AS discovers which key it’s supposed to be proving against is separate. So it goes handle -> key -> client. In OAuth 2, the model is you identify the client and then figure out what key is attached to that client. The relationship is inverted as handle -> client -> key, and that’s where the problems start to come in for other communities. 

It’s really important for a lot of use cases that we let clients have an identifier separate from the key value itself, which is why XYZ doesn’t define the key handle as the fingerprint of the key, or the key ID (which could be internal to the JWK), or anything else. All it means is “when the AS sees this value, it knows what key or keys it is referring to”. And from there, the AS can figure out the rest of its policy. As you say, this relationship can get set up with an AS database, or the AS could know how to look up the key in a DNS store or distributed ledger — it doesn’t matter, as long as the AS can find the key. This allows us to also have use cases where we don’t have a separate identifier that the AS knows about and we can just send the key as-is, like for ephemeral clients in SPAs, or mobile applications that would need to be registered in OAuth 2 in order to get a client ID. And you don’t even need to look that far from OAuth to find use cases for key-based identity, as that’s at the core of the self-issued OP functions in OIDC, which is in the core spec. There, we have the spec saying to use the redirect URI as the client ID — even though the client already is sending the Redirect URI, OAuth 2 (and the associated assumptions and model of the protocol underneath) need this explicit client ID field for all use cases. 

Something that I think is interesting is that we have an opportunity to potentially define ways to process these kinds of things cross domain, much the way JWTs and introspection allow for cross-domain access tokens to be processed. But I think there’s still a lot of discussion and debate to figure out all the avenues that people care about here. XYZ’s model is probably not exactly right for every case, but I’ve already seen the ability to do key by value or by reference be useful in a lot of places that OAuth 2 doesn’t really work well.

And that’s really where GNAP is going to shine — in the gaps that OAuth 2 has left.

> Thanks,
> 
> Ben


Thanks, 
 — Justin