aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/Crypto/Macaroon/Verifier.hs
diff options
context:
space:
mode:
authorJulien Tanguy <julien.tanguy@jhome.fr>2015-08-17 19:40:19 +0200
committerJulien Tanguy <julien.tanguy@jhome.fr>2015-08-17 19:40:19 +0200
commitcfeb65a103cb58048328b2ca3ce74351017f70d1 (patch)
tree8a96cc66aba8d8171045c0e0a6dcdd040b7bc588 /src/Crypto/Macaroon/Verifier.hs
parenta1b6481db1e02013f668851096b084ff6088f682 (diff)
parent27d5a3a43c7d736f8cd842f14f3178d532de9152 (diff)
downloadhmacaroons-cfeb65a103cb58048328b2ca3ce74351017f70d1.tar.gz
hmacaroons-cfeb65a103cb58048328b2ca3ce74351017f70d1.tar.zst
hmacaroons-cfeb65a103cb58048328b2ca3ce74351017f70d1.zip
Merge branch 'verification'
Diffstat (limited to 'src/Crypto/Macaroon/Verifier.hs')
-rw-r--r--src/Crypto/Macaroon/Verifier.hs142
1 files changed, 71 insertions, 71 deletions
diff --git a/src/Crypto/Macaroon/Verifier.hs b/src/Crypto/Macaroon/Verifier.hs
index ed24ea4..4fc6aff 100644
--- a/src/Crypto/Macaroon/Verifier.hs
+++ b/src/Crypto/Macaroon/Verifier.hs
@@ -1,5 +1,8 @@
1{-# LANGUAGE OverloadedStrings #-} 1{-# LANGUAGE FlexibleInstances #-}
2{-# LANGUAGE RankNTypes #-} 2{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE RankNTypes #-}
4{-# LANGUAGE TypeSynonymInstances #-}
5{-# LANGUAGE UndecidableInstances #-}
3{-| 6{-|
4Module : Crypto.Macaroon.Verifier 7Module : Crypto.Macaroon.Verifier
5Copyright : (c) 2015 Julien Tanguy 8Copyright : (c) 2015 Julien Tanguy
@@ -13,80 +16,77 @@ Portability : portable
13 16
14-} 17-}
15module Crypto.Macaroon.Verifier ( 18module Crypto.Macaroon.Verifier (
16 Verified(..) 19 verify
17 , CaveatVerifier 20 , ValidationError(ValidatorError, ParseError)
18 , (<???>) 21 -- , (.<), (.<=), (.==), (.>), (.>=)
19 , verifyMacaroon 22 -- , module Data.Attoparsec.ByteString.Char8
20 , verifySig
21 , verifyExact
22 , verifyFun
23 , module Data.Attoparsec.ByteString.Char8
24 , verifyCavs
25) where 23) where
26 24
27 25
28import Crypto.Hash 26import Control.Applicative
27import Control.Monad hiding (forM)
28import Control.Monad.IO.Class
29import Data.Attoparsec.ByteString
30import Data.Attoparsec.ByteString.Char8
29import Data.Bool 31import Data.Bool
30import qualified Data.ByteString as BS
31import Data.Byteable
32import Data.Foldable
33import Data.Function
34import Data.Maybe
35import Data.Monoid
36import Data.Traversable 32import Data.Traversable
37import Data.Attoparsec.ByteString 33import qualified Data.ByteString as BS
38import Data.Attoparsec.ByteString.Char8 34import Data.Either.Combinators
39 35
40import Crypto.Macaroon.Internal 36import Crypto.Macaroon.Internal
37import Crypto.Macaroon.Verifier.Internal
38
39
40
41
42-- (.<) :: (MonadIO m, Ord a, Parsable a) => Key -> m a -> Caveat -> m (Maybe (Either ValidationError Caveat))
43-- (.<) = verifyOpBool "Greater or equal" (<) "<"
44
45-- (.<=) :: (MonadIO m, Ord a, Parsable a) => Key -> m a -> Caveat -> m (Maybe (Either ValidationError Caveat))
46-- (.<=) = verifyOpBool "Strictly greater" (<=) "<="
47
48-- (.==) :: (MonadIO m, Eq a, Parsable a) => Key -> m a -> Caveat -> m (Maybe (Either ValidationError Caveat))
49-- (.==) = verifyOpBool "Not equal" (==) "="
50
51-- (.>) :: (MonadIO m, Ord a, Parsable a) => Key -> m a -> Caveat -> m (Maybe (Either ValidationError Caveat))
52-- (.>) = verifyOpBool "Less or equal" (>) ">"
53
54-- (.>=) :: (MonadIO m, Ord a, Parsable a) => Key -> m a -> Caveat -> m (Maybe (Either ValidationError Caveat))
55-- (.>=) = verifyOpBool "Strictly less" (>=) ">="
56
57-- | Verify a Macaroon's signature and caveats, given the corresponding Secret
58-- and verifiers.
59--
60-- A verifier is a function of type
61-- @'MonadIO' m => 'Caveat' -> m ('Maybe' ('Either' 'ValidatorError' 'Caveat'))@.
62--
63-- It should return:
64--
65-- * 'Nothing' if the caveat is not related to the verifier
66-- (for instance a time verifier is given an action caveat);
67-- * 'Just' ('Left' ('ParseError' reason)) if the verifier is related to the
68-- caveat, but failed to parse it completely;
69-- * 'Just' ('Left' ('ValidatorError' reason)) if the verifier is related to the
70-- caveat, parsed it and invalidated it;
71-- * 'Just' ('Right' '()') if the verifier has successfully verified the
72-- given caveat
73verify :: (Functor m, MonadIO m) => Secret -> [Caveat -> m (Maybe (Either ValidationError ()))] -> Macaroon -> m (Either ValidationError Macaroon)
74verify secret verifiers m = join <$> forM (verifySig secret m) (verifyCavs verifiers)
75
76
77-- verifyOpBool :: MonadIO m => String -> Parser a -> (a -> a -> Bool) -> BS.ByteString -> Key -> m a -> Caveat -> m (Maybe (Either ValidationError Caveat))
78-- verifyOpBool err p f op k val = verifyParser k valueParser $ \s -> do
79-- expected <- val
80-- return $ bool (Left $ ValidatorError err) (Right Win) =<< f expected <$> mapLeft ParseError (parseOnly p s)
81-- where
82-- valueParser = string op *> skipSpace *> takeByteString
83
84-- verifyParser :: (MonadIO m) => Key -> Parser a -> (a -> m (Either ValidationError Win)) -> Caveat -> m (Maybe (Either ValidationError Caveat))
85-- verifyParser k p f c = case parseOnly keyParser . cid $ c of
86-- Left _ -> return Nothing
87-- Right bs -> Just <$> case parseOnly p bs of
88-- Left err -> return $ Left $ ParseError err
89-- Right a -> fmap (const c) <$> f a
90-- where
91-- keyParser = string k *> skipSpace *> takeByteString
41 92
42
43-- | Opaque datatype for now. Might need more explicit errors
44data Verified = Ok | Failed deriving (Show,Eq)
45
46instance Monoid Verified where
47 mempty = Ok
48 mappend Ok Ok = Ok
49 mappend _ _ = Failed
50
51
52data CaveatVerifier = CV { vFun :: Caveat -> Maybe Verified , helpText :: String}
53
54instance Eq CaveatVerifier where
55 (==) = (==) `on` helpText
56
57instance Show CaveatVerifier where
58 show = helpText
59
60(<???>) :: (Caveat -> Maybe Verified) -> String -> CaveatVerifier
61f <???> t = CV f t
62
63verifySig :: Key -> Macaroon -> Verified
64verifySig k m = bool Failed Ok $
65 signature m == foldl' hash (toBytes (hmac derivedKey (identifier m) :: HMAC SHA256)) (caveats m)
66 where
67 hash s c = toBytes (hmac s (vid c `BS.append` cid c) :: HMAC SHA256)
68 derivedKey = toBytes (hmac "macaroons-key-generator" k :: HMAC SHA256)
69
70verifyMacaroon :: Key -> [CaveatVerifier] -> Macaroon -> Verified
71verifyMacaroon secret verifiers m = verifySig secret m `mappend` verifyCavs verifiers m
72
73
74verifyCavs :: [CaveatVerifier] -> Macaroon -> Verified
75verifyCavs verifiers m = foldMap (\c -> fromMaybe Failed $ foldMap (($ c) . vFun) verifiers) (caveats m)
76
77verifyExact :: (Eq a) => Key -> a -> Parser a -> Caveat -> Maybe Verified
78verifyExact k expected = verifyFun k (expected ==)
79
80verifyFun :: Key -> (a -> Bool) -> Parser a -> Caveat -> Maybe Verified
81verifyFun key f parser cav = if key `BS.isPrefixOf` cid cav then
82 case parseOnly kvparser (cid cav) of
83 Right v -> (bool Failed Ok . f) <$> Just v
84 Left _ -> Just Failed
85 else Nothing
86 where
87 kvparser = do
88 key <- string key
89 skipSpace
90 string "="
91 skipSpace
92 parser <* endOfInput