aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/Crypto/Macaroon/Internal.hs
blob: d6e80d3700d4e416858021b987b4bf72c00c1be4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
{-# LANGUAGE OverloadedStrings #-}
{-|
Module      : Crypto.Macaroon.Internal
Copyright   : (c) 2015 Julien Tanguy
License     : BSD3

Maintainer  : julien.tanguy@jhome.fr
Stability   : experimental
Portability : portable


Internal representation of a macaroon
-}
module Crypto.Macaroon.Internal where


import           Control.DeepSeq
import           Crypto.Hash
import           Data.Byteable
import qualified Data.ByteString        as BS
import qualified Data.ByteString.Base64 as B64
import qualified Data.ByteString.Char8  as B8
import           Data.Hex
import           Data.List


-- |Type alias for Macaroons secret keys
type Secret = BS.ByteString

-- |Type alias for Macaroons and Caveat and identifiers
type Key = BS.ByteString

-- |Type alias for Macaroons and Caveat locations
type Location = BS.ByteString

-- |Type alias for Macaroons signatures
type Sig = BS.ByteString

-- | Main structure of a macaroon
data Macaroon = MkMacaroon { location   :: Location
                           -- ^ Target location
                           , identifier :: Key
                           -- ^ Macaroon Identifier
                           , caveats    :: [Caveat]
                           -- ^ List of caveats
                           , signature  :: Sig
                           -- ^ Macaroon HMAC signature
                           }

-- | Constant-time Eq instance
instance Eq Macaroon where
    (MkMacaroon l1 i1 c1 s1) == (MkMacaroon l2 i2 c2 s2) =
        (l1 `constEqBytes` l2) &&!
        (i1 `constEqBytes` i2) &&!
        (c1 == c2) &&!
        (s1 `constEqBytes` s2)


-- | show instance conforming to the @inspect@ "specification"
instance Show Macaroon where
    -- We use intercalate because unlines would add a trailing newline
    show (MkMacaroon l i c s) = intercalate "\n" [
                      "location " ++ B8.unpack l
                    , "identifier " ++ B8.unpack i
                    , intercalate "\n" (map show c)
                    , "signature " ++ B8.unpack (hex s)
                    ]

-- | NFData instance for use in the benchmark
instance NFData Macaroon where
    rnf (MkMacaroon loc ident cavs sig) = rnf loc `seq` rnf ident `seq` rnf cavs `seq` rnf sig


-- | Caveat structure
data Caveat = MkCaveat { cid :: Key
                       -- ^ Caveat identifier
                       , vid :: Key
                       -- ^ Caveat verification key identifier
                       , cl  :: Location
                       -- ^ Caveat target location
                       }

-- | Constant-time Eq instance
instance Eq Caveat where
    (MkCaveat c1 v1 l1) == (MkCaveat c2 v2 l2) =
        (c1 `constEqBytes` c2) &&!
        (v1 `constEqBytes` v2) &&!
        (l1 `constEqBytes` l2)

-- | show instance conforming to the @inspect@ "specification"
instance Show Caveat where
    show (MkCaveat c v l) | v == BS.empty = "cid " ++ B8.unpack c
                          | otherwise = unlines [ "cid " ++ B8.unpack c
                                                , "vid " ++ B8.unpack v
                                                , "cl " ++ B8.unpack l
                                                ]


-- | NFData instance for use in the benchmark
instance NFData Caveat where
    rnf (MkCaveat cid vid cl) = rnf cid `seq` rnf vid `seq` rnf cl

-- | Primitive to add a First or Third party caveat to a macaroon
-- For internal use only
addCaveat :: Location
          -> Key
          -> Key
          -> Macaroon
          -> Macaroon
addCaveat loc cid vid m = m { caveats = cavs ++ [cav'], signature = sig}
  where
    cavs = caveats m
    cav' = MkCaveat cid vid loc
    sig = toBytes (hmac (signature m) (BS.append vid cid) :: HMAC SHA256)

-- | Utility non-short circuiting '&&' function.
(&&!) :: Bool -> Bool -> Bool
True  &&! True  = True
True  &&! False = False
False &&! True  = False
False &&! False = False