]>
Commit | Line | Data |
---|---|---|
b92e3c15 | 1 | {-# LANGUAGE OverloadedStrings #-} |
6f3c0dca | 2 | {-# LANGUAGE RankNTypes #-} |
b92e3c15 JT |
3 | {-| |
4 | Module : Crypto.Macaroon.Verifier | |
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 | -} | |
6f3c0dca JT |
15 | module Crypto.Macaroon.Verifier ( |
16 | Verified(..) | |
62576139 | 17 | , CaveatVerifier |
90695615 | 18 | , (<???>) |
62576139 | 19 | , verifyMacaroon |
6f3c0dca JT |
20 | , verifySig |
21 | , verifyExact | |
857f2f3b | 22 | , verifyFun |
6f3c0dca | 23 | , module Data.Attoparsec.ByteString.Char8 |
62576139 | 24 | , verifyCavs |
6f3c0dca | 25 | ) where |
b92e3c15 JT |
26 | |
27 | ||
28 | import Crypto.Hash | |
29 | import Data.Bool | |
30 | import qualified Data.ByteString as BS | |
31 | import Data.Byteable | |
32 | import Data.Foldable | |
90695615 | 33 | import Data.Function |
6f3c0dca | 34 | import Data.Maybe |
90695615 | 35 | import Data.Traversable |
6f3c0dca JT |
36 | import Data.Attoparsec.ByteString |
37 | import Data.Attoparsec.ByteString.Char8 | |
b92e3c15 JT |
38 | |
39 | import Crypto.Macaroon.Internal | |
40 | ||
41 | ||
42 | -- | Opaque datatype for now. Might need more explicit errors | |
6f3c0dca | 43 | data Verified = Ok | Failed deriving (Show,Eq) |
b92e3c15 | 44 | |
6f3c0dca JT |
45 | instance Monoid Verified where |
46 | mempty = Ok | |
47 | mappend Ok Ok = Ok | |
48 | mappend _ _ = Failed | |
49 | ||
50 | ||
90695615 JT |
51 | data CaveatVerifier = CV { vFun :: Caveat -> Maybe Verified , helpText :: String} |
52 | ||
53 | instance Eq CaveatVerifier where | |
54 | (==) = (==) `on` helpText | |
55 | ||
56 | instance Show CaveatVerifier where | |
57 | show = helpText | |
58 | ||
59 | (<???>) :: (Caveat -> Maybe Verified) -> String -> CaveatVerifier | |
60 | f <???> t = CV f t | |
6f3c0dca JT |
61 | |
62 | verifySig :: Key -> Macaroon -> Verified | |
63 | verifySig k m = bool Failed Ok $ | |
b92e3c15 JT |
64 | signature m == foldl' hash (toBytes (hmac derivedKey (identifier m) :: HMAC SHA256)) (caveats m) |
65 | where | |
66 | hash s c = toBytes (hmac s (vid c `BS.append` cid c) :: HMAC SHA256) | |
67 | derivedKey = toBytes (hmac "macaroons-key-generator" k :: HMAC SHA256) | |
6f3c0dca | 68 | |
62576139 JT |
69 | verifyMacaroon :: Key -> [CaveatVerifier] -> Macaroon -> Verified |
70 | verifyMacaroon secret verifiers m = verifySig secret m `mappend` verifyCavs verifiers m | |
71 | ||
72 | ||
90695615 JT |
73 | verifyCavs :: [CaveatVerifier] -> Macaroon -> Verified |
74 | verifyCavs verifiers m = foldMap (\c -> fromMaybe Failed $ foldMap (($ c) . vFun) verifiers) (caveats m) | |
6f3c0dca | 75 | |
857f2f3b JT |
76 | verifyExact :: (Eq a) => Key -> a -> Parser a -> Caveat -> Maybe Verified |
77 | verifyExact k expected = verifyFun k (expected ==) | |
78 | ||
79 | verifyFun :: Key -> (a -> Bool) -> Parser a -> Caveat -> Maybe Verified | |
80 | verifyFun key f parser cav = if key `BS.isPrefixOf` cid cav then | |
6f3c0dca | 81 | case parseOnly kvparser (cid cav) of |
857f2f3b | 82 | Right v -> (bool Failed Ok . f) <$> Just v |
6f3c0dca JT |
83 | Left _ -> Just Failed |
84 | else Nothing | |
85 | where | |
86 | kvparser = do | |
87 | key <- string key | |
88 | skipSpace | |
89 | string "=" | |
90 | skipSpace | |
857f2f3b | 91 | parser <* endOfInput |