Re: [OAUTH-WG] New Version Notification for draft-fett-oauth-dpop-03.txt

Neil Madden <neil.madden@forgerock.com> Sat, 30 November 2019 08:03 UTC

Return-Path: <neil.madden@forgerock.com>
X-Original-To: oauth@ietfa.amsl.com
Delivered-To: oauth@ietfa.amsl.com
Received: from localhost (localhost [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id B1FB2120045 for <oauth@ietfa.amsl.com>; Sat, 30 Nov 2019 00:03:39 -0800 (PST)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -1.997
X-Spam-Level:
X-Spam-Status: No, score=-1.997 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, HTML_MESSAGE=0.001, MIME_QP_LONG_LINE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001] autolearn=ham autolearn_force=no
Authentication-Results: ietfa.amsl.com (amavisd-new); dkim=pass (1024-bit key) header.d=forgerock.com
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 BmL4tciWrasE for <oauth@ietfa.amsl.com>; Sat, 30 Nov 2019 00:03:36 -0800 (PST)
Received: from mail-wr1-x434.google.com (mail-wr1-x434.google.com [IPv6:2a00:1450:4864:20::434]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id BBABC12000F for <oauth@ietf.org>; Sat, 30 Nov 2019 00:03:35 -0800 (PST)
Received: by mail-wr1-x434.google.com with SMTP id g17so5667236wro.2 for <oauth@ietf.org>; Sat, 30 Nov 2019 00:03:35 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=forgerock.com; s=google; h=content-transfer-encoding:from:mime-version:date:message-id:subject :in-reply-to:references:to:cc; bh=e2ZPVCKJOj234J821DZO+gigs6pPLa0Qidui7MrejMA=; b=avVX/YJY5bRn7axcd45iQePQAIp72y13dRW/CLb8vXAwppySvK94Fp7q6PCfste14b PKRs9crpROJJ6c5WOhm1HbQWWXoQC22t83e6rjIQsmvJ3Tt2iIODYG1XA7WZFbz8jYxA TyTmlj78H7ipQdAJmTZl7kEm6fB/o0SeyoUbY=
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:content-transfer-encoding:from:mime-version:date :message-id:subject:in-reply-to:references:to:cc; bh=e2ZPVCKJOj234J821DZO+gigs6pPLa0Qidui7MrejMA=; b=FlcGtnp6chvDMyBwhdaXVpnniRDHcOwpWn7E4viNpgyWmWPlbOsqq/PDdI6jPahDkA RpcCNtYbnR/TY6o2XMwAnLs1+pV7EFkbBYVbdjx27Q5ybNLGsySc4q7LzaK6tE4yg23z BstN5VK6/vq/+eD55qvt4sSyj2ArIc0lDWftpm4d9kJ3njq33tFYkg/2DWwuP73oiIm2 HxaCcNY2GTf6MxQvqFXA7yVweWw+ddKprICd9Je7YfENpC+5Wf9Grgcqqadi2zTaGnGp Mc1gye8HocQDiY4VeMJq03abjWJmuGxv0d6FgcSef++L0vOoYYb1Tynn4IrNcwh66QPO Tueg==
X-Gm-Message-State: APjAAAUv8B9JgYPDwROfcn8oYhcxgkuNWVGdJBEUuuAg/UjToq6Np9BI OcdNYgwVcBSVHGyIeRqeKqEPKQ==
X-Google-Smtp-Source: APXvYqxQbsKpSsHG6TSWqQYktrsZlMFGjvSqrn/EAU2iZMaXSCIU7nbJfVn2a3AFAKkygmQ+kKjjMg==
X-Received: by 2002:adf:e301:: with SMTP id b1mr57801827wrj.280.1575101013918; Sat, 30 Nov 2019 00:03:33 -0800 (PST)
Received: from ?IPv6:2a01:4c8:1e:a0cd:50d8:7c74:ca37:84a2? ([2a01:4c8:1e:a0cd:50d8:7c74:ca37:84a2]) by smtp.gmail.com with ESMTPSA id d18sm32267856wrm.85.2019.11.30.00.03.32 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 30 Nov 2019 00:03:32 -0800 (PST)
Content-Type: multipart/alternative; boundary="Apple-Mail-C0A8722B-9AA6-422D-BF32-7AB424D55779"
Content-Transfer-Encoding: 7bit
From: Neil Madden <neil.madden@forgerock.com>
Mime-Version: 1.0 (1.0)
Date: Sat, 30 Nov 2019 08:03:31 +0000
Message-Id: <04D23E63-0D2C-4CBA-B671-3433FC76AE24@forgerock.com>
In-Reply-To: <863A2C3D-FA2A-472C-B9FE-D9B3D99A5812@amazon.com>
References: <863A2C3D-FA2A-472C-B9FE-D9B3D99A5812@amazon.com>
To: "Richard Backman, Annabelle" <richanna@amazon.com>
Cc: Brian Campbell <bcampbell@pingidentity.com>, oauth <oauth@ietf.org>
X-Mailer: iPhone Mail (17A878)
Archived-At: <https://mailarchive.ietf.org/arch/msg/oauth/RAl3jHG_YoXCIftYaUNYt4U7MLA>
Subject: Re: [OAUTH-WG] New Version Notification for draft-fett-oauth-dpop-03.txt
X-BeenThere: oauth@ietf.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: OAUTH WG <oauth.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/oauth>, <mailto:oauth-request@ietf.org?subject=unsubscribe>
List-Archive: <https://mailarchive.ietf.org/arch/browse/oauth/>
List-Post: <mailto:oauth@ietf.org>
List-Help: <mailto:oauth-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/oauth>, <mailto:oauth-request@ietf.org?subject=subscribe>
X-List-Received-Date: Sat, 30 Nov 2019 08:03:40 -0000

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 <richanna@amazon.com> 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 <neil.madden@forgerock.com>
> Date: Wednesday, November 27, 2019 at 11:43 PM
> To: "Richard Backman, Annabelle" <richanna@amazon.com>
> Cc: Brian Campbell <bcampbell@pingidentity.com>, oauth <oauth@ietf.org>
> Subject: Re: [OAUTH-WG] New Version Notification for draft-fett-oauth-dpop-03.txt
>  
> On 27 Nov 2019, at 20:30, Richard Backman, Annabelle <richanna@amazon.com> 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