packages feed

jose 0.7.0.0 → 0.8.0.0

raw patch · 17 files changed

+525/−240 lines, 17 filesdep +unixdep ~semigroupsdep ~textPVP ok

version bump matches the API change (PVP)

Dependencies added: unix

Dependency ranges changed: semigroups, text

API changes (from Hackage documentation)

- Crypto.JOSE.Header: instance (GHC.Classes.Eq a, GHC.Classes.Eq p) => GHC.Classes.Eq (Crypto.JOSE.Header.HeaderParam p a)
- Crypto.JOSE.Header: instance (GHC.Show.Show a, GHC.Show.Show p) => GHC.Show.Show (Crypto.JOSE.Header.HeaderParam p a)
- Crypto.JOSE.JWA.JWE: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.JWA.JWE.AESGCMParameters
- Crypto.JOSE.JWA.JWE: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.JWA.JWE.AlgWithParams
- Crypto.JOSE.JWA.JWE: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.JWA.JWE.ECDHParameters
- Crypto.JOSE.JWA.JWE: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.JWA.JWE.Enc
- Crypto.JOSE.JWA.JWE: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.JWA.JWE.PBES2Parameters
- Crypto.JOSE.JWA.JWE: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.JWA.JWE.AESGCMParameters
- Crypto.JOSE.JWA.JWE: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.JWA.JWE.AlgWithParams
- Crypto.JOSE.JWA.JWE: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.JWA.JWE.ECDHParameters
- Crypto.JOSE.JWA.JWE: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.JWA.JWE.Enc
- Crypto.JOSE.JWA.JWE: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.JWA.JWE.PBES2Parameters
- Crypto.JOSE.JWA.JWE.Alg: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.JWA.JWE.Alg.Alg
- Crypto.JOSE.JWA.JWE.Alg: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.JWA.JWE.Alg.Alg
- Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.JWA.JWK.Crv
- Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.JWA.JWK.ECKeyParameters
- Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.JWA.JWK.KeyMaterial
- Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.JWA.JWK.OKPKeyParameters
- Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.JWA.JWK.OctKeyParameters
- Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.JWA.JWK.RSAKeyParameters
- Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.JWA.JWK.RSAPrivateKeyOptionalParameters
- Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.JWA.JWK.RSAPrivateKeyOthElem
- Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.JWA.JWK.RSAPrivateKeyParameters
- Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.JWA.JWK.Crv
- Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.JWA.JWK.ECKeyParameters
- Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.JWA.JWK.KeyMaterial
- Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.JWA.JWK.OKPKeyParameters
- Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.JWA.JWK.OctKeyParameters
- Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.JWA.JWK.RSAKeyParameters
- Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.JWA.JWK.RSAPrivateKeyOptionalParameters
- Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.JWA.JWK.RSAPrivateKeyOthElem
- Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.JWA.JWK.RSAPrivateKeyParameters
- Crypto.JOSE.JWA.JWS: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.JWA.JWS.Alg
- Crypto.JOSE.JWA.JWS: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.JWA.JWS.Alg
- Crypto.JOSE.JWE: instance (Crypto.JOSE.Header.HasParams a, Crypto.JOSE.Header.ProtectionIndicator p) => Data.Aeson.Types.Class.FromJSON (Crypto.JOSE.JWE.JWE a p)
- Crypto.JOSE.JWE: instance Data.Aeson.Types.Class.FromJSON (Crypto.JOSE.JWE.JWERecipient a p)
- Crypto.JOSE.JWK: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.JWK.JWK
- Crypto.JOSE.JWK: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.JWK.JWKAlg
- Crypto.JOSE.JWK: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.JWK.JWKSet
- Crypto.JOSE.JWK: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.JWK.KeyOp
- Crypto.JOSE.JWK: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.JWK.KeyUse
- Crypto.JOSE.JWK: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.JWK.JWK
- Crypto.JOSE.JWK: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.JWK.JWKAlg
- Crypto.JOSE.JWK: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.JWK.JWKSet
- Crypto.JOSE.JWK: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.JWK.KeyOp
- Crypto.JOSE.JWK: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.JWK.KeyUse
- Crypto.JOSE.JWK.Store: class JWKStore a
- Crypto.JOSE.JWK.Store: instance Crypto.JOSE.JWK.Store.JWKStore Crypto.JOSE.JWK.JWK
- Crypto.JOSE.JWK.Store: instance Crypto.JOSE.JWK.Store.JWKStore Crypto.JOSE.JWK.JWKSet
- Crypto.JOSE.JWK.Store: keys :: JWKStore a => Fold a JWK
- Crypto.JOSE.JWK.Store: keysFor :: (JWKStore a, HasAlg h, HasJku h, HasJwk h, HasKid h, HasX5u h, HasX5c h, HasX5t h, HasX5tS256 h, HasTyp h, HasCty h) => KeyOp -> h p -> Fold a JWK
- Crypto.JOSE.JWS: instance (Crypto.JOSE.Header.HasParams a, Crypto.JOSE.Header.ProtectionIndicator p) => Data.Aeson.Types.Class.FromJSON (Crypto.JOSE.JWS.JWS Data.Functor.Identity.Identity p a)
- Crypto.JOSE.JWS: instance (Crypto.JOSE.Header.HasParams a, Crypto.JOSE.Header.ProtectionIndicator p) => Data.Aeson.Types.Class.FromJSON (Crypto.JOSE.JWS.JWS [] p a)
- Crypto.JOSE.JWS: instance (Crypto.JOSE.Header.HasParams a, Crypto.JOSE.Header.ProtectionIndicator p) => Data.Aeson.Types.Class.FromJSON (Crypto.JOSE.JWS.Signature p a)
- Crypto.JOSE.JWS: instance (Crypto.JOSE.Header.HasParams a, Crypto.JOSE.Header.ProtectionIndicator p) => Data.Aeson.Types.Class.ToJSON (Crypto.JOSE.JWS.JWS Data.Functor.Identity.Identity p a)
- Crypto.JOSE.JWS: instance (Crypto.JOSE.Header.HasParams a, Crypto.JOSE.Header.ProtectionIndicator p) => Data.Aeson.Types.Class.ToJSON (Crypto.JOSE.JWS.JWS [] p a)
- Crypto.JOSE.JWS: instance (Crypto.JOSE.Header.HasParams a, Crypto.JOSE.Header.ProtectionIndicator p) => Data.Aeson.Types.Class.ToJSON (Crypto.JOSE.JWS.Signature p a)
- Crypto.JOSE.JWS: instance Crypto.JOSE.Header.HasAlg Crypto.JOSE.JWS.JWSHeader
- Crypto.JOSE.JWS: instance Crypto.JOSE.Header.HasCrit Crypto.JOSE.JWS.JWSHeader
- Crypto.JOSE.JWS: instance Crypto.JOSE.Header.HasCty Crypto.JOSE.JWS.JWSHeader
- Crypto.JOSE.JWS: instance Crypto.JOSE.Header.HasJku Crypto.JOSE.JWS.JWSHeader
- Crypto.JOSE.JWS: instance Crypto.JOSE.Header.HasJwk Crypto.JOSE.JWS.JWSHeader
- Crypto.JOSE.JWS: instance Crypto.JOSE.Header.HasKid Crypto.JOSE.JWS.JWSHeader
- Crypto.JOSE.JWS: instance Crypto.JOSE.Header.HasTyp Crypto.JOSE.JWS.JWSHeader
- Crypto.JOSE.JWS: instance Crypto.JOSE.Header.HasX5c Crypto.JOSE.JWS.JWSHeader
- Crypto.JOSE.JWS: instance Crypto.JOSE.Header.HasX5t Crypto.JOSE.JWS.JWSHeader
- Crypto.JOSE.JWS: instance Crypto.JOSE.Header.HasX5tS256 Crypto.JOSE.JWS.JWSHeader
- Crypto.JOSE.JWS: instance Crypto.JOSE.Header.HasX5u Crypto.JOSE.JWS.JWSHeader
- Crypto.JOSE.Types: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.Types.Base64Integer
- Crypto.JOSE.Types: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.Types.Base64Octets
- Crypto.JOSE.Types: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.Types.Base64SHA1
- Crypto.JOSE.Types: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.Types.Base64SHA256
- Crypto.JOSE.Types: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.Types.Base64X509
- Crypto.JOSE.Types: instance Data.Aeson.Types.Class.FromJSON Crypto.JOSE.Types.SizedBase64Integer
- Crypto.JOSE.Types: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.Types.Base64Integer
- Crypto.JOSE.Types: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.Types.Base64Octets
- Crypto.JOSE.Types: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.Types.Base64SHA1
- Crypto.JOSE.Types: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.Types.Base64SHA256
- Crypto.JOSE.Types: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.Types.Base64X509
- Crypto.JOSE.Types: instance Data.Aeson.Types.Class.ToJSON Crypto.JOSE.Types.SizedBase64Integer
- Crypto.JWT: data JWT a
- Crypto.JWT: instance Crypto.JOSE.Compact.FromCompact a => Crypto.JOSE.Compact.FromCompact (Crypto.JWT.JWT a)
- Crypto.JWT: instance Crypto.JOSE.Compact.ToCompact a => Crypto.JOSE.Compact.ToCompact (Crypto.JWT.JWT a)
- Crypto.JWT: instance Crypto.JOSE.JWS.HasValidationSettings Crypto.JWT.JWTValidationSettings
- Crypto.JWT: instance Data.Aeson.Types.Class.FromJSON Crypto.JWT.Audience
- Crypto.JWT: instance Data.Aeson.Types.Class.FromJSON Crypto.JWT.ClaimsSet
- Crypto.JWT: instance Data.Aeson.Types.Class.FromJSON Crypto.JWT.NumericDate
- Crypto.JWT: instance Data.Aeson.Types.Class.FromJSON Crypto.JWT.StringOrURI
- Crypto.JWT: instance Data.Aeson.Types.Class.ToJSON Crypto.JWT.Audience
- Crypto.JWT: instance Data.Aeson.Types.Class.ToJSON Crypto.JWT.ClaimsSet
- Crypto.JWT: instance Data.Aeson.Types.Class.ToJSON Crypto.JWT.NumericDate
- Crypto.JWT: instance Data.Aeson.Types.Class.ToJSON Crypto.JWT.StringOrURI
- Crypto.JWT: instance GHC.Classes.Eq a => GHC.Classes.Eq (Crypto.JWT.JWT a)
- Crypto.JWT: instance GHC.Show.Show a => GHC.Show.Show (Crypto.JWT.JWT a)
+ Crypto.JOSE.Error: CompactInvalidNumberOfParts :: InvalidNumberOfParts -> CompactDecodeError
+ Crypto.JOSE.Error: CompactInvalidText :: CompactTextError -> CompactDecodeError
+ Crypto.JOSE.Error: CompactTextError :: Natural -> UnicodeException -> CompactTextError
+ Crypto.JOSE.Error: InvalidNumberOfParts :: Natural -> Natural -> InvalidNumberOfParts
+ Crypto.JOSE.Error: NoUsableKeys :: Error
+ Crypto.JOSE.Error: _CompactInvalidNumberOfParts :: Prism' CompactDecodeError InvalidNumberOfParts
+ Crypto.JOSE.Error: _CompactInvalidText :: Prism' CompactDecodeError CompactTextError
+ Crypto.JOSE.Error: _NoUsableKeys :: AsError r_amjZ => Prism' r_amjZ ()
+ Crypto.JOSE.Error: actualParts :: Getter InvalidNumberOfParts Natural
+ Crypto.JOSE.Error: data CompactDecodeError
+ Crypto.JOSE.Error: data CompactTextError
+ Crypto.JOSE.Error: data InvalidNumberOfParts
+ Crypto.JOSE.Error: expectedParts :: Getter InvalidNumberOfParts Natural
+ Crypto.JOSE.Error: instance GHC.Classes.Eq Crypto.JOSE.Error.CompactDecodeError
+ Crypto.JOSE.Error: instance GHC.Classes.Eq Crypto.JOSE.Error.CompactTextError
+ Crypto.JOSE.Error: instance GHC.Classes.Eq Crypto.JOSE.Error.InvalidNumberOfParts
+ Crypto.JOSE.Error: instance GHC.Show.Show Crypto.JOSE.Error.CompactDecodeError
+ Crypto.JOSE.Error: instance GHC.Show.Show Crypto.JOSE.Error.CompactTextError
+ Crypto.JOSE.Error: instance GHC.Show.Show Crypto.JOSE.Error.InvalidNumberOfParts
+ Crypto.JOSE.Header: instance (GHC.Classes.Eq p, GHC.Classes.Eq a) => GHC.Classes.Eq (Crypto.JOSE.Header.HeaderParam p a)
+ Crypto.JOSE.Header: instance (GHC.Show.Show p, GHC.Show.Show a) => GHC.Show.Show (Crypto.JOSE.Header.HeaderParam p a)
+ Crypto.JOSE.Header: instance GHC.Base.Functor (Crypto.JOSE.Header.HeaderParam p)
+ Crypto.JOSE.JWA.JWE: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.JWA.JWE.AESGCMParameters
+ Crypto.JOSE.JWA.JWE: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.JWA.JWE.AlgWithParams
+ Crypto.JOSE.JWA.JWE: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.JWA.JWE.ECDHParameters
+ Crypto.JOSE.JWA.JWE: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.JWA.JWE.Enc
+ Crypto.JOSE.JWA.JWE: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.JWA.JWE.PBES2Parameters
+ Crypto.JOSE.JWA.JWE: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.JWA.JWE.AESGCMParameters
+ Crypto.JOSE.JWA.JWE: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.JWA.JWE.AlgWithParams
+ Crypto.JOSE.JWA.JWE: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.JWA.JWE.ECDHParameters
+ Crypto.JOSE.JWA.JWE: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.JWA.JWE.Enc
+ Crypto.JOSE.JWA.JWE: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.JWA.JWE.PBES2Parameters
+ Crypto.JOSE.JWA.JWE.Alg: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.JWA.JWE.Alg.Alg
+ Crypto.JOSE.JWA.JWE.Alg: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.JWA.JWE.Alg.Alg
+ Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.JWA.JWK.Crv
+ Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.JWA.JWK.ECKeyParameters
+ Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.JWA.JWK.KeyMaterial
+ Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.JWA.JWK.OKPKeyParameters
+ Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.JWA.JWK.OctKeyParameters
+ Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.JWA.JWK.RSAKeyParameters
+ Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.JWA.JWK.RSAPrivateKeyOptionalParameters
+ Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.JWA.JWK.RSAPrivateKeyOthElem
+ Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.JWA.JWK.RSAPrivateKeyParameters
+ Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.JWA.JWK.Crv
+ Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.JWA.JWK.ECKeyParameters
+ Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.JWA.JWK.KeyMaterial
+ Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.JWA.JWK.OKPKeyParameters
+ Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.JWA.JWK.OctKeyParameters
+ Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.JWA.JWK.RSAKeyParameters
+ Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.JWA.JWK.RSAPrivateKeyOptionalParameters
+ Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.JWA.JWK.RSAPrivateKeyOthElem
+ Crypto.JOSE.JWA.JWK: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.JWA.JWK.RSAPrivateKeyParameters
+ Crypto.JOSE.JWA.JWK: toRSAPublicKeyParameters :: PublicKey -> RSAKeyParameters
+ Crypto.JOSE.JWA.JWS: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.JWA.JWS.Alg
+ Crypto.JOSE.JWA.JWS: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.JWA.JWS.Alg
+ Crypto.JOSE.JWE: instance (Crypto.JOSE.Header.HasParams a, Crypto.JOSE.Header.ProtectionIndicator p) => Data.Aeson.Types.FromJSON.FromJSON (Crypto.JOSE.JWE.JWE a p)
+ Crypto.JOSE.JWE: instance Data.Aeson.Types.FromJSON.FromJSON (Crypto.JOSE.JWE.JWERecipient a p)
+ Crypto.JOSE.JWK: fromX509Certificate :: (AsError e, MonadError e m) => SignedCertificate -> m JWK
+ Crypto.JOSE.JWK: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.JWK.JWK
+ Crypto.JOSE.JWK: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.JWK.JWKAlg
+ Crypto.JOSE.JWK: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.JWK.JWKSet
+ Crypto.JOSE.JWK: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.JWK.KeyOp
+ Crypto.JOSE.JWK: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.JWK.KeyUse
+ Crypto.JOSE.JWK: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.JWK.JWK
+ Crypto.JOSE.JWK: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.JWK.JWKAlg
+ Crypto.JOSE.JWK: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.JWK.JWKSet
+ Crypto.JOSE.JWK: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.JWK.KeyOp
+ Crypto.JOSE.JWK: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.JWK.KeyUse
+ Crypto.JOSE.JWK: setJWKX5c :: Maybe (NonEmpty SignedCertificate) -> JWK -> Maybe JWK
+ Crypto.JOSE.JWK.Store: class VerificationKeyStore m h s a
+ Crypto.JOSE.JWK.Store: getVerificationKeys :: VerificationKeyStore m h s a => h -> s -> a -> m [JWK]
+ Crypto.JOSE.JWK.Store: instance GHC.Base.Applicative m => Crypto.JOSE.JWK.Store.VerificationKeyStore m h s Crypto.JOSE.JWK.JWK
+ Crypto.JOSE.JWK.Store: instance GHC.Base.Applicative m => Crypto.JOSE.JWK.Store.VerificationKeyStore m h s Crypto.JOSE.JWK.JWKSet
+ Crypto.JOSE.JWS: instance (Crypto.JOSE.Header.HasParams a, Crypto.JOSE.Header.ProtectionIndicator p) => Data.Aeson.Types.FromJSON.FromJSON (Crypto.JOSE.JWS.JWS Data.Functor.Identity.Identity p a)
+ Crypto.JOSE.JWS: instance (Crypto.JOSE.Header.HasParams a, Crypto.JOSE.Header.ProtectionIndicator p) => Data.Aeson.Types.FromJSON.FromJSON (Crypto.JOSE.JWS.JWS [] p a)
+ Crypto.JOSE.JWS: instance (Crypto.JOSE.Header.HasParams a, Crypto.JOSE.Header.ProtectionIndicator p) => Data.Aeson.Types.FromJSON.FromJSON (Crypto.JOSE.JWS.Signature p a)
+ Crypto.JOSE.JWS: instance (Crypto.JOSE.Header.HasParams a, Crypto.JOSE.Header.ProtectionIndicator p) => Data.Aeson.Types.ToJSON.ToJSON (Crypto.JOSE.JWS.JWS Data.Functor.Identity.Identity p a)
+ Crypto.JOSE.JWS: instance (Crypto.JOSE.Header.HasParams a, Crypto.JOSE.Header.ProtectionIndicator p) => Data.Aeson.Types.ToJSON.ToJSON (Crypto.JOSE.JWS.JWS [] p a)
+ Crypto.JOSE.JWS: instance (Crypto.JOSE.Header.HasParams a, Crypto.JOSE.Header.ProtectionIndicator p) => Data.Aeson.Types.ToJSON.ToJSON (Crypto.JOSE.JWS.Signature p a)
+ Crypto.JOSE.JWS: makeJWSHeader :: forall e m p. (MonadError e m, AsError e, ProtectionIndicator p) => JWK -> m (JWSHeader p)
+ Crypto.JOSE.JWS: verifyJWSWithPayload :: (HasAlgorithms a, HasValidationPolicy a, AsError e, MonadError e m, HasJWSHeader h, HasParams h, VerificationKeyStore m (h p) payload k, Cons s s Word8 Word8, AsEmpty s, Foldable t, ProtectionIndicator p) => (s -> m payload) -> a -> k -> JWS t p h -> m payload
+ Crypto.JOSE.Types: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.Types.Base64Integer
+ Crypto.JOSE.Types: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.Types.Base64Octets
+ Crypto.JOSE.Types: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.Types.Base64SHA1
+ Crypto.JOSE.Types: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.Types.Base64SHA256
+ Crypto.JOSE.Types: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.Types.Base64X509
+ Crypto.JOSE.Types: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JOSE.Types.SizedBase64Integer
+ Crypto.JOSE.Types: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.Types.Base64Integer
+ Crypto.JOSE.Types: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.Types.Base64Octets
+ Crypto.JOSE.Types: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.Types.Base64SHA1
+ Crypto.JOSE.Types: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.Types.Base64SHA256
+ Crypto.JOSE.Types: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.Types.Base64X509
+ Crypto.JOSE.Types: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JOSE.Types.SizedBase64Integer
+ Crypto.JOSE.Types: type SignedCertificate = SignedExact Certificate
+ Crypto.JWT: instance Crypto.JWT.HasJWTValidationSettings a => Crypto.JOSE.JWS.HasValidationSettings a
+ Crypto.JWT: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JWT.Audience
+ Crypto.JWT: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JWT.ClaimsSet
+ Crypto.JWT: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JWT.NumericDate
+ Crypto.JWT: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.JWT.StringOrURI
+ Crypto.JWT: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JWT.Audience
+ Crypto.JWT: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JWT.ClaimsSet
+ Crypto.JWT: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JWT.NumericDate
+ Crypto.JWT: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.JWT.StringOrURI
- Crypto.JOSE.Compact: encodeCompact :: (ToCompact a) => a -> ByteString
+ Crypto.JOSE.Compact: encodeCompact :: ToCompact a => a -> ByteString
- Crypto.JOSE.Error: CompactDecodeError :: String -> Error
+ Crypto.JOSE.Error: CompactDecodeError :: CompactDecodeError -> Error
- Crypto.JOSE.Error: KeyMismatch :: String -> Error
+ Crypto.JOSE.Error: KeyMismatch :: Text -> Error
- Crypto.JOSE.Error: _AlgorithmMismatch :: AsError r_alFL => Prism' r_alFL String
+ Crypto.JOSE.Error: _AlgorithmMismatch :: AsError r_amjZ => Prism' r_amjZ String
- Crypto.JOSE.Error: _AlgorithmNotImplemented :: AsError r_alFL => Prism' r_alFL ()
+ Crypto.JOSE.Error: _AlgorithmNotImplemented :: AsError r_amjZ => Prism' r_amjZ ()
- Crypto.JOSE.Error: _CompactDecodeError :: AsError r_alFL => Prism' r_alFL String
+ Crypto.JOSE.Error: _CompactDecodeError :: AsError r_amjZ => Prism' r_amjZ CompactDecodeError
- Crypto.JOSE.Error: _CryptoError :: AsError r_alFL => Prism' r_alFL CryptoError
+ Crypto.JOSE.Error: _CryptoError :: AsError r_amjZ => Prism' r_amjZ CryptoError
- Crypto.JOSE.Error: _Error :: AsError r_alFL => Prism' r_alFL Error
+ Crypto.JOSE.Error: _Error :: AsError r_amjZ => Prism' r_amjZ Error
- Crypto.JOSE.Error: _JSONDecodeError :: AsError r_alFL => Prism' r_alFL String
+ Crypto.JOSE.Error: _JSONDecodeError :: AsError r_amjZ => Prism' r_amjZ String
- Crypto.JOSE.Error: _JWSCritUnprotected :: AsError r_alFL => Prism' r_alFL ()
+ Crypto.JOSE.Error: _JWSCritUnprotected :: AsError r_amjZ => Prism' r_amjZ ()
- Crypto.JOSE.Error: _JWSInvalidSignature :: AsError r_alFL => Prism' r_alFL ()
+ Crypto.JOSE.Error: _JWSInvalidSignature :: AsError r_amjZ => Prism' r_amjZ ()
- Crypto.JOSE.Error: _JWSNoSignatures :: AsError r_alFL => Prism' r_alFL ()
+ Crypto.JOSE.Error: _JWSNoSignatures :: AsError r_amjZ => Prism' r_amjZ ()
- Crypto.JOSE.Error: _JWSNoValidSignatures :: AsError r_alFL => Prism' r_alFL ()
+ Crypto.JOSE.Error: _JWSNoValidSignatures :: AsError r_amjZ => Prism' r_amjZ ()
- Crypto.JOSE.Error: _KeyMismatch :: AsError r_alFL => Prism' r_alFL String
+ Crypto.JOSE.Error: _KeyMismatch :: AsError r_amjZ => Prism' r_amjZ Text
- Crypto.JOSE.Error: _KeySizeTooSmall :: AsError r_alFL => Prism' r_alFL ()
+ Crypto.JOSE.Error: _KeySizeTooSmall :: AsError r_amjZ => Prism' r_amjZ ()
- Crypto.JOSE.Error: _OtherPrimesNotSupported :: AsError r_alFL => Prism' r_alFL ()
+ Crypto.JOSE.Error: _OtherPrimesNotSupported :: AsError r_amjZ => Prism' r_amjZ ()
- Crypto.JOSE.Error: _RSAError :: AsError r_alFL => Prism' r_alFL Error
+ Crypto.JOSE.Error: _RSAError :: AsError r_amjZ => Prism' r_amjZ Error
- Crypto.JOSE.Error: class AsError r_alFL
+ Crypto.JOSE.Error: class AsError r_amjZ
- Crypto.JOSE.Header: cty :: HasCty a => Lens' (a p) (Maybe (HeaderParam p String))
+ Crypto.JOSE.Header: cty :: HasCty a => Lens' (a p) (Maybe (HeaderParam p Text))
- Crypto.JOSE.Header: isProtected :: (ProtectionIndicator p) => Getter (HeaderParam p a) Bool
+ Crypto.JOSE.Header: isProtected :: ProtectionIndicator p => Getter (HeaderParam p a) Bool
- Crypto.JOSE.Header: kid :: HasKid a => Lens' (a p) (Maybe (HeaderParam p String))
+ Crypto.JOSE.Header: kid :: HasKid a => Lens' (a p) (Maybe (HeaderParam p Text))
- Crypto.JOSE.Header: typ :: HasTyp a => Lens' (a p) (Maybe (HeaderParam p String))
+ Crypto.JOSE.Header: typ :: HasTyp a => Lens' (a p) (Maybe (HeaderParam p Text))
- Crypto.JOSE.Header: x5c :: HasX5c a => Lens' (a p) (Maybe (HeaderParam p (NonEmpty Base64X509)))
+ Crypto.JOSE.Header: x5c :: HasX5c a => Lens' (a p) (Maybe (HeaderParam p (NonEmpty SignedCertificate)))
- Crypto.JOSE.JWA.JWK: Ed25519Key :: PublicKey -> (Maybe SecretKey) -> OKPKeyParameters
+ Crypto.JOSE.JWA.JWK: Ed25519Key :: PublicKey -> Maybe SecretKey -> OKPKeyParameters
- Crypto.JOSE.JWA.JWK: X25519Key :: PublicKey -> (Maybe SecretKey) -> OKPKeyParameters
+ Crypto.JOSE.JWA.JWK: X25519Key :: PublicKey -> Maybe SecretKey -> OKPKeyParameters
- Crypto.JOSE.JWE: JWE :: (Maybe Text) -> Maybe Base64Octets -> Maybe Base64Octets -> Base64Octets -> Maybe Base64Octets -> [JWERecipient a p] -> JWE a p
+ Crypto.JOSE.JWE: JWE :: Maybe Text -> Maybe Base64Octets -> Maybe Base64Octets -> Base64Octets -> Maybe Base64Octets -> [JWERecipient a p] -> JWE a p
- Crypto.JOSE.JWE: JWEHeader :: Maybe AlgWithParams -> HeaderParam p Enc -> Maybe String -> Maybe (HeaderParam p URI) -> Maybe (HeaderParam p JWK) -> Maybe (HeaderParam p String) -> Maybe (HeaderParam p URI) -> Maybe (HeaderParam p (NonEmpty Base64X509)) -> Maybe (HeaderParam p Base64SHA1) -> Maybe (HeaderParam p Base64SHA256) -> Maybe (HeaderParam p String) -> Maybe (HeaderParam p String) -> Maybe (NonEmpty Text) -> JWEHeader p
+ Crypto.JOSE.JWE: JWEHeader :: Maybe AlgWithParams -> HeaderParam p Enc -> Maybe Text -> Maybe (HeaderParam p URI) -> Maybe (HeaderParam p JWK) -> Maybe (HeaderParam p Text) -> Maybe (HeaderParam p URI) -> Maybe (HeaderParam p (NonEmpty SignedCertificate)) -> Maybe (HeaderParam p Base64SHA1) -> Maybe (HeaderParam p Base64SHA256) -> Maybe (HeaderParam p Text) -> Maybe (HeaderParam p Text) -> Maybe (NonEmpty Text) -> JWEHeader p
- Crypto.JOSE.JWE: [_jweCty] :: JWEHeader p -> Maybe (HeaderParam p String)
+ Crypto.JOSE.JWE: [_jweCty] :: JWEHeader p -> Maybe (HeaderParam p Text)
- Crypto.JOSE.JWE: [_jweKid] :: JWEHeader p -> Maybe (HeaderParam p String)
+ Crypto.JOSE.JWE: [_jweKid] :: JWEHeader p -> Maybe (HeaderParam p Text)
- Crypto.JOSE.JWE: [_jweTyp] :: JWEHeader p -> Maybe (HeaderParam p String)
+ Crypto.JOSE.JWE: [_jweTyp] :: JWEHeader p -> Maybe (HeaderParam p Text)
- Crypto.JOSE.JWE: [_jweX5c] :: JWEHeader p -> Maybe (HeaderParam p (NonEmpty Base64X509))
+ Crypto.JOSE.JWE: [_jweX5c] :: JWEHeader p -> Maybe (HeaderParam p (NonEmpty SignedCertificate))
- Crypto.JOSE.JWE: [_jweZip] :: JWEHeader p -> Maybe String
+ Crypto.JOSE.JWE: [_jweZip] :: JWEHeader p -> Maybe Text
- Crypto.JOSE.JWE: [_protectedRaw] :: JWE a p -> (Maybe Text)
+ Crypto.JOSE.JWE: [_protectedRaw] :: JWE a p -> Maybe Text
- Crypto.JOSE.JWK: jwkX5c :: Lens' JWK (Maybe (NonEmpty Base64X509))
+ Crypto.JOSE.JWK: jwkX5c :: Getter JWK (Maybe (NonEmpty SignedCertificate))
- Crypto.JOSE.JWS: newJWSHeader :: (p, Alg) -> (JWSHeader p)
+ Crypto.JOSE.JWS: newJWSHeader :: (p, Alg) -> JWSHeader p
- Crypto.JOSE.JWS: signJWS :: (Cons s s Word8 Word8, HasJWSHeader a, HasParams a, MonadRandom m, AsError e, MonadError e m, Traversable t, ProtectionIndicator p) => s -> t ((a p), JWK) -> m (JWS t p a)
+ Crypto.JOSE.JWS: signJWS :: (Cons s s Word8 Word8, HasJWSHeader a, HasParams a, MonadRandom m, AsError e, MonadError e m, Traversable t, ProtectionIndicator p) => s -> t (a p, JWK) -> m (JWS t p a)
- Crypto.JOSE.JWS: verifyJWS :: (HasAlgorithms a, HasValidationPolicy a, AsError e, MonadError e m, HasJWSHeader h, HasParams h, JWKStore k, Cons s s Word8 Word8, AsEmpty s, Foldable t, ProtectionIndicator p) => a -> k -> JWS t p h -> m s
+ Crypto.JOSE.JWS: verifyJWS :: (HasAlgorithms a, HasValidationPolicy a, AsError e, MonadError e m, HasJWSHeader h, HasParams h, VerificationKeyStore m (h p) s k, Cons s s Word8 Word8, AsEmpty s, Foldable t, ProtectionIndicator p) => a -> k -> JWS t p h -> m s
- Crypto.JOSE.JWS: verifyJWS' :: (AsError e, MonadError e m, HasJWSHeader h, HasParams h, JWKStore k, Cons s s Word8 Word8, AsEmpty s, Foldable t, ProtectionIndicator p) => k -> JWS t p h -> m s
+ Crypto.JOSE.JWS: verifyJWS' :: (AsError e, MonadError e m, HasJWSHeader h, HasParams h, VerificationKeyStore m (h p) s k, Cons s s Word8 Word8, AsEmpty s, Foldable t, ProtectionIndicator p) => k -> JWS t p h -> m s
- Crypto.JOSE.Types: data URI :: *
+ Crypto.JOSE.Types: data URI
- Crypto.JWT: _JWSError :: AsJWTError r_a1grt => Prism' r_a1grt Error
+ Crypto.JWT: _JWSError :: AsJWTError r_a1efH => Prism' r_a1efH Error
- Crypto.JWT: _JWTClaimsSetDecodeError :: AsJWTError r_a1grt => Prism' r_a1grt String
+ Crypto.JWT: _JWTClaimsSetDecodeError :: AsJWTError r_a1efH => Prism' r_a1efH String
- Crypto.JWT: _JWTError :: AsJWTError r_a1grt => Prism' r_a1grt JWTError
+ Crypto.JWT: _JWTError :: AsJWTError r_a1efH => Prism' r_a1efH JWTError
- Crypto.JWT: _JWTExpired :: AsJWTError r_a1grt => Prism' r_a1grt ()
+ Crypto.JWT: _JWTExpired :: AsJWTError r_a1efH => Prism' r_a1efH ()
- Crypto.JWT: _JWTIssuedAtFuture :: AsJWTError r_a1grt => Prism' r_a1grt ()
+ Crypto.JWT: _JWTIssuedAtFuture :: AsJWTError r_a1efH => Prism' r_a1efH ()
- Crypto.JWT: _JWTNotInAudience :: AsJWTError r_a1grt => Prism' r_a1grt ()
+ Crypto.JWT: _JWTNotInAudience :: AsJWTError r_a1efH => Prism' r_a1efH ()
- Crypto.JWT: _JWTNotInIssuer :: AsJWTError r_a1grt => Prism' r_a1grt ()
+ Crypto.JWT: _JWTNotInIssuer :: AsJWTError r_a1efH => Prism' r_a1efH ()
- Crypto.JWT: _JWTNotYetValid :: AsJWTError r_a1grt => Prism' r_a1grt ()
+ Crypto.JWT: _JWTNotYetValid :: AsJWTError r_a1efH => Prism' r_a1efH ()
- Crypto.JWT: class AsJWTError r_a1grt
+ Crypto.JWT: class AsJWTError r_a1efH
- Crypto.JWT: class HasJWTValidationSettings c_a1hcR
+ Crypto.JWT: class HasJWTValidationSettings c_a1f08
- Crypto.JWT: jWTValidationSettings :: HasJWTValidationSettings c_a1hcR => Lens' c_a1hcR JWTValidationSettings
+ Crypto.JWT: jWTValidationSettings :: HasJWTValidationSettings c_a1f08 => Lens' c_a1f08 JWTValidationSettings
- Crypto.JWT: jwtValidationSettingsAllowedSkew :: HasJWTValidationSettings c_a1hcR => Lens' c_a1hcR NominalDiffTime
+ Crypto.JWT: jwtValidationSettingsAllowedSkew :: HasJWTValidationSettings c_a1f08 => Lens' c_a1f08 NominalDiffTime
- Crypto.JWT: jwtValidationSettingsAudiencePredicate :: HasJWTValidationSettings c_a1hcR => Lens' c_a1hcR (StringOrURI -> Bool)
+ Crypto.JWT: jwtValidationSettingsAudiencePredicate :: HasJWTValidationSettings c_a1f08 => Lens' c_a1f08 (StringOrURI -> Bool)
- Crypto.JWT: jwtValidationSettingsCheckIssuedAt :: HasJWTValidationSettings c_a1hcR => Lens' c_a1hcR Bool
+ Crypto.JWT: jwtValidationSettingsCheckIssuedAt :: HasJWTValidationSettings c_a1f08 => Lens' c_a1f08 Bool
- Crypto.JWT: jwtValidationSettingsIssuerPredicate :: HasJWTValidationSettings c_a1hcR => Lens' c_a1hcR (StringOrURI -> Bool)
+ Crypto.JWT: jwtValidationSettingsIssuerPredicate :: HasJWTValidationSettings c_a1f08 => Lens' c_a1f08 (StringOrURI -> Bool)
- Crypto.JWT: jwtValidationSettingsValidationSettings :: HasJWTValidationSettings c_a1hcR => Lens' c_a1hcR ValidationSettings
+ Crypto.JWT: jwtValidationSettingsValidationSettings :: HasJWTValidationSettings c_a1f08 => Lens' c_a1f08 ValidationSettings
- Crypto.JWT: string :: Prism' StringOrURI String
+ Crypto.JWT: string :: Prism' StringOrURI Text
- Crypto.JWT: stringOrUri :: (Cons s s Char Char, Monoid s) => Prism' s StringOrURI
+ Crypto.JWT: stringOrUri :: (Cons s s Char Char, AsEmpty s) => Prism' s StringOrURI
- Crypto.JWT: type SignedJWT = JWT (CompactJWS JWSHeader)
+ Crypto.JWT: type SignedJWT = CompactJWS JWSHeader
- Crypto.JWT: verifyClaims :: (MonadTime m, HasAllowedSkew a, HasAudiencePredicate a, HasIssuerPredicate a, HasCheckIssuedAt a, HasValidationSettings a, AsError e, AsJWTError e, MonadError e m, JWKStore k) => a -> k -> SignedJWT -> m ClaimsSet
+ Crypto.JWT: verifyClaims :: (MonadTime m, HasAllowedSkew a, HasAudiencePredicate a, HasIssuerPredicate a, HasCheckIssuedAt a, HasValidationSettings a, AsError e, AsJWTError e, MonadError e m, VerificationKeyStore m (JWSHeader ()) ClaimsSet k) => a -> k -> SignedJWT -> m ClaimsSet
- Crypto.JWT: verifyClaimsAt :: (HasAllowedSkew a, HasAudiencePredicate a, HasIssuerPredicate a, HasCheckIssuedAt a, HasValidationSettings a, AsError e, AsJWTError e, MonadError e m, JWKStore k) => a -> k -> UTCTime -> SignedJWT -> m ClaimsSet
+ Crypto.JWT: verifyClaimsAt :: (HasAllowedSkew a, HasAudiencePredicate a, HasIssuerPredicate a, HasCheckIssuedAt a, HasValidationSettings a, AsError e, AsJWTError e, MonadError e m, VerificationKeyStore (ReaderT WrappedUTCTime m) (JWSHeader ()) ClaimsSet k) => a -> k -> UTCTime -> SignedJWT -> m ClaimsSet

Files

README.md view
@@ -56,10 +56,22 @@   The datum [should be a base64url-encoded SHA-1 digest](   https://tools.ietf.org/html/rfc7515#section-4.1.7), but *Auth0*   produces a base64url-encoded hex-encoded SHA-1 digest.  The object-  can be repaired 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.+  can be repaired+  ([example](https://github.com/frasertweedale/hs-jose/issues/54#issuecomment-356460452))+  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](https://tools.ietf.org/html/rfc7518#section-2)) have been+  [seen in the+  wild](https://github.com/frasertweedale/hs-jose/issues/68).  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
example/JWS.hs view
@@ -20,8 +20,8 @@   Just jwk <- decode <$> L.readFile jwkFilename   payload <- L.readFile payloadFilename   result <- runExceptT $ do-    alg <- bestJWSAlg jwk-    signJWS payload [(newJWSHeader (Protected, alg), jwk)]+    h <- makeJWSHeader jwk+    signJWS payload [(h :: JWSHeader Protection, jwk)]   case result of     Left e -> print (e :: Error) >> exitFailure     Right jws -> L.putStr (encode jws)
+ example/KeyDB.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}++module KeyDB+  (+    KeyDB(..)+  ) where++import Control.Exception (IOException, handle)+import Data.Maybe (catMaybes)+import Data.Semigroup ((<>))++import Control.Monad.Trans (MonadIO(..))+import Control.Lens (_Just, preview)+import Data.Aeson (decode)+import qualified Data.ByteString.Lazy as L+import qualified Data.Text as T++import Crypto.JWT++-- | A KeyDB is just a directory+--+newtype KeyDB = KeyDB FilePath++-- | Looks for a key in the directory, based on the @"kid"@ field of+-- the 'JWSHeader' or the @"iss"@ field of the JWT 'ClaimsSet'+--+instance (MonadIO m, HasKid h)+    => VerificationKeyStore m (h p) ClaimsSet KeyDB where+  getVerificationKeys h claims (KeyDB dir) = liftIO $+    fmap catMaybes . traverse findKey $ catMaybes+      [ preview (kid . _Just . param) h+      , preview (claimIss . _Just . string) claims]+    where+    findKey s =+      let path = dir <> "/" <> T.unpack s <> ".jwk"+      in handle+        (\(_ :: IOException) -> pure Nothing)+        (decode <$> L.readFile path)
example/Main.hs view
@@ -1,13 +1,16 @@ {-# OPTIONS_GHC -fno-warn-incomplete-patterns #-} {-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleContexts #-}  import Data.Maybe (fromJust)+import Data.Semigroup ((<>)) import System.Environment (getArgs)-import System.Exit (exitFailure)+import System.Exit (die, exitFailure)  import qualified Data.ByteString.Lazy as L-import Data.Aeson (decode, encode)+import Data.Aeson (decode, eitherDecode, encode) import Data.Text.Strict.Lens (utf8)+import System.Posix.Files (getFileStatus, isDirectory)  import Control.Monad.Except (runExceptT) import Control.Lens (preview, re, review, set, view)@@ -15,6 +18,7 @@ import Crypto.JWT  import JWS (doJwsSign, doJwsVerify)+import KeyDB  main :: IO () main = do@@ -57,9 +61,7 @@ doJwtSign [jwkFilename, claimsFilename] = do   Just k <- decode <$> L.readFile jwkFilename   Just claims <- decode <$> L.readFile claimsFilename-  result <- runExceptT $ do-    alg' <- bestJWSAlg k-    signClaims k (newJWSHeader ((), alg')) claims+  result <- runExceptT $ makeJWSHeader k >>= \h -> signClaims k h claims   case result of     Left e -> print (e :: Error) >> exitFailure     Right jwt -> L.putStr (encodeCompact jwt)@@ -78,16 +80,26 @@ -- doJwtVerify :: [String] -> IO () doJwtVerify [jwkFilename, jwtFilename, aud] = do+  jwtData <- L.readFile jwtFilename   let     aud' = fromJust $ preview stringOrUri aud     conf = defaultJWTValidationSettings (== aud')-  Just k <- decode <$> L.readFile jwkFilename-  jwtData <- L.readFile jwtFilename-  result <- runExceptT-    (decodeCompact jwtData >>= verifyClaims conf (k :: JWK))+    go k = runExceptT (decodeCompact jwtData >>= verifyClaims conf k)++  jwkDir <- isDirectory <$> getFileStatus jwkFilename+  result <-+    if jwkDir+    then go (KeyDB jwkFilename)+    else (eitherDecode <$> L.readFile jwkFilename :: IO (Either String JWK))+      >>= rightOrDie "Failed to decode JWK"+      >>= go+   case result of     Left e -> print (e :: JWTError) >> exitFailure     Right claims -> L.putStr $ encode claims++rightOrDie :: (Show e) => String -> Either e a -> IO a+rightOrDie s = either (die . (\e -> s <> ": " <> show e)) pure   #if MIN_VERSION_aeson(0,10,0)
jose.cabal view
@@ -1,5 +1,5 @@ name:                jose-version:             0.7.0.0+version:             0.8.0.0 synopsis:   Javascript Object Signing and Encryption and JSON Web Token library description:@@ -26,12 +26,12 @@   README.md author:              Fraser Tweedale maintainer:          frase@frase.id.au-copyright:           Copyright (C) 2013, 2014, 2015, 2016, 2017  Fraser Tweedale+copyright:           Copyright (C) 2013-2018  Fraser Tweedale category:            Cryptography build-type:          Simple cabal-version:       >= 1.8 tested-with:-  GHC==7.10.3, GHC==8.0.1, GHC==8.0.2, GHC==8.2.2, GHC==8.4.1+  GHC==7.10.3, GHC==8.0.1, GHC==8.0.2, GHC==8.2.2, GHC==8.4.3, GHC==8.6.1  library   exposed-modules:@@ -137,11 +137,16 @@   ghc-options:    -Wall   main-is:  Main.hs   other-modules:+    KeyDB     JWS+   build-depends:     base     , aeson     , bytestring     , lens     , mtl+    , semigroups+    , text+    , unix     , jose
src/Crypto/JOSE/Error.hs view
@@ -26,26 +26,87 @@   (     Error(..)   , AsError(..)++  -- * JOSE compact serialisation errors+  , InvalidNumberOfParts(..), expectedParts, actualParts+  , CompactTextError(..)+  , CompactDecodeError(..)+  , _CompactInvalidNumberOfParts+  , _CompactInvalidText   ) where +import Data.Semigroup ((<>))+import Numeric.Natural+ import Control.Monad.Trans (MonadTrans(..)) import qualified Crypto.PubKey.RSA as RSA import Crypto.Error (CryptoError) import Crypto.Random (MonadRandom(..))-import Control.Lens.TH (makeClassyPrisms)+import Control.Lens (Getter, to)+import Control.Lens.TH (makeClassyPrisms, makePrisms)+import qualified Data.Text as T+import qualified Data.Text.Encoding.Error as T ++-- | The wrong number of parts were found when decoding a+-- compact JOSE object.+--+data InvalidNumberOfParts =+  InvalidNumberOfParts Natural Natural -- ^ expected vs actual parts+  deriving (Eq)++instance Show InvalidNumberOfParts where+  show (InvalidNumberOfParts n m) =+    "Expected " <> show n <> " parts; got " <> show m++-- | Get the expected or actual number of parts.+expectedParts, actualParts :: Getter InvalidNumberOfParts Natural+expectedParts = to $ \(InvalidNumberOfParts n _) -> n+actualParts   = to $ \(InvalidNumberOfParts _ n) -> n+++-- | Bad UTF-8 data in a compact object, at the specified index+data CompactTextError = CompactTextError+  Natural+  T.UnicodeException+  deriving (Eq)++instance Show CompactTextError where+  show (CompactTextError n s) =+    "Invalid text at part " <> show n <> ": " <> show s+++-- | An error when decoding a JOSE compact object.+-- JSON decoding errors that occur during compact object processing+-- throw 'JSONDecodeError'.+--+data CompactDecodeError+  = CompactInvalidNumberOfParts InvalidNumberOfParts+  | CompactInvalidText CompactTextError+  deriving (Eq)+makePrisms ''CompactDecodeError++instance Show CompactDecodeError where+  show err = "CompactDecodeError: " <> case err of+    CompactInvalidNumberOfParts e -> show e+    CompactInvalidText e        -> show e+++ -- | All the errors that can occur. -- data Error   = AlgorithmNotImplemented   -- ^ A requested algorithm is not implemented   | AlgorithmMismatch String  -- ^ A requested algorithm cannot be used-  | KeyMismatch String        -- ^ Wrong type of key was given+  | KeyMismatch T.Text        -- ^ Wrong type of key was given   | KeySizeTooSmall           -- ^ Key size is too small   | OtherPrimesNotSupported   -- ^ RSA private key with >2 primes not supported   | RSAError RSA.Error        -- ^ RSA encryption, decryption or signing error   | CryptoError CryptoError   -- ^ Various cryptonite library error cases-  | CompactDecodeError String -- ^ Cannot decode compact representation+  | CompactDecodeError CompactDecodeError+  -- ^ Wrong number of parts in compact serialisation   | JSONDecodeError String    -- ^ JSON (Aeson) decoding error+  | NoUsableKeys              -- ^ No usable keys were found in the key store   | JWSCritUnprotected   | JWSNoValidSignatures   -- ^ 'AnyValidated' policy active, and no valid signature encountered
src/Crypto/JOSE/Header.hs view
@@ -163,6 +163,9 @@ data HeaderParam p a = HeaderParam p a   deriving (Eq, Show) +instance Functor (HeaderParam p) where+  fmap f (HeaderParam p a) = HeaderParam p (f a)+ -- | Lens for the 'Protection' of a 'HeaderParam' protection :: Lens' (HeaderParam p a) p protection f (HeaderParam p v) = fmap (\p' -> HeaderParam p' v) (f p)@@ -319,13 +322,13 @@   jwk :: Lens' (a p) (Maybe (HeaderParam p JWK))  class HasKid a where-  kid :: Lens' (a p) (Maybe (HeaderParam p String))+  kid :: Lens' (a p) (Maybe (HeaderParam p T.Text))  class HasX5u a where   x5u :: Lens' (a p) (Maybe (HeaderParam p Types.URI))  class HasX5c a where-  x5c :: Lens' (a p) (Maybe (HeaderParam p (NonEmpty Types.Base64X509)))+  x5c :: Lens' (a p) (Maybe (HeaderParam p (NonEmpty Types.SignedCertificate)))  class HasX5t a where   x5t :: Lens' (a p) (Maybe (HeaderParam p Types.Base64SHA1))@@ -334,10 +337,10 @@   x5tS256 :: Lens' (a p) (Maybe (HeaderParam p Types.Base64SHA256))  class HasTyp a where-  typ :: Lens' (a p) (Maybe (HeaderParam p String))+  typ :: Lens' (a p) (Maybe (HeaderParam p T.Text))  class HasCty a where-  cty :: Lens' (a p) (Maybe (HeaderParam p String))+  cty :: Lens' (a p) (Maybe (HeaderParam p T.Text))  class HasCrit a where   crit :: Lens' (a p) (Maybe (NonEmpty T.Text))
src/Crypto/JOSE/JWA/JWK.hs view
@@ -1,4 +1,4 @@--- Copyright (C) 2013, 2014, 2015, 2016, 2017  Fraser Tweedale+-- Copyright (C) 2013-2018  Fraser Tweedale -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License.@@ -44,6 +44,7 @@   , RSAPrivateKeyParameters(..)   , RSAKeyParameters(RSAKeyParameters)   , toRSAKeyParameters+  , toRSAPublicKeyParameters   , rsaE   , rsaN   , rsaPrivateKeyParameters@@ -160,7 +161,7 @@     o .:? "oth")  instance ToJSON RSAPrivateKeyOptionalParameters where-  toJSON (RSAPrivateKeyOptionalParameters {..}) = object $ [+  toJSON RSAPrivateKeyOptionalParameters{..} = object $ [     "p" .= rsaP     , "q" .= rsaQ     , "dp" .= rsaDp@@ -351,14 +352,19 @@ genRSA size = toRSAKeyParameters . snd <$> RSA.generate size 65537  toRSAKeyParameters :: RSA.PrivateKey -> RSAKeyParameters-toRSAKeyParameters (RSA.PrivateKey (RSA.PublicKey _ n e) d p q dp dq qi) =+toRSAKeyParameters priv@(RSA.PrivateKey pub _ _ _ _ _ _) =+  toRSAPublicKeyParameters pub+  & set rsaPrivateKeyParameters (pure $ toRSAPrivateKeyParameters priv)++toRSAPublicKeyParameters :: RSA.PublicKey -> RSAKeyParameters+toRSAPublicKeyParameters (RSA.PublicKey _ n e) =+  RSAKeyParameters (Types.Base64Integer n) (Types.Base64Integer e) Nothing++toRSAPrivateKeyParameters :: RSA.PrivateKey -> RSAPrivateKeyParameters+toRSAPrivateKeyParameters (RSA.PrivateKey _ d p q dp dq qi) =   let i = Types.Base64Integer-  in RSAKeyParameters-    ( i n )-    ( i e )-    ( Just (RSAPrivateKeyParameters (i d)-      (Just (RSAPrivateKeyOptionalParameters-        (i p) (i q) (i dp) (i dq) (i qi) Nothing))) )+  in RSAPrivateKeyParameters (i d)+      (Just (RSAPrivateKeyOptionalParameters (i p) (i q) (i dp) (i dq) (i qi) Nothing))  signPKCS15   :: (PKCS15.HashAlgorithmASN1 h, MonadRandom m, MonadError e m, AsError e)@@ -555,17 +561,20 @@   deriving (Eq, Show)  showKeyType :: KeyMaterial -> String-showKeyType (ECKeyMaterial (ECKeyParameters { _ecCrv = crv })) = "ECDSA (" ++ show crv ++ ")"+showKeyType (ECKeyMaterial ECKeyParameters{ _ecCrv = crv }) = "ECDSA (" ++ show crv ++ ")" showKeyType (RSAKeyMaterial _) = "RSA" showKeyType (OctKeyMaterial _) = "symmetric" showKeyType (OKPKeyMaterial _) = "OKP"  instance FromJSON KeyMaterial where   parseJSON = withObject "KeyMaterial" $ \o ->-    ECKeyMaterial      <$> parseJSON (Object o)-    <|> RSAKeyMaterial <$> parseJSON (Object o)-    <|> OctKeyMaterial <$> parseJSON (Object o)-    <|> OKPKeyMaterial <$> parseJSON (Object o)+    case M.lookup "kty" o of+      Nothing     -> fail "missing \"kty\" parameter"+      Just "EC"   -> ECKeyMaterial  <$> parseJSON (Object o)+      Just "RSA"  -> RSAKeyMaterial <$> parseJSON (Object o)+      Just "oct"  -> OctKeyMaterial <$> parseJSON (Object o)+      Just "OKP"  -> OKPKeyMaterial <$> parseJSON (Object o)+      Just s      -> fail $ "unsupported \"kty\": " <> show s  instance ToJSON KeyMaterial where   toJSON (ECKeyMaterial p)  = object $ Types.objectPairs (toJSON p)@@ -608,9 +617,9 @@   -> B.ByteString   -> m B.ByteString sign JWA.JWS.None _ = \_ -> return ""-sign JWA.JWS.ES256 (ECKeyMaterial k@(ECKeyParameters { _ecCrv = P_256 })) = signEC SHA256 k-sign JWA.JWS.ES384 (ECKeyMaterial k@(ECKeyParameters { _ecCrv = P_384 })) = signEC SHA384 k-sign JWA.JWS.ES512 (ECKeyMaterial k@(ECKeyParameters { _ecCrv = P_521 })) = signEC SHA512 k+sign JWA.JWS.ES256 (ECKeyMaterial k@ECKeyParameters{ _ecCrv = P_256 }) = signEC SHA256 k+sign JWA.JWS.ES384 (ECKeyMaterial k@ECKeyParameters{ _ecCrv = P_384 }) = signEC SHA384 k+sign JWA.JWS.ES512 (ECKeyMaterial k@ECKeyParameters{ _ecCrv = P_521 }) = signEC SHA512 k sign JWA.JWS.RS256 (RSAKeyMaterial k) = signPKCS15 SHA256 k sign JWA.JWS.RS384 (RSAKeyMaterial k) = signPKCS15 SHA384 k sign JWA.JWS.RS512 (RSAKeyMaterial k) = signPKCS15 SHA512 k
src/Crypto/JOSE/JWE.hs view
@@ -68,16 +68,16 @@ data JWEHeader p = JWEHeader   { _jweAlg :: Maybe AlgWithParams   , _jweEnc :: HeaderParam p Enc-  , _jweZip :: Maybe String  -- protected header only  "DEF" (DEFLATE) defined+  , _jweZip :: Maybe T.Text  -- protected header only  "DEF" (DEFLATE) defined   , _jweJku :: Maybe (HeaderParam p Types.URI)   , _jweJwk :: Maybe (HeaderParam p JWK)-  , _jweKid :: Maybe (HeaderParam p String)+  , _jweKid :: Maybe (HeaderParam p T.Text)   , _jweX5u :: Maybe (HeaderParam p Types.URI)-  , _jweX5c :: Maybe (HeaderParam p (NonEmpty Types.Base64X509))+  , _jweX5c :: Maybe (HeaderParam p (NonEmpty Types.SignedCertificate))   , _jweX5t :: Maybe (HeaderParam p Types.Base64SHA1)   , _jweX5tS256 :: Maybe (HeaderParam p Types.Base64SHA256)-  , _jweTyp :: Maybe (HeaderParam p String)  -- ^ Content Type (of object)-  , _jweCty :: Maybe (HeaderParam p String)  -- ^ Content Type (of payload)+  , _jweTyp :: Maybe (HeaderParam p T.Text)  -- ^ Content Type (of object)+  , _jweCty :: Maybe (HeaderParam p T.Text)  -- ^ Content Type (of payload)   , _jweCrit :: Maybe (NonEmpty T.Text)   }   deriving (Eq, Show)@@ -96,7 +96,8 @@     <*> headerOptional "jwk" hp hu     <*> headerOptional "kid" hp hu     <*> headerOptional "x5u" hp hu-    <*> headerOptional "x5c" hp hu+    <*> ((fmap . fmap . fmap . fmap)+          (\(Types.Base64X509 cert) -> cert) (headerOptional "x5c" hp hu))     <*> headerOptional "x5t" hp hu     <*> headerOptional "x5t#S256" hp hu     <*> headerOptional "typ" hp hu@@ -113,7 +114,7 @@       , fmap (\p -> (view isProtected p, "jwk" .= view param p)) jwk       , fmap (\p -> (view isProtected p, "kid" .= view param p)) kid       , fmap (\p -> (view isProtected p, "x5u" .= view param p)) x5u-      , fmap (\p -> (view isProtected p, "x5c" .= view param p)) x5c+      , fmap (\p -> (view isProtected p, "x5c" .= fmap Types.Base64X509 (view param p))) x5c       , fmap (\p -> (view isProtected p, "x5t" .= view param p)) x5t       , fmap (\p -> (view isProtected p, "x5t#S256" .= view param p)) x5tS256       , fmap (\p -> (view isProtected p, "typ" .= view param p)) typ
src/Crypto/JOSE/JWK.hs view
@@ -62,6 +62,7 @@   , jwkKid   , jwkX5u   , jwkX5c+  , setJWKX5c   , jwkX5t   , jwkX5tS256 @@ -69,6 +70,7 @@   , fromKeyMaterial   , fromRSA   , fromOctets+  , fromX509Certificate  #if MIN_VERSION_aeson(0,10,0)   -- * JWK Thumbprint@@ -88,6 +90,8 @@   ) where  import Control.Applicative+import Control.Monad ((>=>))+import Data.Function (on) import Data.Maybe (catMaybes) import Data.Monoid ((<>)) import Data.Word (Word8)@@ -104,6 +108,7 @@ import qualified Data.ByteString.Builder as Builder import Data.List.NonEmpty import qualified Data.Text as T+import qualified Data.X509 as X509  import Test.QuickCheck @@ -157,33 +162,62 @@   , _jwkAlg :: Maybe JWKAlg   , _jwkKid :: Maybe T.Text   , _jwkX5u :: Maybe Types.URI-  , _jwkX5c :: Maybe (NonEmpty Types.Base64X509)+  , _jwkX5cRaw :: Maybe (NonEmpty X509.SignedCertificate)   , _jwkX5t :: Maybe Types.Base64SHA1   , _jwkX5tS256 :: Maybe Types.Base64SHA256   }   deriving (Eq, Show) makeLenses ''JWK +-- | Get the certificate chain.  Not a lens, because the key of the first+-- certificate in the chain must correspond be the public key of the JWK.+-- To set the certificate chain use 'setJWKX5c'.+--+jwkX5c :: Getter JWK (Maybe (NonEmpty X509.SignedCertificate))+jwkX5c = jwkX5cRaw++-- | Set the @"x5c"@ Certificate Chain parameter.  If setting the list,+-- checks that the key in the first certificate matches the JWK; returns+-- @Nothing@ if it does not.+--+setJWKX5c :: Maybe (NonEmpty X509.SignedCertificate) -> JWK -> Maybe JWK+setJWKX5c Nothing k = pure (set jwkX5cRaw Nothing k)+setJWKX5c certs@(Just (cert :| _)) key+  | certMatchesKey key cert = pure (set jwkX5cRaw certs key)+  | otherwise = Nothing++certMatchesKey :: JWK -> X509.SignedCertificate -> Bool+certMatchesKey key cert =+  maybe False (((==) `on` preview (jwkMaterial . asPublicKey)) key)+    (fromX509CertificateMaybe cert)++ instance FromJSON JWK where-  parseJSON = withObject "JWK" $ \o -> JWK+  parseJSON = withObject "JWK" (\o -> JWK     <$> parseJSON (Object o)     <*> o .:? "use"     <*> o .:? "key_ops"     <*> o .:? "alg"     <*> o .:? "kid"     <*> o .:? "x5u"-    <*> o .:? "x5c"+    <*> ((fmap . fmap) (\(Types.Base64X509 cert) -> cert) <$> o .:? "x5c")     <*> o .:? "x5t"     <*> o .:? "x5t#S256"+    ) >=> checkKey+    where+    checkKey k+      | maybe False (not . certMatchesKey k . Data.List.NonEmpty.head) (view jwkX5c k)+        = fail "X.509 cert in \"x5c\" param does not match key"+      | otherwise = pure k  instance ToJSON JWK where-  toJSON (JWK {..}) = object $ catMaybes+  toJSON JWK{..} = object $ catMaybes     [ fmap ("alg" .=) _jwkAlg     , fmap ("use" .=) _jwkUse     , fmap ("key_ops" .=) _jwkKeyOps     , fmap ("kid" .=) _jwkKid     , fmap ("x5u" .=) _jwkX5u-    , fmap ("x5c" .=) _jwkX5c+    , fmap (("x5c" .=) . fmap Types.Base64X509) _jwkX5cRaw     , fmap ("x5t" .=) _jwkX5t     , fmap ("x5t#S256" .=) _jwkX5tS256     ]@@ -215,12 +249,40 @@ fromRSA :: RSA.PrivateKey -> JWK fromRSA = fromKeyMaterial . RSAKeyMaterial . toRSAKeyParameters +-- | Convert an RSA public key into a JWK+--+fromRSAPublic :: RSA.PublicKey -> JWK+fromRSAPublic = fromKeyMaterial . RSAKeyMaterial . toRSAPublicKeyParameters+ -- | Convert octet string into a JWK -- fromOctets :: Cons s s Word8 Word8 => s -> JWK fromOctets =   fromKeyMaterial . OctKeyMaterial . OctKeyParameters . Types.Base64Octets   . view recons+++-- | Convert an X.509 certificate into a JWK.+--+-- Only RSA keys are supported.  Other key types will throw+-- 'KeyMismatch'.+--+-- The @"x5c"@ field of the resulting JWK contains the certificate.+--+fromX509Certificate+  :: (AsError e, MonadError e m)+  => X509.SignedCertificate -> m JWK+fromX509Certificate =+  maybe (throwError (review _KeyMismatch "X.509 key type not supported")) pure+  . fromX509CertificateMaybe++fromX509CertificateMaybe :: X509.SignedCertificate -> Maybe JWK+fromX509CertificateMaybe cert = do+  k <- case (X509.certPubKey . X509.signedObject . X509.getSigned) cert of+    X509.PubKeyRSA k -> pure (fromRSAPublic k)+    _ -> {- TODO EC -} Nothing+  pure $ k & set jwkX5cRaw (Just (pure cert))+   instance AsPublicKey JWK where
src/Crypto/JOSE/JWK/Store.hs view
@@ -1,4 +1,4 @@--- Copyright (C) 2013, 2014, 2015, 2016  Fraser Tweedale+-- Copyright (C) 2013-2018  Fraser Tweedale -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License.@@ -12,41 +12,72 @@ -- See the License for the specific language governing permissions and -- limitations under the License. -{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}  {-| -A 'JWKStore' provides JWK enumeration and lookup.+Key stores.  Instances are provided for 'JWK' and 'JWKSet'.  These+instances ignore the header and payload and just return the JWK/s+they contain.  More complex scenarios, such as efficient key lookup+by @"kid"@ or searching a database, can be implemented by writing a+new instance. +For example, the following instance looks in a filesystem directory+for keys based on either the JWS Header's @"kid"@ parameter, or the+  @"iss"@ claim in a JWT Claims Set:++@+-- | A KeyDB is just a filesystem directory+newtype KeyDB = KeyDB FilePath++instance (MonadIO m, HasKid h)+    => VerificationKeyStore m (h p) ClaimsSet KeyDB where+  getVerificationKeys h claims (KeyDB dir) = liftIO $+    fmap catMaybes . traverse findKey $ catMaybes+      [ preview (kid . _Just . param) h+      , preview (claimIss . _Just . string) claims]+    where+    findKey :: T.Text -> IO (Maybe JWK)+    findKey s =+      let path = dir <> "/" <> T.unpack s <> ".jwk"+      in handle+        (\(_ :: IOException) -> pure Nothing)+        (decode <$> L.readFile path)+@+ -} module Crypto.JOSE.JWK.Store   (-    JWKStore(..)+    VerificationKeyStore(..)   ) where --import Control.Lens (Fold, folding)--import Crypto.JOSE.Header-import Crypto.JOSE.JWK (JWK, JWKSet(..), KeyOp)--class JWKStore a where-  -- | Enumerate keys-  keys :: Fold a JWK--  -- | Look up key by JWS/JWE header-  keysFor-    ::  ( HasAlg h, HasJku h, HasJwk h, HasKid h-        , HasX5u h, HasX5c h, HasX5t h, HasX5tS256 h-        , HasTyp h, HasCty h )-    => KeyOp-    -> h p-    -> Fold a JWK-  keysFor _ _ = keys+import Crypto.JOSE.JWK (JWK, JWKSet(..)) +-- | Verification keys.  Lookup operates in effect @m@ with access+-- to the JWS header of type @h@ and a payload of type @s@.+--+-- The returned keys are not guaranteed to be used, e.g. if the JWK+-- @"use"@ or @"key_ops"@ field does not allow use for verification.+--+class VerificationKeyStore m h s a where+  -- | Look up verification keys by JWS header and payload.+  getVerificationKeys+    :: h          -- ^ JWS header+    -> s          -- ^ Payload+    -> a+    -> m [JWK] -instance JWKStore JWK where-  keys = id+-- | Use a 'JWK' as a 'VerificationKeyStore'.  Can be used with any+-- payload type.  Header and payload are ignored.  No filtering is+-- performed.+--+instance Applicative m => VerificationKeyStore m h s JWK where+  getVerificationKeys _ _ k = pure [k] -instance JWKStore JWKSet where-  keys = folding (\(JWKSet xs) -> xs)+-- | Use a 'JWKSet' as a 'VerificationKeyStore'.  Can be used with+-- any payload type.  Returns all keys in the set; header and+-- payload are ignored.  No filtering is performed.+--+instance Applicative m => VerificationKeyStore m h s JWKSet where+  getVerificationKeys _ _ (JWKSet xs) = pure xs
src/Crypto/JOSE/JWS.hs view
@@ -35,6 +35,8 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE MonoLocalBinds #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS_GHC -fno-warn-orphans #-}  module Crypto.JOSE.JWS@@ -50,11 +52,13 @@    -- * JWS creation   , newJWSHeader+  , makeJWSHeader   , signJWS    -- * JWS verification   , verifyJWS   , verifyJWS'+  , verifyJWSWithPayload    -- ** JWS validation settings   , defaultValidationSettings@@ -90,7 +94,7 @@  import Control.Lens hiding ((.=)) import Control.Lens.Cons.Extras (recons)-import Control.Monad.Except (MonadError(throwError))+import Control.Monad.Except (MonadError(throwError), unless) import Data.Aeson import qualified Data.ByteString as B import qualified Data.HashMap.Strict as M@@ -175,81 +179,58 @@   { _jwsHeaderAlg :: HeaderParam p Alg   , _jwsHeaderJku :: Maybe (HeaderParam p Types.URI)  -- ^ JWK Set URL   , _jwsHeaderJwk :: Maybe (HeaderParam p JWK)-  , _jwsHeaderKid :: Maybe (HeaderParam p String)  -- ^ interpretation unspecified+  , _jwsHeaderKid :: Maybe (HeaderParam p T.Text)  -- ^ interpretation unspecified   , _jwsHeaderX5u :: Maybe (HeaderParam p Types.URI)-  , _jwsHeaderX5c :: Maybe (HeaderParam p (NonEmpty Types.Base64X509))+  , _jwsHeaderX5c :: Maybe (HeaderParam p (NonEmpty Types.SignedCertificate))   , _jwsHeaderX5t :: Maybe (HeaderParam p Types.Base64SHA1)   , _jwsHeaderX5tS256 :: Maybe (HeaderParam p Types.Base64SHA256)-  , _jwsHeaderTyp :: Maybe (HeaderParam p String)  -- ^ Content Type (of object)-  , _jwsHeaderCty :: Maybe (HeaderParam p String)  -- ^ Content Type (of payload)+  , _jwsHeaderTyp :: Maybe (HeaderParam p T.Text)  -- ^ Content Type (of object)+  , _jwsHeaderCty :: Maybe (HeaderParam p T.Text)  -- ^ Content Type (of payload)   , _jwsHeaderCrit :: Maybe (NonEmpty T.Text)   }   deriving (Eq, Show) -instance HasAlg JWSHeader where-  alg f h@(JWSHeader { _jwsHeaderAlg = a }) =+class HasJWSHeader a where+  jwsHeader :: Lens' (a p) (JWSHeader p)++instance HasJWSHeader JWSHeader where+  jwsHeader = id++instance HasJWSHeader a => HasAlg a where+  alg = jwsHeader . \f h@(JWSHeader { _jwsHeaderAlg = a }) ->     fmap (\a' -> h { _jwsHeaderAlg = a' }) (f a)-instance HasJku JWSHeader where-  jku f h@(JWSHeader { _jwsHeaderJku = a }) =+instance HasJWSHeader a => HasJku a where+  jku = jwsHeader . \f h@(JWSHeader { _jwsHeaderJku = a }) ->     fmap (\a' -> h { _jwsHeaderJku = a' }) (f a)-instance HasJwk JWSHeader where-  jwk f h@(JWSHeader { _jwsHeaderJwk = a }) =+instance HasJWSHeader a => HasJwk a where+  jwk = jwsHeader . \f h@(JWSHeader { _jwsHeaderJwk = a }) ->     fmap (\a' -> h { _jwsHeaderJwk = a' }) (f a)-instance HasKid JWSHeader where-  kid f h@(JWSHeader { _jwsHeaderKid = a }) =+instance HasJWSHeader a => HasKid a where+  kid = jwsHeader . \f h@(JWSHeader { _jwsHeaderKid = a }) ->     fmap (\a' -> h { _jwsHeaderKid = a' }) (f a)-instance HasX5u JWSHeader where-  x5u f h@(JWSHeader { _jwsHeaderX5u = a }) =+instance HasJWSHeader a => HasX5u a where+  x5u = jwsHeader . \f h@(JWSHeader { _jwsHeaderX5u = a }) ->     fmap (\a' -> h { _jwsHeaderX5u = a' }) (f a)-instance HasX5c JWSHeader where-  x5c f h@(JWSHeader { _jwsHeaderX5c = a }) =+instance HasJWSHeader a => HasX5c a where+  x5c = jwsHeader . \f h@(JWSHeader { _jwsHeaderX5c = a }) ->     fmap (\a' -> h { _jwsHeaderX5c = a' }) (f a)-instance HasX5t JWSHeader where-  x5t f h@(JWSHeader { _jwsHeaderX5t = a }) =+instance HasJWSHeader a => HasX5t a where+  x5t = jwsHeader . \f h@(JWSHeader { _jwsHeaderX5t = a }) ->     fmap (\a' -> h { _jwsHeaderX5t = a' }) (f a)-instance HasX5tS256 JWSHeader where-  x5tS256 f h@(JWSHeader { _jwsHeaderX5tS256 = a }) =+instance HasJWSHeader a => HasX5tS256 a where+  x5tS256 = jwsHeader . \f h@(JWSHeader { _jwsHeaderX5tS256 = a }) ->     fmap (\a' -> h { _jwsHeaderX5tS256 = a' }) (f a)-instance HasTyp JWSHeader where-  typ f h@(JWSHeader { _jwsHeaderTyp = a }) =+instance HasJWSHeader a => HasTyp a where+  typ = jwsHeader . \f h@(JWSHeader { _jwsHeaderTyp = a }) ->     fmap (\a' -> h { _jwsHeaderTyp = a' }) (f a)-instance HasCty JWSHeader where-  cty f h@(JWSHeader { _jwsHeaderCty = a }) =+instance HasJWSHeader a => HasCty a where+  cty = jwsHeader . \f h@(JWSHeader { _jwsHeaderCty = a }) ->     fmap (\a' -> h { _jwsHeaderCty = a' }) (f a)-instance HasCrit JWSHeader where-  crit f h@(JWSHeader { _jwsHeaderCrit = a }) =+instance HasJWSHeader a => HasCrit a where+  crit = jwsHeader . \f h@(JWSHeader { _jwsHeaderCrit = a }) ->     fmap (\a' -> h { _jwsHeaderCrit = a' }) (f a) -class HasJWSHeader a where-  jwsHeader :: Lens' (a p) (JWSHeader p) -instance HasJWSHeader JWSHeader where-  jwsHeader = id--instance {-# INCOHERENT #-} HasJWSHeader a => HasAlg a where-  alg = jwsHeader . alg-instance {-# INCOHERENT #-} HasJWSHeader a => HasJku a where-  jku = jwsHeader . jku-instance {-# INCOHERENT #-} HasJWSHeader a => HasJwk a where-  jwk = jwsHeader . jwk-instance {-# INCOHERENT #-} HasJWSHeader a => HasKid a where-  kid = jwsHeader . kid-instance {-# INCOHERENT #-} HasJWSHeader a => HasX5u a where-  x5u = jwsHeader . x5u-instance {-# INCOHERENT #-} HasJWSHeader a => HasX5c a where-  x5c = jwsHeader . x5c-instance {-# INCOHERENT #-} HasJWSHeader a => HasX5t a where-  x5t = jwsHeader . x5t-instance {-# INCOHERENT #-} HasJWSHeader a => HasX5tS256 a where-  x5tS256 = jwsHeader . x5tS256-instance {-# INCOHERENT #-} HasJWSHeader a => HasTyp a where-  typ = jwsHeader . typ-instance {-# INCOHERENT #-} HasJWSHeader a => HasCty a where-  cty = jwsHeader . cty-instance {-# INCOHERENT #-} HasJWSHeader a => HasCrit a where-  crit = jwsHeader . crit-- -- | Construct a minimal header with the given algorithm and -- protection indicator for the /alg/ header. --@@ -257,7 +238,35 @@ newJWSHeader a = JWSHeader (uncurry HeaderParam a) z z z z z z z z z z   where z = Nothing +-- | Make a JWS header for the given signing key.+--+-- Uses 'bestJWSAlg' to choose the algorithm.+-- If set, the JWK's @"kid"@, @"x5u"@, @"x5c"@, @"x5t"@ and+-- @"x5t#S256"@ parameters are copied to the JWS header (as+-- protected parameters).+--+-- May return 'KeySizeTooSmall' or 'KeyMismatch'.+--+makeJWSHeader+  :: forall e m p. (MonadError e m, AsError e, ProtectionIndicator p)+  => JWK+  -> m (JWSHeader p)+makeJWSHeader k = do+  let+    p = getProtected+    f :: ASetter s t a (Maybe (HeaderParam p a1))+      -> Getting (Maybe a1) JWK (Maybe a1)+      -> s -> t+    f lh lk = set lh (HeaderParam p <$> view lk k)+  algo <- bestJWSAlg k+  pure $ newJWSHeader (p, algo)+    & f kid (jwkKid . to (fmap (view recons)))+    & f x5u jwkX5u+    & f x5c jwkX5c+    & f x5t jwkX5t+    & f x5tS256 jwkX5tS256 + -- | Signature object containing header, and signature bytes. -- -- If it was decoded from a serialised JWS, it "remembers" how the@@ -322,9 +331,10 @@     <*> headerOptional "jwk" hp hu     <*> headerOptional "kid" hp hu     <*> headerOptional "x5u" hp hu+    <*> ((fmap . fmap . fmap . fmap)+          (\(Types.Base64X509 cert) -> cert) (headerOptional "x5c" hp hu))     <*> headerOptional "x5t" hp hu     <*> headerOptional "x5t#S256" hp hu-    <*> headerOptional "x5c" hp hu     <*> headerOptional "typ" hp hu     <*> headerOptional "cty" hp hu     <*> (headerOptionalProtected "crit" hp hu@@ -337,7 +347,7 @@       , fmap (\p -> (view isProtected p, "jwk" .= view param p)) (view jwk h)       , fmap (\p -> (view isProtected p, "kid" .= view param p)) (view kid h)       , fmap (\p -> (view isProtected p, "x5u" .= view param p)) (view x5u h)-      , fmap (\p -> (view isProtected p, "x5c" .= view param p)) (view x5c h)+      , fmap (\p -> (view isProtected p, "x5c" .= fmap Types.Base64X509 (view param p))) (view x5c h)       , fmap (\p -> (view isProtected p, "x5t" .= view param p)) (view x5t h)       , fmap (\p -> (view isProtected p, "x5t#S256" .= view param p)) (view x5tS256 h)       , fmap (\p -> (view isProtected p, "typ" .= view param p)) (view typ h)@@ -441,15 +451,18 @@ instance HasParams a => FromCompact (JWS Identity () a) where   fromCompact xs = case xs of     [h, p, s] -> do-      (h', p', s') <- (,,) <$> t h <*> t p <*> t s+      (h', p', s') <- (,,) <$> t 0 h <*> t 1 p <*> t 2 s       let o = object [ ("payload", p'), ("protected", h'), ("signature", s') ]       case fromJSON o of-        Error e -> throwError (compactErr e)+        Error e -> throwError (review _JSONDecodeError e)         Success a -> pure a-    xs' -> throwError $ compactErr $ "expected 3 parts, got " ++ show (length xs')+    xs' -> throwError $+            review (_CompactDecodeError . _CompactInvalidNumberOfParts)+            (InvalidNumberOfParts 3 (fromIntegral (length xs')))     where-      compactErr = review _CompactDecodeError-      t = either (throwError . compactErr . show) (pure . String)+      textErr n e = review (_CompactDecodeError . _CompactInvalidText)+        (CompactTextError n e)+      t n = either (throwError . textErr n) (pure . String)         . T.decodeUtf8' . view recons  @@ -545,7 +558,8 @@ -- See also 'defaultValidationSettings'. -- verifyJWS'-  ::  ( AsError e, MonadError e m , HasJWSHeader h, HasParams h , JWKStore k+  ::  ( AsError e, MonadError e m , HasJWSHeader h, HasParams h+      , VerificationKeyStore m (h p) s k       , Cons s s Word8 Word8, AsEmpty s       , Foldable t       , ProtectionIndicator p@@ -568,7 +582,7 @@ verifyJWS   ::  ( HasAlgorithms a, HasValidationPolicy a, AsError e, MonadError e m       , HasJWSHeader h, HasParams h-      , JWKStore k+      , VerificationKeyStore m (h p) s k       , Cons s s Word8 Word8, AsEmpty s       , Foldable t       , ProtectionIndicator p@@ -577,24 +591,45 @@   -> k        -- ^ key or key store   -> JWS t p h  -- ^ JWS   -> m s-verifyJWS conf k (JWS p@(Types.Base64Octets p') sigs) =+verifyJWS = verifyJWSWithPayload pure++verifyJWSWithPayload+  ::  ( HasAlgorithms a, HasValidationPolicy a, AsError e, MonadError e m+      , HasJWSHeader h, HasParams h+      , VerificationKeyStore m (h p) payload k+      , Cons s s Word8 Word8, AsEmpty s+      , Foldable t+      , ProtectionIndicator p+      )+  => (s -> m payload)  -- ^ payload decoder+  -> a                 -- ^ validation settings+  -> k                 -- ^ key or key store+  -> JWS t p h         -- ^ JWS+  -> m payload+verifyJWSWithPayload dec conf k (JWS p@(Types.Base64Octets p') sigs) =   let     algs :: S.Set Alg     algs = conf ^. algorithms     policy :: ValidationPolicy     policy = conf ^. validationPolicy     shouldValidateSig = (`elem` algs) . view (header . alg . param)-    out = view recons p'+     applyPolicy AnyValidated xs =-      if or xs then pure out else throwError (review _JWSNoValidSignatures ())-    applyPolicy AllValidated [] = throwError (review _JWSNoSignatures ())+      unless (or xs) (throwError (review _JWSNoValidSignatures ()))+    applyPolicy AllValidated [] =+      throwError (review _JWSNoSignatures ())     applyPolicy AllValidated xs =-      if and xs then pure out else throwError (review _JWSInvalidSignature ())-    validate s =-      let h = view header s-      in anyOf (keysFor Verify h) ((== Right True) . verifySig p s) k-  in-    applyPolicy policy $ map validate $ filter shouldValidateSig $ toList sigs+      unless (and xs) (throwError (review _JWSInvalidSignature ()))++    validate payload sig = do+      keys <- getVerificationKeys (view header sig) payload k+      if null keys+        then throwError (review _NoUsableKeys ())+        else pure $ any ((== Right True) . verifySig p sig) keys+  in do+    payload <- (dec . view recons) p'+    results <- traverse (validate payload) $ filter shouldValidateSig $ toList sigs+    payload <$ applyPolicy policy results  verifySig   :: (HasJWSHeader a, HasParams a, ProtectionIndicator p)
src/Crypto/JOSE/Types.hs view
@@ -31,6 +31,7 @@   , Base64SHA1(..)   , Base64SHA256(..)   , Base64X509(..)+  , SignedCertificate   , URI   , base64url   ) where
src/Crypto/JWT.hs view
@@ -18,6 +18,8 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE MonoLocalBinds #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}  {-| @@ -67,7 +69,6 @@   (   -- * Creating a JWT     signClaims-  , JWT   , SignedJWT    -- * Validating a JWT and extracting claims@@ -120,13 +121,13 @@ import Data.Foldable (traverse_) import Data.Functor.Identity import Data.Maybe-import Data.List (unfoldr) import qualified Data.String  import Control.Lens (   makeClassy, makeClassyPrisms, makePrisms,   Lens', _Just, over, preview, review, view,-  Prism', prism', Cons, cons, uncons, iso, Iso')+  Prism', prism', Cons, iso, AsEmpty)+import Control.Lens.Cons.Extras (recons) import Control.Monad.Except (MonadError(throwError)) import Control.Monad.Reader (ReaderT, ask, runReaderT) import Data.Aeson@@ -167,22 +168,22 @@ -- contains a @:@ but does not parse as a 'URI'.  Use 'stringOrUri' -- directly in this situation. ---data StringOrURI = Arbitrary String | OrURI URI deriving (Eq, Show)+data StringOrURI = Arbitrary T.Text | OrURI URI deriving (Eq, Show) +-- | Non-total.  A string with a @':'@ in it MUST parse as a URI instance Data.String.IsString StringOrURI where   fromString = fromJust . preview stringOrUri -consString :: (Cons s s Char Char, Monoid s) => Iso' s String-consString = iso (unfoldr uncons) (foldr cons mempty)--stringOrUri :: (Cons s s Char Char, Monoid s) => Prism' s StringOrURI-stringOrUri = consString . prism' rev fwd+stringOrUri :: (Cons s s Char Char, AsEmpty s) => Prism' s StringOrURI+stringOrUri = iso (view recons) (view recons) . prism' rev fwd   where   rev (Arbitrary s) = s-  rev (OrURI x) = show x-  fwd s = if ':' `elem` s then OrURI <$> parseURI s else pure (Arbitrary s)+  rev (OrURI x) = T.pack (show x)+  fwd s+    | T.any (== ':') s = OrURI <$> parseURI (T.unpack s)+    | otherwise = pure (Arbitrary s) -string :: Prism' StringOrURI String+string :: Prism' StringOrURI T.Text string = prism' Arbitrary f where   f (Arbitrary s) = Just s   f _ = Nothing@@ -256,7 +257,7 @@ -- JWT.  The processing of this claim is generally application -- specific. claimIss :: Lens' ClaimsSet (Maybe StringOrURI)-claimIss f h@(ClaimsSet { _claimIss = a}) =+claimIss f h@ClaimsSet{ _claimIss = a} =   fmap (\a' -> h { _claimIss = a' }) (f a)  -- | The subject claim identifies the principal that is the@@ -266,7 +267,7 @@ -- globally unique.  The processing of this claim is generally -- application specific. claimSub :: Lens' ClaimsSet (Maybe StringOrURI)-claimSub f h@(ClaimsSet { _claimSub = a}) =+claimSub f h@ClaimsSet{ _claimSub = a} =   fmap (\a' -> h { _claimSub = a' }) (f a)  -- | The audience claim identifies the recipients that the JWT is@@ -276,7 +277,7 @@ -- value in the /aud/ claim when this claim is present, then the -- JWT MUST be rejected. claimAud :: Lens' ClaimsSet (Maybe Audience)-claimAud f h@(ClaimsSet { _claimAud = a}) =+claimAud f h@ClaimsSet{ _claimAud = a} =   fmap (\a' -> h { _claimAud = a' }) (f a)  -- | The expiration time claim identifies the expiration time on@@ -286,7 +287,7 @@ -- /exp/ claim.  Implementers MAY provide for some small leeway, -- usually no more than a few minutes, to account for clock skew. claimExp :: Lens' ClaimsSet (Maybe NumericDate)-claimExp f h@(ClaimsSet { _claimExp = a}) =+claimExp f h@ClaimsSet{ _claimExp = a} =   fmap (\a' -> h { _claimExp = a' }) (f a)  -- | The not before claim identifies the time before which the JWT@@ -296,14 +297,14 @@ -- claim.  Implementers MAY provide for some small leeway, usually -- no more than a few minutes, to account for clock skew. claimNbf :: Lens' ClaimsSet (Maybe NumericDate)-claimNbf f h@(ClaimsSet { _claimNbf = a}) =+claimNbf f h@ClaimsSet{ _claimNbf = a} =   fmap (\a' -> h { _claimNbf = a' }) (f a)  -- | The issued at claim identifies the time at which the JWT was -- issued.  This claim can be used to determine the age of the -- JWT. claimIat :: Lens' ClaimsSet (Maybe NumericDate)-claimIat f h@(ClaimsSet { _claimIat = a}) =+claimIat f h@ClaimsSet{ _claimIat = a} =   fmap (\a' -> h { _claimIat = a' }) (f a)  -- | The JWT ID claim provides a unique identifier for the JWT.@@ -313,12 +314,12 @@ -- claim can be used to prevent the JWT from being replayed.  The -- /jti/ value is a case-sensitive string. claimJti :: Lens' ClaimsSet (Maybe T.Text)-claimJti f h@(ClaimsSet { _claimJti = a}) =+claimJti f h@ClaimsSet{ _claimJti = a} =   fmap (\a' -> h { _claimJti = a' }) (f a)  -- | Claim Names can be defined at will by those using JWTs. unregisteredClaims :: Lens' ClaimsSet (M.HashMap T.Text Value)-unregisteredClaims f h@(ClaimsSet { _unregisteredClaims = a}) =+unregisteredClaims f h@ClaimsSet{ _unregisteredClaims = a} =   fmap (\a' -> h { _unregisteredClaims = a' }) (f a)  @@ -368,7 +369,7 @@   } makeClassy ''JWTValidationSettings -instance HasValidationSettings JWTValidationSettings where+instance HasJWTValidationSettings a => HasValidationSettings a where   validationSettings = jwtValidationSettingsValidationSettings  -- | Maximum allowed skew when validating the /nbf/, /exp/ and /iat/ claims.@@ -464,7 +465,7 @@   traverse_ (\t -> do     now <- currentTime     when (view checkIssuedAt conf) $-      when ((view _NumericDate t) > addUTCTime (abs (view allowedSkew conf)) now) $+      when (view _NumericDate t > addUTCTime (abs (view allowedSkew conf)) now) $         throwError (review _JWTIssuedAtFuture ()))     . preview (claimIat . _Just) @@ -502,21 +503,9 @@       throwError (review _JWTNotInIssuer ()))   . preview (claimIss . _Just) ---- | JSON Web Token data.----newtype JWT a = JWT a-  deriving (Eq, Show)- -- | A digitally signed or MACed JWT ---type SignedJWT = JWT (CompactJWS JWSHeader)--instance FromCompact a => FromCompact (JWT a) where-  fromCompact = fmap JWT . fromCompact--instance ToCompact a => ToCompact (JWT a) where-  toCompact (JWT a) = toCompact a+type SignedJWT = CompactJWS JWSHeader   newtype WrappedUTCTime = WrappedUTCTime { getUTCTime :: UTCTime }@@ -542,18 +531,18 @@     , HasCheckIssuedAt a     , HasValidationSettings a     , AsError e, AsJWTError e, MonadError e m-    , JWKStore k+    , VerificationKeyStore m (JWSHeader ()) ClaimsSet k     )   => a   -> k   -> SignedJWT   -> m ClaimsSet-verifyClaims conf k (JWT jws) =+verifyClaims conf k jws =   -- It is important, for security reasons, that the signature get   -- verified before the claims.-  verifyJWS conf k jws-  >>= either (throwError . review _JWTClaimsSetDecodeError) pure . eitherDecode-  >>= validateClaimsSet conf+  verifyJWSWithPayload f conf k jws >>= validateClaimsSet conf+  where+    f = either (throwError . review _JWTClaimsSetDecodeError) pure . eitherDecode   -- | Cryptographically verify a JWS JWT, then validate the@@ -570,7 +559,7 @@     , HasCheckIssuedAt a     , HasValidationSettings a     , AsError e, AsJWTError e, MonadError e m-    , JWKStore k+    , VerificationKeyStore (ReaderT WrappedUTCTime m) (JWSHeader ()) ClaimsSet k     )   => a   -> k@@ -587,5 +576,4 @@   -> JWSHeader ()   -> ClaimsSet   -> m SignedJWT-signClaims k h c =-  JWT <$> signJWS (encode c) (Identity (h, k))+signClaims k h c = signJWS (encode c) (Identity (h, k))
test/JWK.hs view
@@ -1,4 +1,4 @@--- Copyright (C) 2013, 2017  Fraser Tweedale+-- Copyright (C) 2013, 2017, 2018  Fraser Tweedale -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License.@@ -19,7 +19,7 @@  import Data.Monoid ((<>)) -import Control.Lens (_Right, review, view)+import Control.Lens (_Left, _Right, review, view) import Control.Lens.Extras (is) import Data.Aeson import qualified Data.ByteArray as BA@@ -179,23 +179,10 @@       <> "}"  jwkAppendixBSpec :: Spec-jwkAppendixBSpec = describe "JWK B.  Example Use of \"x5c\" (X.509 Certificate Chain) Parameter" $-  it "successfully decodes the example" $-    (eitherDecode exampleJWK :: Either String JWK) `shouldSatisfy` is _Right-    where-    exampleJWK = ""-      <> "{\"kty\":\"RSA\","-      <> " \"use\":\"sig\","-      <> " \"kid\":\"1b94c\","-      <> " \"n\":\"vrjOfz9Ccdgx5nQudyhdoR17V-IubWMeOZCwX_jj0hgAsz2J_pqYW08"-      <> "PLbK_PdiVGKPrqzmDIsLI7sA25VEnHU1uCLNwBuUiCO11_-7dYbsr4iJmG0Q"-      <> "u2j8DsVyT1azpJC_NG84Ty5KKthuCaPod7iI7w0LK9orSMhBEwwZDCxTWq4a"-      <> "YWAchc8t-emd9qOvWtVMDC2BXksRngh6X5bUYLy6AyHKvj-nUy1wgzjYQDwH"-      <> "MTplCoLtU-o-8SNnZ1tmRoGE9uJkBLdh5gFENabWnU5m1ZqZPdwS-qo-meMv"-      <> "VfJb6jJVWRpl2SUtCnYG2C32qvbWbjZ_jBPD5eunqsIo1vQ\","-      <> " \"e\":\"AQAB\","-      <> " \"x5c\":"-      <> "  [\"MIIDQjCCAiqgAwIBAgIGATz/FuLiMA0GCSqGSIb3DQEBBQUAMGIxCzAJB"+jwkAppendixBSpec = describe "JWK B.  Example Use of \"x5c\" (X.509 Certificate Chain) Parameter" $ do+  let+    appendixBExampleX5c = ""+      <> "[\"MIIDQjCCAiqgAwIBAgIGATz/FuLiMA0GCSqGSIb3DQEBBQUAMGIxCzAJB"       <> "gNVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYD"       <> "VQQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1"       <> "wYmVsbDAeFw0xMzAyMjEyMzI5MTVaFw0xODA4MTQyMjI5MTVaMGIxCzAJBg"@@ -214,7 +201,48 @@       <> "2Bo3UPGrpsHzUoaGpDftmWssZkhpBJKVMJyf/RuP2SmmaIzmnw9JiSlYhzo"       <> "4tpzd5rFXhjRbg4zW9C+2qok+2+qDM1iJ684gPHMIY8aLWrdgQTxkumGmTq"       <> "gawR+N5MDtdPTEQ0XfIBc2cJEUyMTY5MPvACWpkA6SdS4xSvdXK3IVfOWA==\"]"-      <> "}"+    exampleKeyCommon = ""+      <> "{\"kty\":\"RSA\","+      <> " \"use\":\"sig\","+      <> " \"kid\":\"1b94c\","+      <> " \"n\":\"vrjOfz9Ccdgx5nQudyhdoR17V-IubWMeOZCwX_jj0hgAsz2J_pqYW08"+      <> "PLbK_PdiVGKPrqzmDIsLI7sA25VEnHU1uCLNwBuUiCO11_-7dYbsr4iJmG0Q"+      <> "u2j8DsVyT1azpJC_NG84Ty5KKthuCaPod7iI7w0LK9orSMhBEwwZDCxTWq4a"+      <> "YWAchc8t-emd9qOvWtVMDC2BXksRngh6X5bUYLy6AyHKvj-nUy1wgzjYQDwH"+      <> "MTplCoLtU-o-8SNnZ1tmRoGE9uJkBLdh5gFENabWnU5m1ZqZPdwS-qo-meMv"+      <> "VfJb6jJVWRpl2SUtCnYG2C32qvbWbjZ_jBPD5eunqsIo1vQ\","+      <> " \"e\":\"AQAB\""+    Just exampleJWKWithX5c = decode $ exampleKeyCommon <> ",\"x5c\":" <> appendixBExampleX5c <> "}"+    Just exampleJWKWithoutX5c = decode $ exampleKeyCommon <> "}"+    -- Note: this key is bogus: the "d" param does not correspond to the "n"+    -- of the public key.  This is not what we're testing, but if a "n"/"d"+    -- sanity check gets implemented in future this test will need updating+    Just examplePrivateJWKWithoutX5c = decode $ exampleKeyCommon+      <> ",\"d\":\"X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9"+      <> "M7dx5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqij"+      <> "wp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ46pRUohsXywbReAdYaMwFs9tv8d"+      <> "_cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBz"+      <> "nbJSzFHK66jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFz"+      <> "me1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q\"}"+    Just certs = (fmap . fmap) (\(Types.Base64X509 cert) -> cert) (decode appendixBExampleX5c)+    jwkWithMismatchedPubKeyAndX5c = ""+      <> "{\"kty\":\"RSA\","+      <> " \"n\":\"vrjOfz9Ccdgx5nQudyhdoR17V-IubWMeOZCwX_jj0hgAsz2J_pqYW08"+      <> "HACK_HACK_HACK_HACK_HACK_HACK_HACK_HACK_HACK_HACK_HACK_HACK_"+      <> "u2j8DsVyT1azpJC_NG84Ty5KKthuCaPod7iI7w0LK9orSMhBEwwZDCxTWq4a"+      <> "YWAchc8t-emd9qOvWtVMDC2BXksRngh6X5bUYLy6AyHKvj-nUy1wgzjYQDwH"+      <> "MTplCoLtU-o-8SNnZ1tmRoGE9uJkBLdh5gFENabWnU5m1ZqZPdwS-qo-meMv"+      <> "VfJb6jJVWRpl2SUtCnYG2C32qvbWbjZ_jBPD5eunqsIo1vQ\","+      <> " \"e\":\"AQAB\",\"x5c\":" <> appendixBExampleX5c <> "}"+  it "sets x5c in JWK with PUBLIC key when first cert matches key" $+    setJWKX5c (Just certs) exampleJWKWithoutX5c `shouldBe` Just exampleJWKWithX5c+  it "sets x5c in JWK with PRIVATE key when first cert matches key" $+    (setJWKX5c (Just certs) examplePrivateJWKWithoutX5c >>= view asPublicKey)+    `shouldBe` Just exampleJWKWithX5c+  it "unsets x5c in JWK when given x5c = Nothing" $+    setJWKX5c Nothing exampleJWKWithX5c `shouldBe` Just exampleJWKWithoutX5c+  it "rejects (parse error) keys with x5c that does not match public key" $+    (eitherDecode jwkWithMismatchedPubKeyAndX5c :: Either String JWK) `shouldSatisfy` is _Left  jwkAppendixC1Spec :: Spec jwkAppendixC1Spec = describe "RFC 7517  C.1. Plaintext RSA Private Key" $@@ -271,7 +299,7 @@     it "corresponds to A.1. private key" $ Right True == do       sk <- _A1_result       pk <- _A2_result-      pure $ maybe False (== pk) (view asPublicKey sk)+      pure $ view asPublicKey sk == Just pk  rfc8037_A1_jwkJson = ""   <> "{\"kty\":\"OKP\",\"crv\":\"Ed25519\","
test/JWS.hs view
@@ -72,10 +72,10 @@   , _acmeNonce :: Types.Base64Octets   } deriving (Show) acmeJwsHeader :: Lens' (ACMEHeader p) (JWSHeader p)-acmeJwsHeader f s@(ACMEHeader { _acmeJwsHeader = a}) =+acmeJwsHeader f s@ACMEHeader{ _acmeJwsHeader = a} =   fmap (\a' -> s { _acmeJwsHeader = a'}) (f a) acmeNonce :: Lens' (ACMEHeader p) Types.Base64Octets-acmeNonce f s@(ACMEHeader { _acmeNonce = a}) =+acmeNonce f s@ACMEHeader{ _acmeNonce = a} =   fmap (\a' -> s { _acmeNonce = a'}) (f a) instance HasJWSHeader ACMEHeader where   jwsHeader = acmeJwsHeader@@ -386,27 +386,24 @@     jws ^? _Right . dropping 1 signatures . header `shouldBe` Just h2'     jws ^? _Right . dropping 1 signatures . signature `shouldBe` Just mac2 -  it "decodes single-sig Generalised JWS correctly" $ do-    let jws = eitherDecode exampleJWSOneSig :: Either String (GeneralJWS JWSHeader)-    lengthOf (_Right . signatures) jws `shouldBe` 1-    jws ^? _Right . signatures . header `shouldBe` Just h2'-    jws ^? _Right . signatures . signature `shouldBe` Just mac2+  let+    decodeChecks jws = do+      lengthOf (_Right . signatures) jws `shouldBe` 1+      jws ^? _Right . signatures . header `shouldBe` Just h2'+      jws ^? _Right . signatures . signature `shouldBe` Just mac2 -  it "fails to decode single-sig Generalised JWS to 'JWS Identity'" $ do+  it "decodes single-sig Generalised JWS correctly" $+    decodeChecks (eitherDecode exampleJWSOneSig :: Either String (GeneralJWS JWSHeader))++  it "fails to decode single-sig Generalised JWS to 'JWS Identity'" $     (eitherDecode exampleJWSOneSig :: Either String (FlattenedJWS JWSHeader))       `shouldSatisfy` is _Left -  it "decodes flattened JWS to 'JWS []' correctly" $ do-    let jws = eitherDecode exampleJWSFlat :: Either String (GeneralJWS JWSHeader)-    lengthOf (_Right . signatures) jws `shouldBe` 1-    jws ^? _Right . signatures . header `shouldBe` Just h2'-    jws ^? _Right . signatures . signature `shouldBe` Just mac2+  it "decodes flattened JWS to 'JWS []' correctly" $+    decodeChecks (eitherDecode exampleJWSFlat :: Either String (GeneralJWS JWSHeader)) -  it "decodes flattened JWS to 'JWS Identity' correctly" $ do-    let jws = eitherDecode exampleJWSFlat :: Either String (FlattenedJWS JWSHeader)-    lengthOf (_Right . signatures) jws `shouldBe` 1-    jws ^? _Right . signatures . header `shouldBe` Just h2'-    jws ^? _Right . signatures . signature `shouldBe` Just mac2+  it "decodes flattened JWS to 'JWS Identity' correctly" $+    decodeChecks (eitherDecode exampleJWSFlat :: Either String (FlattenedJWS JWSHeader))    it "fails to decode flattened JWS when \"signatures\" key is present" $ do     (eitherDecode exampleFlatJWSWithSignatures :: Either String (GeneralJWS JWSHeader))
test/JWT.hs view
@@ -282,12 +282,12 @@       k = fromJust $ decode "{\"kty\":\"oct\",\"k\":\"\"}" :: JWK      describe "when the current time is prior to the Expiration Time" $-      it "can be decoded and validated" $ do+      it "can be decoded and validated" $         runReaderT (jwt >>= verifyClaims conf k) (utcTime "2010-01-01 00:00:00")           `shouldBe` (Right exampleClaimsSet :: Either JWTError ClaimsSet)      describe "when the current time is after the Expiration Time" $-      it "can be decoded, but not validated" $ do+      it "can be decoded, but not validated" $         runReaderT (jwt >>= verifyClaims conf k) (utcTime "2012-01-01 00:00:00")           `shouldBe` Left JWTExpired