Subject: [OAUTH-WG] Motivation for plain transform method in PKCE, and encrypted code_challenge in code

From: Adam Lewis <[email-masked]>
Date: Wed, 24 Jun 2015 10:19:50 -0500

Hi,

I'm probably missing something here, but what is the use case for allowing
the plain transform method in PKCE?  It seems to me the entire point of
sending the hash of the code_verifier (code_challenge) rather than the
code_verifier itself is to avoid leaking the code_verifier through
the browser during the authorization request.  It seems using the plain
type would enable an attacker to intercept the code verifier and use it to
exchange the code for the AT.  If a client is really unable to compute a
S256 hash, wouldn't it just fall back to vanilla OAuth?

Also, under security considerations, it mentions that if the code challenge
is returned as part of the code, it needs to be encrypted. Not sure why
since it was sent un-encrypted, where the attacker would have already had
the opportunity to intercept/obtain it. Plus 7.3 re-enforces the point that
the code verifier has sufficient entropy to prevent brute force attacks.  I
suppose the motivation then for encrypting the code_challenge is to address
the scenario whereby 1) the plain transform method is used, and 2) a
malicious app fails to intercept the code_challenge, but then 3) gets the
code?

Just looking for some background understanding of what went into these
designs.

tx!
adam

---

From: William Denniss <[email-masked]>
Date: Wed, 24 Jun 2015 14:02:53 -0700

Hi Adam,

I work with Naveen (one of the co-authors), and we support the plain
transform method with PKCE for OAuth on iOS currently. My comments are
inline:

On Wed, Jun 24, 2015 at 8:20 AM Adam Lewis <[email-masked]>
wrote:

> the browser during the authorization request.
>

> It seems using the plain type would enable an attacker to intercept
> the code verifier and use it to exchange the code for the AT.
>

PKCE w/ plain protects against a specific attack where a rogue app
intercepts (or eavesdrops) the Authorization Code Grant, but not the
initial auth request.  The code interception attack vector is quite real on
mobile platforms that rely on custom URI schemes for returning the OAuth
code to the native app, and was the motivation of this spec.

PKCE w/ S256 additionally protects against the case where both the auth
request and code grant can be eavesdropped (and potentially the code grant
– but not the initial auth request – intercepted).  Due to the fact
inter-process communication tends to be less secure than HTTPS, this is the
best practice.

If the rogue app can intercept the initial auth request (which is a risk
for a native OAuth token agent), then they are executing a local MitM
attack and all bets are off (that attack isn't protected by PKCE, though we
are looking at addressing this issue separately, within the OIDF NAPPS
Working Group).

Importantly, on iOS if your auth request is initiated with a "https://" url
(i.e. a normal OAuth2 web request), the auth request can *not* be
intercepted by a rogue app, but the returning authorization code grant
*can* be (if uses a custom URI scheme to return the code to the native app
from the browser). PKCE w/ plain was designed specifically to protect
against that attack, and is why we implemented it.

> If a client is really unable to compute a S256 hash, wouldn't it just fall
> back to vanilla OAuth?
>

PKCE w/ plain prevents some actual attack scenarios today. S256 remains the
best practice, but it doesn't invalidate the effectiveness of "plain" in
some situations.

> Also, under security considerations, it mentions that if the code
> challenge is returned as part of the code, it needs to be encrypted. Not
> sure why since it was sent un-encrypted, where the attacker would have
> already had the opportunity to intercept/obtain it. Plus 7.3 re-enforces
> the point that the code verifier has sufficient entropy to prevent brute
> force attacks.  I suppose the motivation then for encrypting the
> code_challenge is to address the scenario whereby 1) the plain transform
> method is used, and 2) a malicious app fails to intercept the
> code_challenge, but then 3) gets the code?
>

There are two common ways the Authorization Server can associate the
verifier with the code to compare later when the code is redeemed on the
token endpoint. One is storing and associating the code and verifier server
side, the other avoids server storage by using symmetric encryption to
encode both the verifier and code together, and return that as the code
(this works as the client treats the authorization code as an opaque blob).
Then when the code is redeemed, the server can decrypt, and get the
verifier.  But that is unrelated to the transform method.

> Just looking for some background understanding of what went into these

I hope the above explanations help.

Best,
William