frasertweedale / hs-jose

Haskell JOSE and JWT library
http://hackage.haskell.org/package/jose
Apache License 2.0
122 stars 46 forks source link

Verify JWT/JWS using a JWKSet #35

Closed edgmnt closed 7 years ago

edgmnt commented 7 years ago

There should be a helper that validates a JWT/JWS using a JWKSet instead of just one key. I'm not sure if we can do better than verifying against all keys in the JWKSet. Any thoughts?

This is useful for checking Google's JWTs, because they publish multiple keys as a JWKSet.

frasertweedale commented 7 years ago

Yep, we can do better. I need to think about what the API should look like. Ideas welcome.

edgmnt commented 7 years ago

I think it should look the same, but take a JWKSet instead of a JWK. The current validation policy stuff makes sense, e.g. one or all signatures must check out, but each can come from a different key in the set.

frasertweedale commented 7 years ago

I want to make sure that the type will admit a more general implementation in future, e.g. instead of a JWKSet, consider a map structure that looks up keys efficiently by "kid" or ""x5t#S256" parameter if present in the JWS header, otherwise performs a linear search (or aborts).

So something like:

class JWKStore a where
  keysFor
    -- parameters shared by JWS and JWE header
    :: ( HasAlg h, HasJku h, HasJwk h, HasKid h
       , HasX5u h, HasX5c h, HasX5t h, HasX5t_S256 h
       , HasTyp h, HasCty h )
    => h -> Fold a JWK

instance JWKStore JWK where
  ... -- constant fold; just the single key

instance Foldable t => JWKStore (t JWK) where
  ... -- constant fold; all the keys in the container

instance JWKStore JWKSet where
  ... -- constant fold; everything in the JWKSet

verifyJWS
  :: ( HasAlgorithms a, HasValidationPolicy a, AsError e, MonadError e m
     , HasJWSHeader h, HasParams h
     , JWKStore k )
  => a
  -> k
  -> JWS h
  -> m ()
verifyJWS = ...

This approach would allow verifyJWS to be used with both single JWK as well as a JWKSet or any Foldable t => t JWK. Existing code will be compatible.

And the JWKStore class can be used to build any (pure) key lookup structure that can use almost any information available in JWS or JWE header.

Sound alright?

Not sure when I'll get around to implementing it...

frasertweedale commented 7 years ago

I implemented it. Could you please review to see how well it meets your needs? (On master branch).

frasertweedale commented 7 years ago

@edgmnt ping. Does the current implementation meet your needs?

edgmnt commented 7 years ago

@frasertweedale Sorry it took me so long to reply. Yes, it's alright, although it should also work for JWTs, so validateJWSJWT should also take a JWKStore.

frasertweedale commented 7 years ago

Right, good point @edgmnt. I'll do that and hopefully cut a new release in the not too distant future.