sigstore / fulcio

Sigstore OIDC PKI
Apache License 2.0
659 stars 139 forks source link

Proposal: Proof of Possession should bind key to identity & token #975

Open haydentherapper opened 1 year ago

haydentherapper commented 1 year ago

Description

Replay of a proof of possession (PoP) to associate a key with a different identity is currently possible (albeit difficult, since you must intercept the PoP somehow).

A proposal would be to generate a PoP over the identity of the token, the identity being the subject AND provider. Currently, only the subject is signed over. Furthermore, a CSR can be provided as a PoP, but Fulcio currently ignores the value of the subject. The CSR should sign over the subject and provider of the identity token (brought up in https://github.com/sigstore/fulcio/issues/863#issuecomment-1343459762)

We can go one step further, and bind a specific token to a PoP, by including the token nonce. The signature would then be Sign(token.Subject, token.Issuer, token.Nonce) (for the CSR, maybe we'd include the nonce as an extension, implementation details TBD).

Thoughts @znewman01 @asraa @woodruffw?

Note: Not in scope is reuse of the OIDC token (which is a feature to some clients that cache OIDC tokens) or reuse of the signing key (Fulcio does not assert ephemerality, since some users may manage their own keys)

Lofty idea: PoPs are weaker than challenges, when a server presents a nonce to sign over, for replay prevention. The server could provide a challenge for clients to sign. This ends up looking a lot like ACME, so maybe Fulcio should implement the ACME protocol? This may be overkill, because users won't be hosting the challenge over HTTP/DNS. Needs more exploration.

woodruffw commented 1 year ago

This sounds pretty good to me! Anything that ratchets down the PoP is nice, even if intercepting the PoP is not a particularly likely attack scenario. +1 additionally to using the OIDC token's nonce in the PoP as well 🙂

One thing I want to make sure I understand: this has no meaningful effect on an attacker who intercepts the PoP (as (CSR, OIDC-token) and uses the intercepted OIDC-token to generate an entirely new CSR, correct? In that case the malicious CSR would be detected solely through the transparency log.

haydentherapper commented 1 year ago

Correct! The transparency log should be sufficient for that case. Another option would be to persist token nonces to prevent reuse, but this would break some client use cases that want to cache and reuse tokens. Relying on the transparency log and checking for an expected number of identities in the log should be good.

woodruffw commented 1 year ago

Correct! The transparency log should be sufficient for that case. Another option would be to persist token nonces to prevent reuse, but this would break some client use cases that want to cache and reuse tokens. Relying on the transparency log and checking for an expected number of identities in the log should be good.

Makes perfect sense! And agreed 100% on the CT log being sufficient 🙂

(This is making me again wish we could do key-binding on the OIDC token itself, but that seems like a remote possibility with the current IdPs...)

znewman01 commented 1 year ago

A proposal would be to generate a PoP over the identity of the token, the identity being the subject AND provider. Currently, only the subject is signed over. Furthermore, a CSR can be provided as a PoP, but Fulcio currently ignores the value of the subject. The CSR should sign over the subject and provider of the identity token (brought up in https://github.com/sigstore/fulcio/issues/863#issuecomment-1343459762)

I think this is a great idea for both our PoP or CSRs. I also am in favor of shifting toward CSRs more generally from our PoPs.

Lofty idea: PoPs are weaker than challenges, when a server presents a nonce to sign over, for replay prevention. The server could provide a challenge for clients to sign. This ends up looking a lot like ACME, so maybe Fulcio should implement the ACME protocol? This may be overkill, because users won't be hosting the challenge over HTTP/DNS. Needs more exploration.

My dream here is to extend ACME to support a JWT "challenge type." There's an existing draft RFC that extends ACME for "End User Client and Code Signing Certificates" that has sort-of stalled. It alludes to but does not cover JWT challenges. I would like to (1) revive and finish that draft RFC, and (2) create a new RFC for JWT challenges, with which Fulcio could comply. (CC @joshuagl )

(This is making me again wish we could do key-binding on the OIDC token itself, but that seems like a remote possibility with the current IdPs...)

Would something like DPoPs get us there? See this analysis (you may need to join sigstore-dev@googlegroups.com for access).

Or are you talking about basically having IdPs operate as CAs?

haydentherapper commented 1 year ago

Interesting RFC! Happy to chat more about it if you start work on reviving it.

woodruffw commented 1 year ago

Would something like DPoPs get us there? See this analysis (you may need to join sigstore-dev@googlegroups.com for access).

Yep, I think so -- I was thinking of the <aud>?pkid=<H(DER(SPKI))> idea that came up in that recent "Sigstore without Sigstore" paper, but DPoP seems to be (from my reading) a generalization of the same key binding property!

arianvp commented 1 year ago

There is https://datatracker.ietf.org/doc/draft-acme-device-attest/00/. It doesn't use JWS signatures but WebAuthn signatures (The same that are used by Passkeys)

arianvp commented 1 year ago

https://solidproject.org/TR/oidc#tokens-id has a WIP spec for DPoP-id_tokens btw

asraa commented 1 year ago

Overall yes, I agree. I found it interested that only the token subject is signed over as proof of posession of the key, which means you can replay it with a different OIDC token whose issuer is different.

I badgered myself on this a lot, but it's only a very sneaky attack that requires a shady OIDC provider or squatting an account with the same subject in order to fool someone that you've also signed something that was ALREADY signed. Because you don't have private key access, you can't spoof a NEW signature.

Regardless, I still think it's important to do :) Because I don't like the idea of using the subject from the signed challenge, but the issuer from the OIDC token, which may mismatch.

I also am in favor of shifting toward CSRs more generally from our PoPs.

I think so too. I'm a little less familiar with the way this would work, but from my understanding Fulcio must verify the OIDC token, the CSR, and then ensure that the CSR subject and extension values match the OIDC token in order for this to work, right?

haydentherapper commented 1 year ago

We aren’t verifying the CSR subject currently, it’s just a vehicle for the public key. With this proposal, yes, we must verify both the subject and an extension in the CSR match what’s in the token.

A small detail is extensions in CSRs are a bit of a pain to add in OpenSSL, but it’s doable, just need some examples.