[needs-PR] Nonce Management

Issue #1577 resolved
Tobias Looker created an issue

The first valid c_nonce value for a client is returned from the token endpoint, with subsequent c_nonce values returned from the credential endpoint response when the presented nonce is invalid.

One observation that has been made is that extending the members present in the token endpoint response can be a barrier to certain implementations that want to make use of an unmodified authorisation server. Therefore if the initial nonce is not present in the token endpoint response, then where is it sourced from?

In my opinion there are few options we could consider

  1. Leave it as is, implementations need to extend the token response object. Downside as discussed above
  2. A seperate nonce endpoint which is the single endpoint where all nonces required for PoP’s would be sourced from. Downside a new round trip of req/res required to obtain the nonce.
  3. Define that the initial c_nonce value is the hash of the issued access_token, credential endpoint will return a suitable error alongside a fresh nonce when the one supplied is no longer valid. Downside to this approach is that the initial nonces validity is entirely opaque to the client (e.g it doesn’t know when it expires so it just has to try it).
  4. Dont return initial nonce from token endpoint, instead the client is expected to make a request to the credential endpoint omitting the nonce and expects the request to fail on purpose so it can obtain a valid nonce. Downside is sending knowingly invalid requests.

Also as a related FYI, there is some language to relax the normative statements around c_nonce related to this PR that Oliver Terbu is going to submit a PR for

Comments (37)

  1. Kristina Yasuda

    SIOP call - agreed to take time to understand the attack, what we are trying to prevent to choose the best option.

  2. Torsten Lodderstedt

    From my perspective, the attack we want to prevent is replay of a proof of possession for key material. What does this mean? In such a case, an attacker would try to bind a credential to key material for which he (the attacker) does not control the respective private key. I assume such a credential would contain data determined by the attacker.

    I assume the attacker would subsequently try to trick the victim to use this credential.

    What objective could the attacker achieve by mounting such an attack?

  3. David W Chadwick

    You can protect against replay e.g. from a MITM, by letting the sender insert its own nonce. The nonce does not have to be provided by the recipient.

  4. Tobias Looker reporter

    Having the nonce provided by the recipient significantly increases their confidence around when the proof of possession was done. Without it there is the potential that the attacker pre-computed the PoP (therefore its debate-able whether its even truely acting as a PoP). If the PoP is time bound by the sender too, the recipient has to trust their clock (or assertions about the time when the PoP was made).

  5. David W Chadwick

    I would expect the sender to insert an expiry time for the nonce, and if this is only a short distance from “now”, but is sufficient to cater for clock skew, then it should be sufficient for our purposes. We can place a size requirement on the size of the nonce to help to counteract pre-computations (and on the algorithm to use).

  6. Tobias Looker reporter

    Yes but the client could lie, so this expiry time does not protect against nonce/pop precomputation attacks

  7. David W Chadwick

    I do not understand your trust model. The client is providing an access token, and a PoP for a private key and it might lie about the expiry time?

  8. David W Chadwick

    Surely an attacker that can pre-compute the PoP if a strong crypto algorithm is being used must have massive computing power? And be able to intercept the TLS session and highjack the access token at the time it has pre-computed. So the user must be accessing the OP at the time this attacker pre-computed?

  9. Tobias Looker reporter

    I think we should follow the approach taken by DPoP instead, which is that the nonce value is one that is always created by an external party (in our case we only have one which is the credential issuer). If the credential issuer for whatever reason is willing to accept PoP’s without a nonce, then it should just be omitted from the PoP. To ensure some other source of uniqueness in the PoP’s without nonces we could also make use of the JTI claim as DPoP does.

  10. David W Chadwick

    I agree. It seems to me that the JTI claim serves a very similar purpose to a nonce created by the JWT creator (the client in our case) i.e. to stop replay. And the expiry time of the JWT serves a similar purpose to the expiry of the nonce.

  11. Kristina Yasuda

    in Aug-11 SIOP call we discussed three mechanisms: (client generated) “jti“, (server provided) “nonce“, and “at_hash“, which arguable serve different purposes. jti can help AS to detect if a proof is being used multiple times, but some ASs might not keep track of/check jti. nonce can help prove freshness of a generated proof, but is hard to implement for some AS because it requires changes to the token endpoint. at_hash does not really help with freshness or replay, because same access token can be reuse across multiple credential requests, but helps with binding proof to a user session. (is what I understood)

    {
      "alg": "ES256",
      "x5c":[<key certificate + certificate chain for attestation>]
    }.
    {
      "iss": "s6BhdRkqt3",
      "aud": "https://server.example.com",
      "iat": "fix",
      "jti": 1659145924, //one-time only
      "nonce": "tZignsnFbp", //fresh
      "at_hash": "hash of an Access Token" //bound to this transaction
    }
    

    + Brian pointed out “typ“: “JWT“ should not be used (PR #268)

  12. Kristina Yasuda

    I thought that jti is enough if replay of a proof is sufficient than proving freshness. but DPoP editors pointed out that if client environment is compromised or client is cooperating with the attacker, valid proofs with random jtis can be minted for future use, which was why DPoP added nonce. We discussed that we do not know if it is harder or easier to compromise native apps environment and pre-mint…

  13. Joseph Heenan

    I don’t have the sequence of events here clear enough to provide a really firm example of an attack. However after reading the above I’d be very nervous about removing the nonce without a thorough security analysis.

    The general problem with mobile app wallets (compared to a “traditional” server-based confidential client) is that the expected user (and often also anyone else that has the pin code) has a great deal of control over them. For example if we look at David’s earlier comment:

    It seems to me that the JTI claim serves a very similar purpose to a nonce created by the JWT creator (the client in our case) i.e. to stop replay. And the expiry time of the JWT serves a similar purpose to the expiry of the nonce.

    I believe the “expiry” time in the JWT is (at least in the simple obvious implementation) generated using the current time on the mobile device, which the user can trivially change so it can’t be relied on.

    Another thing that can be easy done are installing new CA root certificates to intercept/decode/change any TLS traffic using a man-in-the-middle style proxy server, then you get into the ‘less trivial’ area of things like attaching attaching debuggers to the wallet app that allow you to manipulate the application (which generally requires finding some kind of kernel level security bug).

    Most of these things you can probably mitigate to some extent (if you spend enough time/money/expertise on the wallet implementation), but really I think the only way you can guarantee freshness is with a server provided challenge. The server provided nonce is a pretty common method for achieving this; as well as DPoP they’re used in TLS, Apple’s device check APIs and so on.

  14. David W Chadwick

    Concerning the expiry time, I am less concerned about the user manipulating the date/time in the mobile phone, as the iat will change as well. The server should reject all JWTs that have an iat that is not near to “now” as determined by the server. Assuming the iat is approximately correct, then the exp can be relied upon by the server and this determines for how long the server must store the jti. Once this time has expired and the jti is forgotten by the server, then a new JWT with the same jti cannot be a replay of the forgotten one.

    So I think we should adopt a two fold approach.

    For issuers that are not issuing high value credentials (as determined by them), they will accept JWTs in which the replay and freshness are set by the client in the iat, exp and jti.

    For issuers that are issuing high value credentials, they will reject the previous JWTs and will return an error containing a nonce and nonce exp time, so that the client has to use these and repeat the issuance request with a new JWT containing the nonce and nonce exp time. This means that for high value credentials two round trips are necessary, but this seems to be an acceptable trade off given their higher value.

  15. Joseph Heenan

    Concerning the expiry time, I am less concerned about the user manipulating the date/time in the mobile phone, as the iat will change as well. The server should reject all JWTs that have an iat that is not near to “now” as determined by the server. Assuming the iat is approximately correct, then the exp can be relied upon by the server and this determines for how long the server must store the jti. Once this time has expired and the jti is forgotten by the server, then a new JWT with the same jti cannot be a replay of the forgotten one.

    Only iat seems to be a mandatory field if I’m looking in the right part of the spec. (So it’s optional for clients to send exp and jti currently.)

    Making some spec change that requires clients to send exp and jti sounds potentially sane (and presumably also setting some limit on the acceptable delta of exp vs iat so that it’s not possible to create proofs that are valid for years/millennia and/or require servers to remember jti values for stupidly long times).

    This unfortunately still wouldn’t prevent pre-generation (i.e. setting the device time to a time you want to use this JWT, generating it, then playing it to the server later). I don’t feel sufficiently expert on the specs to make a judgement call on if that is a good idea or not, vs always requiring a fresh nonce. What would be an example of a low value credential?

  16. David W Chadwick

    Examples of low value credentials might be:

    a VC to say I spent several hours on a project management course, for my CV;

    a member certificate for my local library,

    a BA entry level frequent flyer card.

  17. Kristina Yasuda

    However after reading the above I’d be very nervous about removing the nonce without a thorough security analysis.

    How about removing c_nonce from token response and adopting a DPoP model where

    • a basic model to check whether the client actually controls the key in the proof is jti

      • this could guarantee one time use of a proof if issuer is enforcing a jti check
      • does not guarantee freshness
    • when the issuer requires a fresh nonce to be included in the credential request, it will return an error with a fresh nonce to the first credential request (which is by default without a nonce) from the client

  18. Joseph Heenan

    Initial feeling is that I think that the nonce being just in the credential request/response is okay. It adds an extra roundtrip when the server wants to ensure freshness, but I presume we’re willing to accept that as a tradeoff.

    I still feel a bit nervous about defining a basic model that uses just jti. It’s maybe okay but I worry that that the value of a credential depends on the context it’s being presented in, which is unknown at the time of issuance I think? e.g. a BA entry level frequent flyer card is higher value if the account contains a high number of air miles and it’s being presented to use those air miles.

  19. Kristina Yasuda

    Credential type is passed in an authorization request /Issuance initiation request. Issuer already knows whether credential type is high assurance or not already.

  20. Kristina Yasuda

    Connect call 2022-08-22, agreed to adopt DPoP approach - mandatory jti and optionally nonce returned in a credential response - allowing issuer to pick a mechanism that works for it. Tobias to do a PR.

  21. Torsten Lodderstedt

    Couple of thoughts:

    1) The PR must also address the question whether a server provided nonce can be used for multiple proofs. I would assume so, especially in case of batch issuance requests (see PR #285). I think that is acceptable given the currently know threats this facility shall protected against (attacker minting a credential bound to key material under the victim’s control).

    2) We need a documented threat analysis. There are elements already in this ticket but I would feel more comfortable with having a comprehensive analysis and a documentation of security considerations in the spec. That will give us certainty and stability. My feeling right now is, the threats are not super critical meaning we can work with simpler means than originally expected.

    3) The current discussion entirely focusses on JWTs/JWS as means for proof of possession. However, the issuance spec is supposed to support all kinds of proof types including blinded proofs as used by anon creds, for example. This means the concept must be applicable to such proof types as well. I think this is possible since the conclusion as I read it so far is:

    • low security: client provides nonce, creation instant and expiration in the proof
    • high security: server provides nonce and expiration

    I think the spec should state it on this abstract level and provide a mapping to JWT as the first proof method, very much like the OpenID 4 VP spec does (https://openid.bitbucket.io/connect/openid-4-verifiable-presentations-1_0.html#name-preventing-replay-attacks).

  22. Kristina Yasuda

    wrt point 1. Client is using a simple credential endpoint (not batch issuance) to request issuance of two credentials that require server provided nonce. Issuer will have to throw back error two times and return two separate nonces, correct?

  23. Kristina Yasuda

    wrt point 3, can you please provide an example of how a proof format for anoncreds blinded proofs will look like. we can’t account for something that is not defined in the spec yet.

  24. Kristina Yasuda

    wrt point 2, there is an issue open. are you saying we should not do the PR for this issue before that analysis is complete?

  25. David W Chadwick

    One of my implementors today suggested that the RS should have an new “get-nonce” endpoint, which will return the c_nonce and expiry time to the wallet when requested. The advantages of this are:

    i) the OAuth2 server does not need to send the c_nonce to the wallet

    ii) the RS does not need to reject the first wallet request for a high security credentials that does not contain the c_nonce

    iii) the c_nonce and access_token can have different expiry times, so this allows a wallet with a valid access_token and an expired c_nonce to get a new c_nonce before making a credential request

    The suggestion was also that the issuer’s metadata should contain, for each supported credential type, whether the c_nonce was required or not, so that the wallet would never need to make a credential request without it. It will also require a new ‘get-nonce’ endpoint

  26. Joseph Heenan

    @David I worry this potentially overcomplicates things.

    I think a server should still be free to reject a request with an error that a new nonce is needed (even if the nonce hasn’t expired - either as a risk based decision, or because the old nonce has been somehow lost, or other reasons), and the client should be robust against that. It then seems simpler to just rely on that mechanism for all cases, rather than introducing new mechanisms for getting a nonce in advance.

  27. Torsten Lodderstedt

    I had a chat with Daniel about the nonce handling yesterday in the context of his overall security analysis.

    We came to the conclusion that server provided nonces give the issuer more implementation flexibility and they are more universal (as client provided nonces as discussed above do not work with non-JWT proofs). So we suggest to stick to this approach.

    We further propose to add clarifying text as follows: “The nonce provided by the issuer must be used for all proofs in any subsequent call to the credential endpoint until the issuer responds with a fresh nonce in a credential/batch or error response.” I think that also makes nonce handling for batch issuance clear.

    Note: c_nonce in token response is already optional, so an issuer only needs to implement nonce issuance at the issuance endpoint(s).

  28. David W Chadwick

    I think it would be good to add a complete (sub)section describing the use of c_nonce and jti so as to make it clear to implementers what the various options are. As I see it there are 4 possibilities

    1. The token endpoint returns c_nonce and the issuer always requires it. Issuance succeeds first time.
    2. The token endpoint never returns c_nonce and the issuer always requires it - in this case the first issuance request for a VC fails and returns the c_nonce.
    3. The token endpoint returns c_nonce and the issuer never requires it (it uses jti to stop replay). The nonce is ignored and the VC is issued.
    4. The token endpoint never returns c_nonce and the issuer never requires it (but requires jti). Success, the VC is issued.

    For cases 3 and 4 I think we should state that iat and exp are required to be inserted by the wallet/client.

  29. Torsten Lodderstedt

    I’m in favor of a (at least spec wise) simple approach. The wallet must use the nonce whenever the credential issuer provides one and this is the only specified mechanism. I don’t see the additional complexity of supporting jti as alternative pay off for any of the parties involved.

    I filed PR #383 on this issue.

  30. Log in to comment