]>
Commit | Line | Data |
---|---|---|
86f38823 JT |
1 | {-# LANGUAGE OverloadedStrings #-} |
2 | {-# LANGUAGE RankNTypes #-} | |
7f9f7386 JT |
3 | {-| |
4 | Module : Crypto.Macaroon.Verifier.Internal | |
5 | Copyright : (c) 2015 Julien Tanguy | |
6 | License : BSD3 | |
7 | ||
8 | Maintainer : julien.tanguy@jhome.fr | |
9 | Stability : experimental | |
10 | Portability : portable | |
11 | ||
12 | ||
13 | ||
14 | -} | |
15 | module Crypto.Macaroon.Verifier.Internal where | |
16 | ||
1fcdeab5 | 17 | import Control.Applicative |
7f9f7386 JT |
18 | import Control.Monad |
19 | import Control.Monad.IO.Class | |
20 | import Crypto.Hash | |
21 | import Data.Bool | |
22 | import Data.Byteable | |
86f38823 | 23 | import qualified Data.ByteString as BS |
7f9f7386 JT |
24 | import Data.Either |
25 | import Data.Either.Validation | |
26 | import Data.Foldable | |
27 | import Data.Maybe | |
86f38823 | 28 | import Data.Monoid |
7f9f7386 JT |
29 | |
30 | import Crypto.Macaroon.Internal | |
31 | ||
be278da9 JT |
32 | |
33 | -- | Type representing the result of a validator | |
34 | data 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 |
42 | data 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 |
50 | instance 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 |
60 | verifySig :: Key -> Macaroon -> Either ValidationError Macaroon |
61 | verifySig 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 | 68 | verifyCavs :: (Functor m, MonadIO m) |
be278da9 | 69 | => [Caveat -> m VerifierResult] |
7f9f7386 JT |
70 | -> Macaroon |
71 | -> m (Either ValidationError Macaroon) | |
72 | verifyCavs 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) |