{-# LANGUAGE OverloadedStrings #-}
module Jose.Jws
( jwkEncode
, hmacEncode
, hmacDecode
, rsaEncode
, rsaDecode
, ecDecode
, ed25519Encode
, ed25519Decode
, ed448Encode
, ed448Decode
)
where
import qualified Crypto.PubKey.ECC.ECDSA as ECDSA
import qualified Crypto.PubKey.Ed25519 as Ed25519
import qualified Crypto.PubKey.Ed448 as Ed448
import Crypto.PubKey.RSA (PrivateKey(..), PublicKey(..), generateBlinder)
import Crypto.Random (MonadRandom)
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import Jose.Types
import qualified Jose.Internal.Base64 as B64
import Jose.Internal.Crypto
import qualified Jose.Internal.Parser as P
import Jose.Jwa
import Jose.Jwk (Jwk (..))
jwkEncode :: MonadRandom m
=> JwsAlg
-> Jwk
-> Payload
-> m (Either JwtError Jwt)
jwkEncode :: forall (m :: * -> *).
MonadRandom m =>
JwsAlg -> Jwk -> Payload -> m (Either JwtError Jwt)
jwkEncode JwsAlg
a Jwk
key Payload
payload = case Jwk
key of
RsaPrivateJwk PrivateKey
kPr Maybe KeyId
kid Maybe KeyUse
_ Maybe Alg
_ -> forall (m :: * -> *).
MonadRandom m =>
JwsAlg -> PrivateKey -> ByteString -> m (Either JwtError Jwt)
rsaEncodeInternal JwsAlg
a PrivateKey
kPr (JwsAlg -> Maybe KeyId -> Payload -> ByteString
sigTarget JwsAlg
a Maybe KeyId
kid Payload
payload)
SymmetricJwk ByteString
k Maybe KeyId
kid Maybe KeyUse
_ Maybe Alg
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ JwsAlg -> ByteString -> ByteString -> Either JwtError Jwt
hmacEncodeInternal JwsAlg
a ByteString
k (JwsAlg -> Maybe KeyId -> Payload -> ByteString
sigTarget JwsAlg
a Maybe KeyId
kid Payload
payload)
Ed25519PrivateJwk SecretKey
kPr PublicKey
kPub Maybe KeyId
kid -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$
case JwsAlg
a of
JwsAlg
EdDSA -> forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$ SecretKey -> PublicKey -> ByteString -> Jwt
ed25519EncodeInternal SecretKey
kPr PublicKey
kPub (JwsAlg -> Maybe KeyId -> Payload -> ByteString
sigTarget JwsAlg
EdDSA Maybe KeyId
kid Payload
payload)
JwsAlg
_ -> forall a b. a -> Either a b
Left (Text -> JwtError
KeyError Text
"Algorithm cannot be used with an Ed25519 key")
Ed448PrivateJwk SecretKey
kPr PublicKey
kPub Maybe KeyId
kid -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$
case JwsAlg
a of
JwsAlg
EdDSA -> forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$ SecretKey -> PublicKey -> ByteString -> Jwt
ed448EncodeInternal SecretKey
kPr PublicKey
kPub (JwsAlg -> Maybe KeyId -> Payload -> ByteString
sigTarget JwsAlg
EdDSA Maybe KeyId
kid Payload
payload)
JwsAlg
_ -> forall a b. a -> Either a b
Left (Text -> JwtError
KeyError Text
"Algorithm cannot be used with an Ed448 key")
Jwk
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ Text -> JwtError
BadAlgorithm Text
"EC signing is not supported"
hmacEncode :: JwsAlg
-> ByteString
-> ByteString
-> Either JwtError Jwt
hmacEncode :: JwsAlg -> ByteString -> ByteString -> Either JwtError Jwt
hmacEncode JwsAlg
a ByteString
key ByteString
payload = JwsAlg -> ByteString -> ByteString -> Either JwtError Jwt
hmacEncodeInternal JwsAlg
a ByteString
key (JwsAlg -> Maybe KeyId -> Payload -> ByteString
sigTarget JwsAlg
a forall a. Maybe a
Nothing (ByteString -> Payload
Claims ByteString
payload))
hmacEncodeInternal :: JwsAlg
-> ByteString
-> ByteString
-> Either JwtError Jwt
hmacEncodeInternal :: JwsAlg -> ByteString -> ByteString -> Either JwtError Jwt
hmacEncodeInternal JwsAlg
a ByteString
key ByteString
st = ByteString -> Jwt
Jwt forall b c a. (b -> c) -> (a -> b) -> a -> c
. (\ByteString
mac -> [ByteString] -> ByteString
B.concat [ByteString
st, ByteString
".", forall input output.
(ByteArrayAccess input, ByteArray output) =>
input -> output
B64.encode ByteString
mac]) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> JwsAlg -> ByteString -> ByteString -> Either JwtError ByteString
hmacSign JwsAlg
a ByteString
key ByteString
st
hmacDecode :: ByteString
-> ByteString
-> Either JwtError Jws
hmacDecode :: ByteString -> ByteString -> Either JwtError Jws
hmacDecode ByteString
key = JwsVerifier -> ByteString -> Either JwtError Jws
decode (JwsAlg -> ByteString -> ByteString -> ByteString -> Bool
`hmacVerify` ByteString
key)
rsaEncode :: MonadRandom m
=> JwsAlg
-> PrivateKey
-> ByteString
-> m (Either JwtError Jwt)
rsaEncode :: forall (m :: * -> *).
MonadRandom m =>
JwsAlg -> PrivateKey -> ByteString -> m (Either JwtError Jwt)
rsaEncode JwsAlg
a PrivateKey
pk ByteString
payload = forall (m :: * -> *).
MonadRandom m =>
JwsAlg -> PrivateKey -> ByteString -> m (Either JwtError Jwt)
rsaEncodeInternal JwsAlg
a PrivateKey
pk (JwsAlg -> Maybe KeyId -> Payload -> ByteString
sigTarget JwsAlg
a forall a. Maybe a
Nothing (ByteString -> Payload
Claims ByteString
payload))
rsaEncodeInternal :: MonadRandom m
=> JwsAlg
-> PrivateKey
-> ByteString
-> m (Either JwtError Jwt)
rsaEncodeInternal :: forall (m :: * -> *).
MonadRandom m =>
JwsAlg -> PrivateKey -> ByteString -> m (Either JwtError Jwt)
rsaEncodeInternal JwsAlg
a PrivateKey
pk ByteString
st = do
Blinder
blinder <- forall (m :: * -> *). MonadRandom m => Integer -> m Blinder
generateBlinder (PublicKey -> Integer
public_n forall a b. (a -> b) -> a -> b
$ PrivateKey -> PublicKey
private_pub PrivateKey
pk)
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Blinder -> Either JwtError Jwt
sign Blinder
blinder
where
sign :: Blinder -> Either JwtError Jwt
sign Blinder
b = case Maybe Blinder
-> JwsAlg -> PrivateKey -> ByteString -> Either JwtError ByteString
rsaSign (forall a. a -> Maybe a
Just Blinder
b) JwsAlg
a PrivateKey
pk ByteString
st of
Right ByteString
sig -> forall a b. b -> Either a b
Right forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Jwt
Jwt forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
B.concat [ByteString
st, ByteString
".", forall input output.
(ByteArrayAccess input, ByteArray output) =>
input -> output
B64.encode ByteString
sig]
Left JwtError
e -> forall a b. a -> Either a b
Left JwtError
e
ed25519Decode :: Ed25519.PublicKey
-> ByteString
-> Either JwtError Jws
ed25519Decode :: PublicKey -> ByteString -> Either JwtError Jws
ed25519Decode PublicKey
key = JwsVerifier -> ByteString -> Either JwtError Jws
decode (JwsAlg -> PublicKey -> ByteString -> ByteString -> Bool
`ed25519Verify` PublicKey
key)
ed25519Encode :: Ed25519.SecretKey
-> Ed25519.PublicKey
-> ByteString
-> Jwt
ed25519Encode :: SecretKey -> PublicKey -> ByteString -> Jwt
ed25519Encode SecretKey
kPr PublicKey
kPub ByteString
payload =
SecretKey -> PublicKey -> ByteString -> Jwt
ed25519EncodeInternal SecretKey
kPr PublicKey
kPub (JwsAlg -> Maybe KeyId -> Payload -> ByteString
sigTarget JwsAlg
EdDSA forall a. Maybe a
Nothing (ByteString -> Payload
Claims ByteString
payload))
ed25519EncodeInternal :: Ed25519.SecretKey
-> Ed25519.PublicKey
-> ByteString
-> Jwt
ed25519EncodeInternal :: SecretKey -> PublicKey -> ByteString -> Jwt
ed25519EncodeInternal SecretKey
kPr PublicKey
kPub ByteString
signMe =
let
sig :: Signature
sig = forall ba.
ByteArrayAccess ba =>
SecretKey -> PublicKey -> ba -> Signature
Ed25519.sign SecretKey
kPr PublicKey
kPub ByteString
signMe
in
ByteString -> Jwt
Jwt ([ByteString] -> ByteString
B.concat [ByteString
signMe, ByteString
".", forall input output.
(ByteArrayAccess input, ByteArray output) =>
input -> output
B64.encode Signature
sig])
ed448Decode :: Ed448.PublicKey
-> ByteString
-> Either JwtError Jws
ed448Decode :: PublicKey -> ByteString -> Either JwtError Jws
ed448Decode PublicKey
key = JwsVerifier -> ByteString -> Either JwtError Jws
decode (JwsAlg -> PublicKey -> ByteString -> ByteString -> Bool
`ed448Verify` PublicKey
key)
ed448Encode :: Ed448.SecretKey
-> Ed448.PublicKey
-> ByteString
-> Jwt
ed448Encode :: SecretKey -> PublicKey -> ByteString -> Jwt
ed448Encode SecretKey
kPr PublicKey
kPub ByteString
payload =
SecretKey -> PublicKey -> ByteString -> Jwt
ed448EncodeInternal SecretKey
kPr PublicKey
kPub (JwsAlg -> Maybe KeyId -> Payload -> ByteString
sigTarget JwsAlg
EdDSA forall a. Maybe a
Nothing (ByteString -> Payload
Claims ByteString
payload))
ed448EncodeInternal :: Ed448.SecretKey
-> Ed448.PublicKey
-> ByteString
-> Jwt
ed448EncodeInternal :: SecretKey -> PublicKey -> ByteString -> Jwt
ed448EncodeInternal SecretKey
kPr PublicKey
kPub ByteString
signMe =
let
sig :: Signature
sig = forall ba.
ByteArrayAccess ba =>
SecretKey -> PublicKey -> ba -> Signature
Ed448.sign SecretKey
kPr PublicKey
kPub ByteString
signMe
in
ByteString -> Jwt
Jwt ([ByteString] -> ByteString
B.concat [ByteString
signMe, ByteString
".", forall input output.
(ByteArrayAccess input, ByteArray output) =>
input -> output
B64.encode Signature
sig])
rsaDecode :: PublicKey
-> ByteString
-> Either JwtError Jws
rsaDecode :: PublicKey -> ByteString -> Either JwtError Jws
rsaDecode PublicKey
key = JwsVerifier -> ByteString -> Either JwtError Jws
decode (JwsAlg -> PublicKey -> ByteString -> ByteString -> Bool
`rsaVerify` PublicKey
key)
ecDecode :: ECDSA.PublicKey
-> ByteString
-> Either JwtError Jws
ecDecode :: PublicKey -> ByteString -> Either JwtError Jws
ecDecode PublicKey
key = JwsVerifier -> ByteString -> Either JwtError Jws
decode (JwsAlg -> PublicKey -> ByteString -> ByteString -> Bool
`ecVerify` PublicKey
key)
sigTarget :: JwsAlg -> Maybe KeyId -> Payload -> ByteString
sigTarget :: JwsAlg -> Maybe KeyId -> Payload -> ByteString
sigTarget JwsAlg
a Maybe KeyId
kid Payload
payload = ByteString -> [ByteString] -> ByteString
B.intercalate ByteString
"." forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map forall input output.
(ByteArrayAccess input, ByteArray output) =>
input -> output
B64.encode [forall a. ToJSON a => a -> ByteString
encodeHeader JwsHeader
hdr, ByteString
bytes]
where
hdr :: JwsHeader
hdr = JwsHeader
defJwsHdr {jwsAlg :: JwsAlg
jwsAlg = JwsAlg
a, jwsKid :: Maybe KeyId
jwsKid = Maybe KeyId
kid, jwsCty :: Maybe Text
jwsCty = Maybe Text
contentType}
(Maybe Text
contentType, ByteString
bytes) = case Payload
payload of
Claims ByteString
c -> (forall a. Maybe a
Nothing, ByteString
c)
Nested (Jwt ByteString
b) -> (forall a. a -> Maybe a
Just Text
"JWT", ByteString
b)
type JwsVerifier = JwsAlg -> ByteString -> ByteString -> Bool
decode :: JwsVerifier -> ByteString -> Either JwtError Jws
decode :: JwsVerifier -> ByteString -> Either JwtError Jws
decode JwsVerifier
verify ByteString
jwt = do
DecodableJwt
decodableJwt <- ByteString -> Either JwtError DecodableJwt
P.parseJwt ByteString
jwt
case DecodableJwt
decodableJwt of
P.DecodableJws JwsHeader
hdr (P.Payload ByteString
p) (P.Sig ByteString
sig) (P.SigTarget ByteString
signed) ->
if JwsVerifier
verify (JwsHeader -> JwsAlg
jwsAlg JwsHeader
hdr) ByteString
signed ByteString
sig
then forall a b. b -> Either a b
Right (JwsHeader
hdr, ByteString
p)
else forall a b. a -> Either a b
Left JwtError
BadSignature
DecodableJwt
_ -> forall a b. a -> Either a b
Left (Text -> JwtError
BadHeader Text
"JWT is not a JWS")