Code Monkey home page Code Monkey logo

hs-jose's Introduction

jose - JSON Object Signing and Encryption & JWT (JSON Web Token)

jose is a Haskell implementation of JSON Object Signing and Encryption (JOSE) and JSON Web Token (JWT).

The JSON Web Signature (JWS; RFC 7515) implementation is complete. JSON Web Encryption (JWE; RFC 7516) is not yet implemented.

EdDSA signatures (RFC 8037) and secp256k1 signatures (RFC 8812) are supported.

JWK Thumbprint (RFC 7638) is supported.

Contributions are welcome.

Security

If you discover a security issue in this library, please email me the details, ideally with a proof of concept (frase @ frase.id.au ; PGP key).

Before reporting an issue, please note the following known vulnerabilities:

  • The ECDSA implementation is vulnerable to timing attacks and should therefore only be used for verification.

and the following known not-vulnerabilities:

Interoperability issues

The following known interoperability issues will not be addressed, so please do not open issues:

  • Some JOSE tools and libraries permit the use of short keys, in violation of the RFCs. This implementation rejects JWS or JWT objects minted with short keys, as required by the RFCs.

  • The Auth0 software produces objects with an invalid "x5t" parameter. The datum should be a base64url-encoded SHA-1 digest, but Auth0 produces a base64url-encoded hex-encoded SHA-1 digest. The object can be repaired (example) so that this library will admit it, unless the offending parameter is part of the JWS Protected Header in which case you are out of luck (until Auth0 bring their implementation into compliance).

  • JWKs with leading null bytes in the RSA "n" parameter (a violation of RFC 7518) have been seen in the wild. This library rejects nonconformant JWKs. If you know which programs/libraries produce such objects, please file bugs against them. It is straightforward to repair these keys: base64url-decode the offending parameter, drop the leading null byte, base64url-encode again then update the JSON object.

Contributing

Bug reports, patches, feature requests, code review, crypto review, examples and documentation are welcome.

If you are wondering about how or whether to implement some feature or fix, please open an issue where it can be discussed. I appreciate your efforts, but I do not wish such efforts to be misplaced.

To submit a patch, please use git send-email or open a pull request. Write a well formed commit message. If your patch is nontrivial, update the copyright notice at the top of the modified files.

hs-jose's People

Contributors

albertov avatar alexanderkjeldaas avatar brandon-leapyear avatar felixonmars avatar frasertweedale avatar gwils avatar haishengwu-okta avatar jaspervdj avatar lexi-lambda avatar mattaudesse avatar nghamilton avatar phadej avatar sajidanower23 avatar sophie-h avatar stevemao avatar tmcgilchrist avatar vmchale avatar whittle avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hs-jose's Issues

JWT: implement "nbf" and "exp" processing

Type of JWT validator is currently:

validateJWSJWT
  :: ValidationAlgorithms
  -> ValidationPolicy
  -> JWK
  -> JWT
  -> Bool

Propose implementing the "nbf" and "exp" checks required by the spec by
updating validateJWSJWT to have type such as:

validateJWSJWT
  :: ValidationAlgorithms
  -> ValidationPolicy
  -> JWK
  -> UTCTime
  -> JWT
  -> Bool

And providing a new function in IO that uses the current time:

validateJWSJWTAtCurrentTime
  :: ValidationAlgorithms
  -> ValidationPolicy
  -> JWK
  -> JWT
  -> IO Bool

implement "non-empty array" restrictions

Several places in the JOSE specs require non-empty arrays, but these requirements are
not currently encapsulated by the types or checked by the parser.

These should be implemented using Data.List.NonEmpty.NonEmpty from the semigroups package. Orphan FromJSON and ToJSON instances will be needed for this type, too.

JWT example in documentation incorrect

In the documentation the example reads:

signClaims jwk (newJWSHeader (Protected, alg)) claims

however, the type of signClaims is:

signClaims :: (MonadRandom m, MonadError e m, AsError e) => JWK -> JWSHeader () -> ClaimsSet -> m SignedJWT

In order for it to work the type would have to be:

signClaims :: (MonadRandom m, MonadError e m, AsError e) => JWK -> JWSHeader Protection -> ClaimsSet -> m SignedJWT

or the example would need to be changed to:

signClaims jwk (newJWSHeader ((), alg)) claims

Serialize one "aud" (Audience) Claim to JSON as string

In https://tools.ietf.org/html/rfc7519#section-4.1.3 - In the
special case when the JWT has one audience, the "aud" value MAY be a
single case-sensitive string containing a StringOrURI value.

In current implementation is a single value array, for example "aud": ["https://www.googleapis.com/oauth2/v4/token"] but that doesn't work for https://developers.google.com/identity/protocols/OAuth2ServiceAccount where they expect "aud":"https://www.googleapis.com/oauth2/v4/token"

Would it be possible to support singe string in
instance ToJSON Audience where
toJSON (Audience auds) = toJSON auds
?

Verifying tokens from Google's SecureTokens API

I am trying to verify tokens signed by Google's SecureToken service - https://developers.google.com/identity/toolkit/securetoken

Google is using the RS256 algo, and the public key is one of the keys provided at https://www.googleapis.com/robot/v1/metadata/x509/[email protected]

So to verify the tokens generated by Google, we need to parse and convert the keys provided at the above URL, and check if any of them successfully verify the token.

To parse each public key, I am using:

fromCertRaw :: ByteString -> Either Text X509.Certificate
fromCertRaw s = do
    pems <- fmapL toS $ Pem.pemParseBS s
    pem <- note "No pem found" $ headMay pems
    signedExactCert <- fmapL toS $ X509.decodeSignedCertificate $
                       Pem.pemContent pem
    let sCert = X509.getSigned signedExactCert
        cert = X509.signedObject sCert
    return cert

To convert the Certificate value to a JWK value:

certToJwk :: X509.Certificate -> Either Text JWT.JWK
certToJwk cert = do
    let X509.PubKeyRSA (PublicKey size n e) = X509.certPubKey cert
        jwk = JWK.fromKeyMaterial $ JWK.RSAKeyMaterial $
              JWK.RSAKeyParameters (JTypes.SizedBase64Integer size n)
              (JTypes.Base64Integer e) Nothing
        jwk' = jwk & JWK.jwkKeyOps .~ Just [JWK.Verify]
    return jwk'

I got signature verification working with something like this:

verifyIt :: ByteString -> JWT.JWK -> Either JWT.Error ByteString
verifyIt token key = do
    jws <- decodeCompact (toS token) :: (Either JWT.Error
                                         (JWS.CompactJWS JWS.JWSHeader))
    JWS.verifyJWS' key jws

Is this the right way to perform the verification?

If you like I could send part of this as a PR as it could help solve part of #62 - but I would need some help as I am not too familiar with lenses.

Caching getPOSIXTime calls

Hi there, thanks for this excellent library. I'm switching PostgREST to use it in PostgREST/postgrest#919, but we noticed one regression. It used to be that we protected the getPOSIXTime function using the auto-update library. This way when the server gets high traffic it doesn't have to make this relatively expensive system call every time, but only one second apart at most.

-- ask for the OS time at most once per second		
getTime <- mkAutoUpdate defaultUpdateSettings {updateAction = getPOSIXTime}

Previously, with a different jwt library, we were passing this time into the jwt validation function inside our request handler like this:

time <- getTime
-- use time when checking jwt expiration

Is it possible to include this optimization inside hs-jose?

Removing errors from API

A lot of functions in the API of this package throw errors, when it seems like if there were tighter types they wouldn't need to. This matters a lot to me since I'm writing a library (servant-auth) where I end up having to expose users to a lot of Eithers - even if they're using keys or whatever that will never fail.

For example, toCompact - in the case JWS, I'd imagine parameterizing by a Traversable

data JWS t a = JWS Types.Base64Octets (t (Signature a))

with t as Identity, we know encoding will succeed w.r.t the number of signatures, as there is only one signature. Alternatively, a different datatype representing encodable JWSs could be created, though if the signature of the toCompact method were to change, the current JWS couldn't be an instance of ToCompact (which is intuitively correct, since a lot of them are not encodable as compact!).

Would a PR with this be considered, or is it too substantial an API change (or might there be issues I'm not aware of)?

Construct JWK from X.509 certificate

Add a function to convert an X.509 certificate to a JWK.
The JWK should bear the certificate in its x5c field, and possibly
also the fingerprint(s) of the certificate in the x5t and x5t#S256
fields.

Missing and future JWSHeader parameters

IANA currently lists about 35 header parameters. JWSHeader implements about 11 of them. There are also drafts using keys that are not listed in the registry yet an I need to use them.

Is there already a way to add other parameters without creating a new type?

RE: JWT's and validation

What are your thoughts on adding a unsafeJWTClaims like function where we can get the claims in the JWT without claims validation (but still validate the signature).

My motivating case is we have multiple services running that pass a JWT for validation if the token just happens to expire in the middle of a transaction I'd like to refresh the token rather then abort the transaction, in order to refresh the token I would need to access the claims to use the identity to verify the token can still be refreshed.

I understand that the idea is to never use the JWT without it being valid so having a function prefaced with unsafe hopefully makes it clear that using it is more of an edge case then the norm.

Thoughts?

Build failure with GHC 8

> /tmp/stackage-build8$ stack unpack jose-0.4.0.1
Unpacked jose-0.4.0.1 to /tmp/stackage-build8/jose-0.4.0.1/
> /tmp/stackage-build8/jose-0.4.0.1$ runghc -clear-package-db -global-package-db -package-db=/home/stackage/work/builds/nightly/pkgdb Setup configure --package-db=clear --package-db=global --package-db=/home/stackage/work/builds/nightly/pkgdb --libdir=/home/stackage/work/builds/nightly/lib --bindir=/home/stackage/work/builds/nightly/bin --datadir=/home/stackage/work/builds/nightly/share --libexecdir=/home/stackage/work/builds/nightly/libexec --sysconfdir=/home/stackage/work/builds/nightly/etc --docdir=/home/stackage/work/builds/nightly/doc/jose-0.4.0.1 --htmldir=/home/stackage/work/builds/nightly/doc/jose-0.4.0.1 --haddockdir=/home/stackage/work/builds/nightly/doc/jose-0.4.0.1 --flags=
Configuring jose-0.4.0.1...
> /tmp/stackage-build8/jose-0.4.0.1$ runghc -clear-package-db -global-package-db -package-db=/home/stackage/work/builds/nightly/pkgdb Setup build
Building jose-0.4.0.1...
Preprocessing library jose-0.4.0.1...
[ 1 of 19] Compiling Crypto.JOSE.Types.Orphans ( src/Crypto/JOSE/Types/Orphans.hs, dist/build/Crypto/JOSE/Types/Orphans.o )

src/Crypto/JOSE/Types/Orphans.hs:22:1: warning: [-Wunused-imports]
    The import of ‘Control.Applicative’ is redundant
      except perhaps to import instances from ‘Control.Applicative’
    To import instances alone, use: import Control.Applicative()

src/Crypto/JOSE/Types/Orphans.hs:23:1: warning: [-Wunused-imports]
    The import of ‘Data.Traversable’ is redundant
      except perhaps to import instances from ‘Data.Traversable’
    To import instances alone, use: import Data.Traversable()

src/Crypto/JOSE/Types/Orphans.hs:25:1: warning: [-Wunused-imports]
    The import of ‘toList’
    from module ‘Data.List.NonEmpty’ is redundant

src/Crypto/JOSE/Types/Orphans.hs:27:1: warning: [-Wunused-imports]
    The qualified import of ‘Data.Vector’ is redundant
      except perhaps to import instances from ‘Data.Vector’
    To import instances alone, use: import Data.Vector()
[ 2 of 19] Compiling Crypto.JOSE.TH   ( src/Crypto/JOSE/TH.hs, dist/build/Crypto/JOSE/TH.o )

src/Crypto/JOSE/TH.hs:100:3: error:
    • Couldn't match expected type ‘Q Dec’
                  with actual type ‘CxtQ -> DecQ’
    • Probable cause: ‘dataD’ is applied to too few arguments
      In the expression:
        dataD
          (cxt []) (mkName s) [] (map conQ vs) (map mkName ["Eq", "Show"])
      In the first argument of ‘sequenceQ’, namely
        ‘[dataD
            (cxt []) (mkName s) [] (map conQ vs) (map mkName ["Eq", "Show"]),
          instanceD (cxt []) (aesonInstance s ''FromJSON) [parseJSONFun vs],
          instanceD (cxt []) (aesonInstance s ''ToJSON) [toJSONFun vs]]’
      In the expression:
        sequenceQ
          [dataD
             (cxt []) (mkName s) [] (map conQ vs) (map mkName ["Eq", "Show"]),
           instanceD (cxt []) (aesonInstance s ''FromJSON) [parseJSONFun vs],
           instanceD (cxt []) (aesonInstance s ''ToJSON) [toJSONFun vs]]

src/Crypto/JOSE/TH.hs:100:33: error:
    • Couldn't match expected type ‘Maybe Kind’
                  with actual type ‘[ConQ]’
    • In the fourth argument of ‘dataD’, namely ‘(map conQ vs)’
      In the expression:
        dataD
          (cxt []) (mkName s) [] (map conQ vs) (map mkName ["Eq", "Show"])
      In the first argument of ‘sequenceQ’, namely
        ‘[dataD
            (cxt []) (mkName s) [] (map conQ vs) (map mkName ["Eq", "Show"]),
          instanceD (cxt []) (aesonInstance s ''FromJSON) [parseJSONFun vs],
          instanceD (cxt []) (aesonInstance s ''ToJSON) [toJSONFun vs]]’

src/Crypto/JOSE/TH.hs:100:47: error:
    • Couldn't match type ‘Name’ with ‘Q Con’
      Expected type: [ConQ]
        Actual type: [Name]
    • In the fifth argument of ‘dataD’, namely
        ‘(map mkName ["Eq", "Show"])’
      In the expression:
        dataD
          (cxt []) (mkName s) [] (map conQ vs) (map mkName ["Eq", "Show"])
      In the first argument of ‘sequenceQ’, namely
        ‘[dataD
            (cxt []) (mkName s) [] (map conQ vs) (map mkName ["Eq", "Show"]),
          instanceD (cxt []) (aesonInstance s ''FromJSON) [parseJSONFun vs],
          instanceD (cxt []) (aesonInstance s ''ToJSON) [toJSONFun vs]]’

add complete JWT verification example

10:22 <frphank_> frase: other libraries' "verifyJWT" function takes 2 strings, the JWT and the secret.
10:22 <frphank_> where is this function
10:22 <frphank_> I had to write it
10:39 <frase> wtf, strings.  no wai man
10:40 <frphank_> well I ended up finding the fromOctets and decodeCompact functions eventually so it's not like it 
                 isn't supported
10:40 <frphank_> you just have to puzzle it together yourself

JWS.defaultValidationSettings is insecure

The current API for choosing validation settings promotes insecure usage of the library. The default validation settings allow the second attack detailed in this blog post to happen.

Consumers of this library should explicitly set which algorithm they expect a signature to have before validating it. The current defaults seem to trust client input of the 'alg' header

An example attack based on knowledge of the server public key (from the blogpost):

forgedToken = sign(tokenPayload, 'HS256', serverRSAPublicKey)

(Disclaimer: I only took a brief look. Sorry if I missed something)

add function from JWK to compatible JWS header

As a user of jose library, I want to load a JWK that will be used for signing,
and apply to it a function that returns a JWS header using an algorithm that
is "compatible" with the key type and size.

e.g. load a symmetric key, get HS256. Load an RSA key, get RS384.

The strongest compatible algorithm should be chosen by default.

Perhaps a companion function that allows user to further constrain the algorithm would
also be a good idea, e.g. to choose "more widely implemented" algos even if key size
supports stronger algo, based on required/recommended/recommended+ algos in RFCs.

JWT: implement "aud" check

In JWT spec:

4.1.3. "aud" (Audience) Claim

The "aud" (audience) claim identifies the recipients that the JWT is
intended for. Each principal intended to process the JWT MUST
identify itself with a value in the audience claim. If the principal
processing the claim does not identify itself with a value in the
"aud" claim when this claim is present, then the JWT MUST be
rejected. In the general case, the "aud" value is an array of case-
sensitive strings, each containing a StringOrURI value. In the
special case when the JWT has one audience, the "aud" value MAY be a
single case-sensitive string containing a StringOrURI value. The
interpretation of audience values is generally application specific.
Use of this claim is OPTIONAL.

Add an audience parameter to the JWT validation functions and check for
a match if the "aud" claim is present.

Verifying JWT with shared secret results in invalid signature error when using secret length less than 256 bits

When JWT verification is done via verifyClaims it results in JWSInvalidSignature, when using secret key length less than 32 characters (256 bits)

Steps to reproduce:

verify :: L.ByteString -> L.ByteString -> IO (Either JWTError ClaimsSet)
verify k s = runExceptT $ do
  let k' = fromOctets k      -- turn raw secret into symmetric JWK
       audCheck = const True  -- should be a proper audience check
  s' <- decodeCompact s    -- decode JWT
  verifyClaims (defaultJWTValidationSettings audCheck) k' s'
  1. Go to https://jwt.io/#debugger-io?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4ifQ.8OB07dpDCXm3FBT5I7v64oX2XoTqpLsj7OSdDWX8k6s

  2. Use a secret less than 32 characters long (e.g "mysecret").

  3. Copy the resulting JWT and run:

verify "mysecret" "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4ifQ.foxp_NGV2a8Yaikh-qBpx3LAro_jDUvyaKAqbGEv2K4"

Actual output:

Left (JWSError JWSInvalidSignature)

Expected output:
I don't know what the spec says, I did not read the spec. But it should be either of the following two:

  1. Spec doesn't mention anything about key size: Results in a claimset.
  2. Spec says should not validate if key size is less than 256 bits: Results in: Left (JWSError KeySizeTooSmall)

Version: 0.7.0.0


PS:

  1. If in the same jwt.io debugger if you increase the secret to be 32 characters, then the same verify
    function above results in a valid ClaimsSet.
  2. I did not generate a JWT using jose with key size less than 32 and try.
  3. I spent the better half of my evening trying to debug why it was an invalid signature, when infact the error was the key size was small.

Overlapping instance

There are overlapping instances defined for AsError without OVERLAPS/OVERLAPPABLE pragmas. Attempting to use Error as an AsError results in:

Overlapping instances for Jose.AsError Jose.Error
  arising from a use of ‘Jose.decodeCompact’
Matching instances:
  instance Jose.AsError Jose.Error -- Defined in ‘Crypto.JOSE.Error’
  instance Jose.AsJWTError e => Jose.AsError e
    -- Defined in ‘Crypto.JWT’
In the expression: Jose.decodeCompact
In the second argument of ‘($)’, namely
  ‘Jose.decodeCompact $ BSL.fromStrict hdr’
In the expression:
  withExceptT convertErr $ Jose.decodeCompact $ BSL.fromStrict hdr

The options are adding the overlapping pragmas, or making the instance for JWTError just instance AsError JWTError where {...}. The latter seems more reasonable to me, since

  • dealing with overlapping instances with makeClassy is a little full of boilerplate,
  • avoiding overlapping instances is always good, and
  • the current instance rules out any similar instances (i.e., AsError e), and it's not at all obvious to me conceptually why JWTError would get to do this.

PR #17 implements the second option.

(And thanks for the library, by the way!)

As a library user I want a more convenient way of filtering keys

Newtyping or defining one's own JWKStore type to implement new "filtering" rules,
e.g. ignoring keys whose "jku" or "alg" parameters are inconsistent with the operation being performed,
is quite burdensome. A more lightweight way of filtering keys is preferred, along with a set of
useful predefined rules.

JWK constructor for ECDSA Public Keys

It appears there is no way to create a Public Key for ECDSA because none of the constructors are exported. Is there a way around this. I'm willing to put in a PR if you have a vague idea for how you'd like to do this.

test/JWT.hs: error: Duplicate instance declarations

In Stackage Nightly:

test/JWT.hs:54:10: error:
    Duplicate instance declarations:
      instance Monad m => MonadTime (ReaderT UTCTime m)
        -- Defined at test/JWT.hs:54:10
      instance [overlapping] [safe] Monad m =>
                                    MonadTime (ReaderT UTCTime m)
        -- Defined in ‘Control.Monad.Time’
   |
54 | instance Monad m => MonadTime (ReaderT UTCTime m) where
   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Custom JWTValidationSettings

In the example it shows verifying a jwt.

doJwtVerify :: [String] -> IO ()
doJwtVerify [jwkFilename, jwtFilename] = do
  Just jwk <- decode <$> L.readFile jwkFilename
  jwtData <- L.readFile jwtFilename
  result <- runExceptT (
    decodeCompact jwtData
    >>= validateJWSJWT defaultJWTValidationSettings jwk)
  case result of
    Left e -> print (e :: JWTError) >> exitFailure
    Right _ -> exitSuccess

How would one construct an alternative JWTValidationSettings than what defaultJWTValidationSettings gives you?

In particular I am trying to verify that the audience is correct.

How to construct HMAC-SHA256 from simple string?

I'm working on code which can either load a full JWK from a file in its normal JSON format, or else construct a HMAC-SHA256 key from just a secret string. I intend this key to be used to verify a signed (not encrypted) JWT. Can't get the following snippet to compile though because I don't know how to construct the KeyUse (it's defined with template haskell somehow).

import Data.ByteString.Base64  (encode)

hs256jwk :: ByteString -> JWK
hs256jwk key =
  fromKeyMaterial km
    & jwkUse .~ Just "sig"
    & jwkAlg .~ Just (JWSAlg HS256)
 where
  km = OctKeyMaterial (OctKeyParameters Oct (Base64Octets b64))
  b64 = encode key

Am I even going about this the right way?

Verify JWT/JWS using a JWKSet

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.

jose-0.3.38.0 can't compile its own test suite

Citing from http://hydra.cryp.to/build/606676/nixlog/1/raw:

Preprocessing test suite 'tests' for jose-0.3.38.0...

test/Test.hs:17:8:
    Could not find module ‘JWK’
    Use -v to see a list of the files searched for.

test/Test.hs:18:8:
    Could not find module ‘JWS’
    Use -v to see a list of the files searched for.

test/Test.hs:19:8:
    Could not find module ‘JWT’
    Use -v to see a list of the files searched for.

test/Test.hs:20:8:
    Could not find module ‘Types’
    Perhaps you meant
      CTypes (needs flag -package haskell98-2.0.0.3)
      Type (needs flag -package ghc-7.8.4)
    Use -v to see a list of the files searched for.

Can't decode JWKSet if thumbprint is not 20 bytes (incorrect number of bytes)

Hi!
While trying to decode JWKSet from Auth0 I stumbled on an issue when decoding fails because x5t is more than 20 bytes (I'm getting Left "Error in $.keys[0].x5t: incorrect number of bytes").
Here is the value:

"x5t":"RTBFQjE3MEU0QjQ2M0FCNkYxRTEwMUIwNTJFOUY1NDgyMjgzRTI1NQ"

The decoded value for this is:

E0EB170E4B463AB6F1E101B052E9F5482283E255

It has 40 characters in hex, so I think it will be 20 bytes when in binary.

This is the JWK set coming from https://auth0.com

The full set if needed:

{  
   "keys":[  
      {  
         "alg":"RS256",
         "kty":"RSA",
         "use":"sig",
         "x5c":[  
            "MIIDATCCAemgAwIBAgIJFZEwRAGW4NzQMA0GCSqGSIb3DQEBCwUAMB4xHDAaBgNVBAMTE2xlb250aS5hdS5hdXRoMC5jb20wHhcNMTcwNzA5MDk1OTU3WhcNMzEwMzE4MDk1OTU3WjAeMRwwGgYDVQQDExNsZW9udGkuYXUuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApSUFVpIv+kiRsIw6M9R2JqXFofwHM7JXo022PkDFiIsgu1UtKV4ubLssA3hrmJAx1n+jSENifzMEl6ppyh4cmnTbV5XVKNjUm8D7+DsKYebTaf5tbvTTCiil7t4YMWcwIbHudF6j6NFDxXy3c2A0oCOA7+edMOVXXKAbE6/QyE+Z59pa2PkEFWQbE13R4GXewHqtOmuzBj0bKN9mj37tPAaAluizhrE60sK97Xn49wIizunJlquUJycoF093adz0nfJRk/scchID0Dg+MgDNePLUtfCEkGMYDPgwepDUfsOaQDNlssxRGxaFgrK3U6ASMSLkoqP2gCcX9t+uWbO/9QIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBT8lWNl0h7CwDPWEN/WVzh55xwYBjAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADggEBAFWJRIuxuPAfX8chXZ2ZEXK+70DGMbw42XWZxNCnhAaPWftPcybvws24LWdxVrYCOngTIQo5ezOsELVjn6mO8TDHvp5L8oeGLCLyTHe4sTw+7rKjV9wyS5DH6xH/40h8CuUEyXghiMAE6r5weCcUQ9r21VpNvLdK+O9LSwnBUCcjOqM4RFazbeVqVMjGWOCP/j9nHpPW5/18YHTTUV5pIrS/STzlGaQ/oeu7GImQSea/Zxsgmw+bkSyT/p5eyDOrlMcc3fwB1LJB72oA3hYj44ndj9gel8dQzWwNb3YKeDbDDUHjGyEfcW+D9HYDAtmgRedOxAt4YGVa7abjwUvfWos="
         ],
         "n":"pSUFVpIv-kiRsIw6M9R2JqXFofwHM7JXo022PkDFiIsgu1UtKV4ubLssA3hrmJAx1n-jSENifzMEl6ppyh4cmnTbV5XVKNjUm8D7-DsKYebTaf5tbvTTCiil7t4YMWcwIbHudF6j6NFDxXy3c2A0oCOA7-edMOVXXKAbE6_QyE-Z59pa2PkEFWQbE13R4GXewHqtOmuzBj0bKN9mj37tPAaAluizhrE60sK97Xn49wIizunJlquUJycoF093adz0nfJRk_scchID0Dg-MgDNePLUtfCEkGMYDPgwepDUfsOaQDNlssxRGxaFgrK3U6ASMSLkoqP2gCcX9t-uWbO_9Q",
         "e":"AQAB",
         "kid":"RTBFQjE3MEU0QjQ2M0FCNkYxRTEwMUIwNTJFOUY1NDgyMjgzRTI1NQ",
         "x5t":"RTBFQjE3MEU0QjQ2M0FCNkYxRTEwMUIwNTJFOUY1NDgyMjgzRTI1NQ"
      }
   ]
}

Cheers,
Leonti

Perform key sanity check when verifying signatures

Currently if a key is too small, the verification fails with InvalidSignature instead
of KeySizeTooSmall. Add a key sanity check step before attempting to validate
the signature so that the appropriate error gets returned to the caller.

Thanks to @begriffs for reporting.

JWT verification vulnerable to header manipulation

It looks like Crypto.JOSE.JWS.verifySig gets the key type from the unverified header:

verifySig k m (Signature raw h (Types.Base64Octets s)) = 
  verify (param (view jwsHeaderAlg h)) (view jwkMaterial k) tbs s where [...]

And here's what the callee does:

verify JWA.JWS.None _ = \_ s -> Right $ s == ""

An attacker could simply substitute None for the key type in the header and clear out the signature.

Issue #5 might've been closed too soon.

JWT Invalid

Hi, I have a JWT and JWK issued by Auth0 that get a systematic JWSError JWSInvalidSignature on validation.

Here's a sample JWT
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlJEWTVSVEpFTVRReFF6WTBPVFkzT0VORk1UUXpPVEU1UXpORFFVSTBNVVl4UkRnMU5VUXdSUSJ9.eyJpc3MiOiJodHRwczovL2xvYmJ5Y2l0b3llbi5ldS5hdXRoMC5jb20vIiwic3ViIjoibFptdTQzdDJXQjBrWm1sQzV3ZmxoTVVQOFY3bzlNemRAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vd3d3LmxvYmJ5LWNpdG95ZW4tYXBpLWF1dGguZnIvIiwiZXhwIjoxNTA2NDk5ODExLCJpYXQiOjE1MDY0MTM0MTEsInNjb3BlIjoiIn0.NxFEQy_vhFR_zjkNqq8wkCmdhs8sdyiB4SNuh3sKDwgGZpxQAq5CsqYzmkLl5A9nF1wRp0lwyYVncx3_ctaILJ92cpoM2478CNzDPzCKTydUzABgwK6Jo9L-R8A2FGjPRtMeMxpkhTTlclEo6ERIXocVQa6-Oeji42nwmQEjJkkdX4iTBl0DgsqrfrfPPxa1XtvF5MyjT6U8XlV_65C1zXcayhA2nhykIhbw5atht_yUkrhdbYEihZblaUTy7cfmEYpqeNTJxLRyQ30wPvccXi2bQgq7Sq7VIFP_S-dHERk6LXTbase0bu7QR_XA5w6lyOs7oXVbF5Jr8adrMh2R6g

and here's the JWK

{"alg":"RS256","kty":"RSA","use":"sig","x5c":["MIIDDTCCAfWgAwIBAgIJTegPuD4Mvm6sMA0GCSqGSIb3DQEBCwUAMCQxIjAgBgNVBAMTGWxvYmJ5Y2l0b3llbi5ldS5hdXRoMC5jb20wHhcNMTcwODAyMTQ1MjM2WhcNMzEwNDExMTQ1MjM2WjAkMSIwIAYDVQQDExlsb2JieWNpdG95ZW4uZXUuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvVzlh+IW4I95QelKKZyDjbVv0tLBvEo/jE9ndTCigjPHrtHzjAg+aB+u/KBYkF9CxT8nRWutm9GB9tXvg7z7n4U2fd4qZGLH6xFmIzqAJKwe7Z3l2fSqI1jJw4KLfYfGvAqP9qrETb8cH7jpEoI9nXp7a0GQ/BftQUk0qmczN9yLp+k0UGXtUNrJXJ7hWjpVcG7wRGHDZ9plbQZ9WmMJUFlPIn7Yvar1GhZNozz+37pD3a/DkE+uIQ1zhgMRcZhl6Sb3zjKn7l7XrMjuZJ7afSNHaXicrIhHS2/J3FtmDlR4/cha4H/jBVKzlUd+zB+pFMoOd1hnxE773b8ZVQ9dcwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSzoceBhNJklZTlVIox/Kpq1cWUszAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADggEBAKFgVJ/SAcp32TsW/RlhjRBcSZ3cQKGjpMGs2FMm4dvZocPSIezK8KQt9Vq6K+H6/gePmTa9/z1wQTWsRSI+a6/RJ8rXbLiHovuFC5ilpcDGrBJj2KDkSYPfc0E9B0eXeeZSe7TVY6gbOKvut3mVESuZP/+r36ieyIiIVWIkoZrOULniCUxClFRRNYfl9AnvC18buxK69MjNNUYtvmL1hE9CWyptBM1Pjlo1e4qMMusn9Jm2EHNf9j0e0b1gaV4z4OL+uOE756P9ef8XxLbE5cuqt3fDXi9qFLvTy0wlFaZB1P39rt6JkWTiilB4dT06JxursJTEY0fKtWimKbhQd3Y="],"n":"vVzlh-IW4I95QelKKZyDjbVv0tLBvEo_jE9ndTCigjPHrtHzjAg-aB-u_KBYkF9CxT8nRWutm9GB9tXvg7z7n4U2fd4qZGLH6xFmIzqAJKwe7Z3l2fSqI1jJw4KLfYfGvAqP9qrETb8cH7jpEoI9nXp7a0GQ_BftQUk0qmczN9yLp-k0UGXtUNrJXJ7hWjpVcG7wRGHDZ9plbQZ9WmMJUFlPIn7Yvar1GhZNozz-37pD3a_DkE-uIQ1zhgMRcZhl6Sb3zjKn7l7XrMjuZJ7afSNHaXicrIhHS2_J3FtmDlR4_cha4H_jBVKzlUd-zB-pFMoOd1hnxE773b8ZVQ9dcw","e":"AQAB","kid":"RDY5RTJEMTQxQzY0OTY3OENFMTQzOTE5QzNDQUI0MUYxRDg1NUQwRQ","x5t":"RDY5RTJEMTQxQzY0OTY3OENFMTQzOTE5QzNDQUI0MUYxRDg1NUQwRQ"}

I can't seem to find the issue as it validates well on jwt.io...

Thanks a lot for your help!

optics for StringOrURI

Currently StringOrURI uses some not very nice functions for parsing and getting at the possible values.
Prisms would be better.

Also note that the current implementation is not quite right: we interpret anything that does not parse as a URI as an arbitrary string value, but according to https://tools.ietf.org/html/rfc7519#section-2, any value that contains a ':' MUST be a URI. So this should be fixed at the same time.

JWK.Alg not exported

The Crypto.JWK module does not export the Alg type and it's constructors. I'm not sure why, or how to get the JWS algorithm of a JWK without that.

[Question] replacing removed `fromString` when upgrading to 0.6

While migrating from 0.5 to 0.6 (for the posgrest project) I have to face 9ed8fe1 and the change from Text to String in StringOrUri.

What is the idiomatic way to replace the removed fromString function ? As the comment on the PR suggests, the following does not seem satisfying:

Text -> StringOrUri

let audience' = fromJust $ preview stringOrUri audience

Thanks for your help

Build failure with QuickCheck 2.9

> /tmp/stackage-build8$ stack unpack jose-0.4.0.2
Unpacked jose-0.4.0.2 to /tmp/stackage-build8/jose-0.4.0.2/
> /tmp/stackage-build8/jose-0.4.0.2$ runghc -clear-package-db -global-package-db -package-db=/var/stackage/work/builds/nightly/pkgdb Setup configure --package-db=clear --package-db=global --package-db=/var/stackage/work/builds/nightly/pkgdb --libdir=/var/stackage/work/builds/nightly/lib --bindir=/var/stackage/work/builds/nightly/bin --datadir=/var/stackage/work/builds/nightly/share --libexecdir=/var/stackage/work/builds/nightly/libexec --sysconfdir=/var/stackage/work/builds/nightly/etc --docdir=/var/stackage/work/builds/nightly/doc/jose-0.4.0.2 --htmldir=/var/stackage/work/builds/nightly/doc/jose-0.4.0.2 --haddockdir=/var/stackage/work/builds/nightly/doc/jose-0.4.0.2 --flags=
Configuring jose-0.4.0.2...
> /tmp/stackage-build8/jose-0.4.0.2$ runghc -clear-package-db -global-package-db -package-db=/var/stackage/work/builds/nightly/pkgdb Setup build
Building jose-0.4.0.2...
Preprocessing library jose-0.4.0.2...
[ 1 of 19] Compiling Crypto.JOSE.Types.Orphans ( src/Crypto/JOSE/Types/Orphans.hs, dist/build/Crypto/JOSE/Types/Orphans.o )

src/Crypto/JOSE/Types/Orphans.hs:53:10: error:
    Duplicate instance declarations:
      instance Arbitrary a => Arbitrary (NonEmpty a)
        -- Defined at src/Crypto/JOSE/Types/Orphans.hs:53:10
      instance [safe] Arbitrary a => Arbitrary (NonEmpty a)
        -- Defined in ‘Test.QuickCheck.Arbitrary’

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.