Historical Keys should show validaty status

Issue #1757 resolved
Mischa Salle created an issue

Keys might have been rotated because the private key has leaked. That makes anything signed with that key untrustworthy. Hence I think it is probably good to distinguish between normal expiry and revocation and for the latter include the time of revocation.

In principle this could be done using expiry and the `exp` claim, but revoked keys can no longer reliably be used for anything unlike normally rotated and expired keys. The latter can in principle be used to confirm that a chain was valid before it’s expiry date.

See also e.g. https://pki-tutorial.readthedocs.io/en/latest/cadb.html for OpenSSL’s index.txt format, which has a flag for valid, revoked and expired and a timestamp for revocation or expiration.

Comments (20)

  1. Giuseppe De Marco

    Thanks, useful tip. We should start with a proposal to discuss

    A solution could be to introduce the claim status with a set("v", "r", "e")

    where (v=valid, r=revoked, e=expired)

  2. Mischa Salle reporter

    That sounds reasonable.
    Also, thinking again, I’d say we should have a separate claim for the revocation time and not re-use the exp claim for that. That claim would of course only make sense when the status is revoked, so perhaps they should be bundled into an array?

    And should we include the reason? That could be sensitive information, so perhaps we don’t want to expose that?

  3. Giuseppe De Marco

    Your reasoning makes sense.

    We can create a new claim attesting, in an array, the properties of the revocation, such the revocation time.

    or, differently, we can define the revocation time claim independently of the revocation json object, if adopted.

    Do you have a proposal for this brand new claim name?

    I'll reach out the other authors of the specs to work on this, meanwhile if you can do a proposal for the claim name, or for the schema of the revocation object, it would be great

  4. Mischa Salle reporter

    I think the easiest is to just add a single revocation time claim. For example rat or revoked_at ?

    Not sure actually we need the status claim. Other than for the revoked, the status follows (currently) from the iat, exp and nbf claims. And the revoked status would follow from the presence of the revocation time claim.

    If we also need the reason, we could then bundle them in something like

    "revoked": {
      "revoked_at": 1672392712,
      "reason": "keyCompromise",
    } 
    

    or we could make also that into a separate claim, something like revocation_reason. That is probably easier, in case we don’t always want to add a reason. So personally I think 1 or two extra simple claims is probably the easiest.

  5. Giuseppe De Marco

    I personally think that your proposal definitively wins.

    I'm for revoked_at with the json object

    We should define the set of values for the claim “reason”

  6. Giuseppe De Marco

    Hi Misha,

    I agree for the adoption of the same values we have in rfc5280 (even if not snake cased, it’s not relevant)

    To date I have not matured any interest in an entity statement revocation mechanism because with a request to the fetch endpoint we can get the status of a descendant in realtime (or even a 404, which indicates exclusion). We could rather enable the historical register of the jwks also for the intermediaries, to manage historical episodes which concern the compromise of a key used to sign an entity statement.

    please feel free to put your notes here, I’ll discuss these with the other authors, and thank you for this precious issue!

  7. Vladimir Dzhuvinov

    What are your thoughts on publishing the revoked keys at a new, separate endpoint?

    Open Banking UK has taken this approach for the members of its “federation”. There is an org_jwks_endpoint where the good keys are published. And then, there is an org_jwks_revoked_endpoint where revoked keys are placed (but there is no reason metadata).

    https://openbanking.atlassian.net/wiki/spaces/DZ/pages/36667724/OpenBanking+OpenID+Dynamic+Client+Registration+Specification+-+v1.0.0-rc2#OpenBankingOpenIDDynamicClientRegistrationSpecification-v1.0.0-rc2-SoftwareStatementAssertion(SSA)

    The main argument for having a separate endpoint is that client code that uses the org_jwks_endpoint cannot accidentally pull in revoked keys and somehow end up using them to verify a signature. The JWK RFC also says this about JWK params:

    https://www.rfc-editor.org/rfc/rfc7517#section-4

    Additional members can be present in the JWK; if not understood by
    implementations encountering them, they MUST be ignored.

    The JWK spec defines no crit parameter (like the JWS spec does to designate “MUST understand” headers), meaning that all currently available JWT libs will simply ignore a revoked JWK parameter. Updating all those libs to support the new revoked parameter could take a long time, which means that some OIDC Federation developers may simply end up using JWT libs with their default settings. A separate JWKs endpoint seems the safer choice for me.

  8. Vladimir Dzhuvinov

    PS following a chat with Giuseppe:

    I wasn't aware this was intended for the historical JWKs endpoint. I thought it was meant for the entity statements in general :)

  9. Mischa Salle reporter

    considering this is primarily about the jwks claim in the well known endpoint openid-federation-historical-jwks response, perhaps it would then be better to make it two claims jwks and jwks_revoked ?

    I do agree with your reasoning that we need to ensure that clients don’t accidentally use them. In principle the same is true for expired keys: people will not usually revoke an expired key in case of leaks. So you cannot trust expired keys either.

    Also, I think it would be good to use the same setup as others, but I’m not sure that works here, the Open Banking spec has current and revoked keys, not past (rolled-over or expired but not necessarily revoked), while fed now has current and historic.

  10. Vladimir Dzhuvinov

    With the clarification that the revoked keys will only appear in the response from the historical JWKs endpoint - placing them together with the expired keys seems okay to me, because as you say, they are all keys that should be no longer in use (whatever the reason).

    How is the endpoint going to find out or become updated that a key is revoked?

    For the iat and exp there is a method - whenever an subordinate entity enrols a new JWK set it can be diffed against the previous version. But how can this work with a revoked key?

  11. Giuseppe De Marco

    I’m wondering if there may be some cases where an already expired key is found as leaked in the past, so it should be revoked in the present even if it is expired.
    In this case an expired key should be also revoked to tell to all the participants in the federation that the historical trust chains, validated with that key, may be unsafe.

    I would not create a separate schema or top-claim for the revoked keys but just the json object carrying the revocation properties (revocation reason, date of revocation)

    How is the endpoint going to find out or become updated that a key is revoked?

    Administrative process, federation operators that handles the responsible disclosure of the leakages will remove the leaked jwks fron the TA’s entity configuration and move these in the historical endpoint, with the reason of the revocation.

    a TA only publish in its EC the jwks intended for the validation of the signatures issued by it.
    All the expired and revoked jwks should be published in the historical jwks registry.

    considering that historical has a meaning more closer to “expired” I’m wondering if, considering how we increase the awareness on the revocation ops and the scope of this endpoint, we should rename this endpoint.

    the discussion is open and I hope to resolve this feature in the current draft if the authors agree.

  12. Giuseppe De Marco

    I’d proceed with a PR with the solution below:

    "revoked": {
      "revoked_at": 1672392712,
      "reason": "keyCompromise",
      "reason_code": 1
    } 
    

  13. Vladimir Dzhuvinov

    I’m wondering if there may be some cases where an already expired key is found as leaked in the past, so it should be revoked in the present even if it is expired.
    In this case an expired key should be also revoked to tell to all the participants in the federation that the historical trust chains, validated with that key, may be unsafe.

    This is an entirely plausible scenario. Very often incidents are discovered after the fact.

    How is the endpoint going to find out or become updated that a key is revoked?

    Administrative process, federation operators that handles the responsible disclosure of the leakages will remove the leaked jwks fron the TA’s entity configuration and move these in the historical endpoint, with the reason of the revocation.

    My concern was chiefly about incidents at entities below the TA. Whether this can be automated, to a good effect. Because with X.509 certs, revocation, as a whole, seldom works well in practice.

    I’d proceed with a PR with the solution below:

    Looking forward to it!

  14. Giuseppe De Marco

    My concern was chiefly about incidents at entities below the TA. Whether this can be automated, to a good effect. Because with X.509 certs, revocation, as a whole, seldom works well in practice.

    @Vladimir Dzhuvinov that’s why I would like to purpose in the PR, if you agree, to enable this endpoint for all the federation_entity (TA and intermediaries)

  15. Log in to comment