client_secret to key

Issue #762 resolved
Brian Campbell created an issue

client_secret is a string but most crypto operates on bytes

There is text that says, "[MAC] is calculated using the value of client_secret as the shared key"[1] or "use a left truncated SHA-256 hash of client_secret to ..." [2]

(side question, is SHA-256 there too restrictive as far as crypto agility is concerned?)

Should the spec(s) explicitly state how to go from the client_secret string to the bytes input into the MAC or hash functions? Probably it could just be "the bytes of the UTF-8 representation" or something like that. Or restrict client_secret to only ASCII printable characters? Which it kind of is already, I guess, by its possible use in HTTP Basic.

Lastly should we consider/address potential loss of entropy or key-space in such a conversion? I.e. the bytes of the UTF-8 representation of a 32 character sting will produce a 256 bits but the likely make up of the string (even machine generated) means that you don't really get the full 256 bits of strength. I'm not sure if that's esoteric or important. JOSE/JWA is pretty strong about key size, "a key of the same size as the hash output (for instance, 256 bits for "HS256") or larger MUST be used with [HMAC] algorithm[s]." [3] (though I think most implementations are ignoring that currently).

This is somewhat related to https://bitbucket.org/openid/connect/issue/761

[1] http://openid.net/specs/openid-connect-messages-1_0-15.html#client_authentication

[2] http://openid.net/specs/openid-connect-messages-1_0-15.html#enc

[3] http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-08#section-3.2

Comments (9)

  1. Vladimir Dzhuvinov

    In our OIDC SDK we do a simple client_secret.getBytes("utf-8"). Our client_secret generator, however, is strictly limited to outputting ASCII chars only.

    It's interesting that I couldn't find specific normative text for what encoding the secret in HTTP Basic must be. I first had a look at OAuth 2.0, section 2.2.1 which says the secret must be "application/x-www-form-urlencoded", then refers to RFC 2617. There in section two on HTTP Basic Auth it says that the password must be base64url encoded, and the password itself is given as *TEXT. However, there is no ABNF definition of TEXT that I know of. Strange :)

  2. Michael Jones

    TEXT is defined in http://www.ietf.org/rfc/rfc2616 as:

       TEXT           = <any OCTET except CTLs, but including LWS>
       LWS            = [CRLF] 1*( SP | HT )
       CRLF           = CR LF
       CTL            = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
       CR             = <US-ASCII CR, carriage return (13)>
       LF             = <US-ASCII LF, linefeed (10)>
       SP             = <US-ASCII SP, space (32)>
       HT             = <US-ASCII HT, horizontal-tab (9)>
    

    For background, OAuth client_id values MUST be form-urlencoded when passed to HTTP Basic because they can contain ':' characters, which is used by HTTP Basic to separate the username part from the password part. (The form-url-encoding also means that Unicode characters can be used because their UTF-8 representations can be form-urlencoded.)

  3. Brian Campbell reporter

    I also have been doing a do a simple client_secret.getBytes("utf-8"). So we've come to the same conclusion, and a reasonable one, but there's ambiguity in the spec and we could have potentially done something different. We also only generate the secret using a subset of ASCII chars (though we have other workflows that allow the client or client admin to dictate the secret).

    The form-url-encoding on the pwd in OAuth's use of HTTP basic does means that Unicode characters can be used because their UTF-8 representations can be form-urlencoded but, AFAIK, the character encoding isn't actually specified anywhere so there's still ambiguity and potential interop problems. I.e. if the sender url endcodes using UTF-8 but the receiver URL decodes using a platform default.

    I think that many implementations will use some subset ASCII for simplicity and to avoid potential issues like the above (even if I'm mistaken, the potential concern is there and it's a lot easier to just go with alpha numeric chars or something than to deal with even trying to understand that stuff). And in that case, you effectively lose at least one bit of entropy for every byte in the secret.

  4. Michael Jones

    We will use the left-truncated SHA-256 hash of the UTF-8 representation of the client secret as the symmetric key.

    We should add security considerations about the client secret size and entropy.

  5. Brian Campbell reporter

    The "left-truncated SHA-256 hash" language is currently (as of -15) only for encryption and doesn't work as written for singing with HS384 or HS512 due to min key lengths defined in JWA ([3] in the original ticket).

  6. Brian Campbell reporter
    • changed status to open

    On the 2/14 call there was push-back on the hash part of the hmac key process and folks agreed that just the UTF8 bytes of the secret is sufficient (and seems to be current practice or close enough to it so want to not break that).

    Also the → <<cset 45d34fab8fac>> change left things in an inconsistent state because in addition to http://openid.net/specs/openid-connect-messages-1_0-15.html#sigs these two sections http://openid.net/specs/openid-connect-messages-1_0-15.html#client_authentication (client_secret_jwt) and http://openid.net/specs/openid-connect-messages-1_0-15.html#id.token.validation (step 6) also talk about client secret to hmac key and need to be adjusted accordingly.

    Which maybe argues for consolidation of the text somewhere rather than repeating the language.

  7. Log in to comment