]> git.immae.eu Git - github/fretlink/hmacaroons.git/blame - src/Crypto/Macaroon/Verifier/Internal.hs
Dedicated VerifierResult
[github/fretlink/hmacaroons.git] / src / Crypto / Macaroon / Verifier / Internal.hs
CommitLineData
86f38823
JT
1{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE RankNTypes #-}
7f9f7386
JT
3{-|
4Module : Crypto.Macaroon.Verifier.Internal
5Copyright : (c) 2015 Julien Tanguy
6License : BSD3
7
8Maintainer : julien.tanguy@jhome.fr
9Stability : experimental
10Portability : portable
11
12
13
14-}
15module Crypto.Macaroon.Verifier.Internal where
16
1fcdeab5 17import Control.Applicative
7f9f7386
JT
18import Control.Monad
19import Control.Monad.IO.Class
20import Crypto.Hash
21import Data.Bool
22import Data.Byteable
86f38823 23import qualified Data.ByteString as BS
7f9f7386
JT
24import Data.Either
25import Data.Either.Validation
26import Data.Foldable
27import Data.Maybe
86f38823 28import Data.Monoid
7f9f7386
JT
29
30import Crypto.Macaroon.Internal
31
be278da9
JT
32
33-- | Type representing the result of a validator
34data VerifierResult = Verified -- ^ The caveat is correctly parsed and verified
35 | Refused ValidationError -- ^ The caveat is refused (Either a parse error or a validation error
36 | Unrelated -- ^ The given verifier does not verify the caveat
37 deriving (Show, Eq)
38
86f38823 39-- | Type representing different validation errors.
27d5a3a4
JT
40-- Only 'ParseError' and 'ValidatorError' are exported, @SigMismatch@ and
41-- @NoVerifier@ are used internally and should not be used by the user
86f38823
JT
42data ValidationError = SigMismatch -- ^ Signatures do not match
43 | NoVerifier -- ^ No verifier can handle a given caveat
44 | ParseError String -- ^ A verifier had a parse error
45 | ValidatorError String -- ^ A verifier failed
46 deriving (Show,Eq)
7f9f7386 47
27d5a3a4
JT
48-- | The 'Monoid' instance is written so @SigMismatch@ is an annihilator,
49-- and @NoVerifier@ is the identity element
7f9f7386
JT
50instance Monoid ValidationError where
51 mempty = NoVerifier
52 NoVerifier `mappend` e = e
53 e `mappend` NoVerifier = e
54 SigMismatch `mappend` _ = SigMismatch
55 _ `mappend` SigMismatch = SigMismatch
56 (ValidatorError e) `mappend` (ParseError _) = ValidatorError e
57 (ParseError _) `mappend` (ValidatorError e) = ValidatorError e
58
bf31e290 59-- | Check that the given macaroon has a correct signature
7f9f7386
JT
60verifySig :: Key -> Macaroon -> Either ValidationError Macaroon
61verifySig k m = bool (Left SigMismatch) (Right m) $
62 signature m == foldl' hash (toBytes (hmac derivedKey (identifier m) :: HMAC SHA256)) (caveats m)
63 where
64 hash s c = toBytes (hmac s (vid c `BS.append` cid c) :: HMAC SHA256)
65 derivedKey = toBytes (hmac "macaroons-key-generator" k :: HMAC SHA256)
66
86f38823 67-- | Given a list of verifiers, verify each caveat of the given macaroon
a11f20be 68verifyCavs :: (Functor m, MonadIO m)
be278da9 69 => [Caveat -> m VerifierResult]
7f9f7386
JT
70 -> Macaroon
71 -> m (Either ValidationError Macaroon)
72verifyCavs verifiers m = gatherEithers <$> mapM validateCaveat (caveats m)
73 where
74 {-
75 - validateCaveat :: Caveat -> m (Validation String Caveat)
76 - We can use fromJust here safely since we use a `Just Failure` as a
77 - starting value for the foldM. We are guaranteed to have a `Just something`
78 - from it.
79 -}
be278da9
JT
80 validateCaveat c = fmap (const c) . fromJust <$> foldM (\res v -> mappend res . fmap eitherToValidation . vResult2MaybeEither <$> v c) (defErr c) verifiers
81 -- vResult2MaybeEither :: VerifierResult -> Maybe (Either ValidationError ())
82 vResult2MaybeEither Unrelated = Nothing
83 vResult2MaybeEither Verified = Just (Right ())
84 vResult2MaybeEither (Refused e)= Just (Left e)
7f9f7386
JT
85 -- defErr :: Caveat -> Maybe (Validation String Caveat)
86 defErr c = Just $ Failure NoVerifier
87 -- gatherEithers :: [Validation String Caveat] -> Either String Caveat
88 gatherEithers vs = case partitionEithers . map validationToEither $ vs of
89 ([],_) -> Right m
90 (errs,_) -> Left (mconcat errs)