I think that is probably secure, although I’d like to see a formal proof of 
correctness like the ones for macaroons in 
https://cs.nyu.edu/media/publications/TR2013-962.pdf. There are often subtle 
details to these things. 

Using chained public key signatures in this way goes back to SDSI 
(http://people.csail.mit.edu/rivest/sdsi11.html#secoverview) and has more 
recently been used in Vanadium under the name “blessings”: 
https://vanadium.github.io/concepts/security.html

It has some nice properties, but it is very expensive in terms of CPU costs and 
size of tokens. It also requires every hop to add a signature even if they’re 
not adding any new caveats. This is very secure but can add a lot of overhead, 
and of course means that all parties have to be aware of this format/protocol. 

I still think it’s much easier and more efficient to just use HMAC-based 
macaroons in most cases. You can upgrade them to PoP tokens by appending a 
“cnf” caveat (eg for mTLS). And you can still do things like the “phantom 
token” pattern where a macaroon-based “by ref” token is received by an API 
gateway, introspected, and then replaced with an equivalent (but short-lived) 
signed JWT for consumption by backend microservices. 

— Neil

>> On 29 Nov 2019, at 22:13, Richard Backman, Annabelle <[email protected]> 
>> wrote:
> 
> > That is the easiest way to let the RS verify the macaroon on the assumption 
> > that the RS is trusted. I’m not aware of an alternative for asymmetric 
> > crypto when the RS is untrusted other than using the signature-based 
> > macaroon variant or having per-RS keys. 
>  
> It occurred to me that my previous example of how to do layering with JWTs 
> was needlessly complicated. You can prevent removal of layered constraints by 
> constraining each inner layer to require a wrapper. Consider a "foobar" claim 
> that specifies a public key and indicates that the token must be presented 
> wrapped within a JWS signed with the corresponding private key. The wrapper 
> JWS may introduce additional constraints, and may or may not permit the 
> recipient to present the access token to others, depending on the value of 
> the "foobar" claim. For example:
>  
> The AS generates an access token, with a public key registered by the client 
> as the value of the "foobar" claim. This registration could’ve happened via a 
> dev console, dynamic client reg., or as part of the token request.
> <at_0> = JWS(<AS private key>, {
>     "iss": "as.example.com",
>     "client_id": "...",
>     "user_id": "...",
>     "scope": "a b",
>     "exp": <now + 1 hour>,
>     "foobar": <client public key>
> })
>  
> To call rs1.example.com, the client wraps the token in a JWS signed with the 
> client’s private key. They further restrict the scope and expiration time, 
> and authorize the RS to use the token with other RSes by setting the value of 
> the "foobar" claim to the RS’s public key.
> <at_1> = JWS(<client private key>, {
>     "token": <at_0>,
>     "aud": "rs1.example.com",
>     "exp": <now + 5 seconds>,
>     "scope": "a b",
>     "foobar": <RS1 public key>
> })
>  
> To call rs2.example.com, rs1.example.com wraps the token in a JWS signed with 
> the RS’s private key. The RS prohibits rs2.example.com from further use of 
> the token by setting the "foobar" claim to null.
> <at_2> = JWS(<RS1 private key>, {
>     "token": <at_1>,
>     "aud": "rs2.example.com",
>     "scope": "b",
>     "foobar": null
> })
>  
> Similarly, the client can call rs2.example.com with a token that is 
> restricted from further use.
> <at_3> = JWS(<client private key>, {
>     "token": <at_0>,
>     "aud": "rs2.example.com",
>     "exp": <now + 5 seconds>,
>     "scope": "b",
>     "foobar": null
> })
>  
>  
> This pattern allows for layered constraints, local introspection, and local 
> validation. The requirements (that I’ve identified) are that:
> The client must register a public key with the AS (this could be done during 
> the token request).
> The AS must know whether or not to give the client a plain bearer token or a 
> token with the "foobar" claim (presentation of a key possession proof in the 
> token request could be enough).
> Any recipient that wishes to validate the token must have the public key for 
> the AS.
> Any recipient that wishes to add a layer must have a public key that is known 
> to its callers.
> Any recipient that performs local validation must understand the meaning of 
> the "foobar" claim.
>  
> I haven’t thought too deeply on this so I wouldn’t consider the idea fully 
> baked, but I’m curious to hear your thoughts on it.
>  
> – 
> Annabelle Richard Backman
> AWS Identity
>  
>  
> From: Neil Madden <[email protected]>
> Date: Wednesday, November 27, 2019 at 11:43 PM
> To: "Richard Backman, Annabelle" <[email protected]>
> Cc: Brian Campbell <[email protected]>, oauth <[email protected]>
> Subject: Re: [OAUTH-WG] New Version Notification for 
> draft-fett-oauth-dpop-03.txt
>  
> On 27 Nov 2019, at 20:30, Richard Backman, Annabelle <[email protected]> 
> wrote:
>  
> > That is true, but is IMO more of a hindrance than an advantage for a PoP 
> > scheme. The very fact that the signature is valid at every RS is why you 
> > need additional measures to prevent cross-RS token reuse.
>  
> The other methods you mention require their own additional measures in the 
> form of key exchanges/handshakes. And you still need to prove possession of 
> that shared key somehow.
>  
> This is true. The difference being that the derived key can then be reused 
> for many requests. Because the key derivation is cryptographically tied to 
> this context the RS can’t replay these symmetric tokens anywhere else.. 
>  
> In some cases, “derive a shared key and encrypt this blob” is easier; in some 
> cases “sign this blob declaring your audience” is easier.
>  
> The ECDH scheme does challenge-response to ensure freshness. This was 
> designed to match the anti-replay measures in the DPoP draft but without 
> requiring the server store any state. If you don’t need replay protection (if 
> TLS is enough) then you can indeed just sign the audience, or for ECDH you 
> can do completely static ECDH between the client’s private key and the RS’s 
> public key to derive a shared key that is the same for all time (until key 
> rotation). But in that case you may as well just return a symmetric key 
> directly from the AS... attached to a macaroon, say. 
> 
> 
>  
> > The easiest way to use macaroons with asymmetric crypto is to make the 
> > macaroon identifier be an encrypted random HMAC key that the RS can decrypt 
> > (or a derived key using diffie-hellman). You can concatenate multiple 
> > encrypted keys for multiple RSes. Alternatively in a closed ecosystem you 
> > can encrypt the random HMAC with a key stored in a KMS (such as AWS KMS) 
> > and grant each RS decrypt permissions for that KMS key.
>  
> Is the “random HMAC key that the RS can decrypt” the root key used to 
> generate the macaroon? If so, how would you prevent one targeted RS from 
> using the root key and macaroon identifier to construct an arbitrary macaroon 
> for replay against another targeted RS? If not, how does the targeted RS use 
> the decrypted “random HMAC key” to validate the macaroon? Is there a paper on 
> this approach?
>  
> That is the easiest way to let the RS verify the macaroon on the assumption 
> that the RS is trusted. I’m not aware of an alternative for asymmetric crypto 
> when the RS is untrusted other than using the signature-based macaroon 
> variant or having per-RS keys. 
>  
> I’m not really a fan of purely signature-based JWT access tokens because 
> those tokens often contain PII and so should really be encrypted to avoid 
> leaking details to the client (or anyone else if the token does leak). This 
> came up in the discussion of the JWT-based access tokens draft, which is why 
> I proposed https://tools.ietf.org/html/draft-madden-jose-ecdh-1pu-02 for use 
> in that draft. But if you’re doing encryption then you’re already down the 
> path of having per-RS access tokens (and keys) - the compact encoding of JWE 
> only allows a single recipient. 
>  
>  
> The KMS approach is just symmetric crypto mediated through a third party (and 
> has the same centralization problem as validation at the AS).
>  
> > Clients can then later start adding caveats…, while RSes still don't have 
> > to make any changes….
> > DPoP only effectively prevents cross-RS replay if all RSes implement it, 
> > otherwise the ones that don't are still vulnerable.
> This is because macaroons bake the proof into the “bearer” token (which is no 
> longer really a bearer token) in the Authorization header, whereas DPoP puts 
> it in a separate header.
>  
> That’s not the only difference. The other is that the AS does the validation. 
> If the client appended the DPoP claims to the access token and signed the 
> whole thing, and then the RS took that and sent it to the AS introspection 
> endpoint to validate it, then that would have the same advantage of not 
> requiring any changes at the RS. 
>  
> But if you do this then there’s no longer any reason to use public key 
> signatures because the client and AS may as well agree a shared secret. (The 
> AS can always impersonate a client anyway). At which point we’re basically 
> back using macaroons. 
> 
> 
> draft-ietf-oauth-signed-http-request is another way to do this that doesn’t 
> rely on macaroons.
>  
> > Your previous point was that they require "non-trivial work to use ... and 
> > require developers to learn a new token format".
> By “non-trivial work to use” I was referring to work required from the 
> working group, that I did not feel was being acknowledged.
>  
> Do you believe it’s a disproportionate amount of work compared to any other 
> draft the WG works on?
> 
> 
> Looking back over the thread, I think my objection stems from you referring 
> to macaroons as an “access token format” when they’re really an applied 
> cryptography pattern. The “format” part would need to be defined by the 
> working group. For what it’s worth, I think it’d be interesting to explore 
> if/how the pattern could be applied to the JWT format, or what tweaks would 
> be necessary to make it work. If we could describe a way to create macaroons 
> that reuse the existing work on JWTs, that would be pretty cool.
>  
> There are existing interoperable macaroon libraries right now that define a 
> common format [*]. Unless there was a compelling reason not to, I’d hope we’d 
> just standardize that. 
>  
> [*] Actually they’ve gone through a couple of iterations. I believe the 
> “libmacaroons V2 binary” format is what most now use. 
> 
> 
>  
> > That burden is significantly reduced when developers can just add a 
> > dependency and call a one-liner to add a caveat.
> Libraries can certainly reduce the amount of work required by developers (and 
> here I mean client developers, RS developers, AS developers, and OAuth client 
> and server library developers), but come with their own concerns (e.g., 
> platform availability, licensing, maintenance and reliability, etc.). It 
> becomes one more dependency that developers have to consider.
>  
> I’m not really sure what your point is here. *Any* new addition to OAuth has 
> to be implemented. Either that’s done with a library or you write your own. 
>  
> — Neil
_______________________________________________
OAuth mailing list
[email protected]
https://www.ietf.org/mailman/listinfo/oauth

Reply via email to