28 |
28 |
|
29 |
29 |
module Ganeti.Confd.Utils
|
30 |
30 |
( getClusterHmac
|
31 |
|
, parseRequest
|
|
31 |
, parseSignedMessage
|
32 |
32 |
, parseMessage
|
33 |
33 |
, signMessage
|
34 |
34 |
, getCurrentTime
|
... | ... | |
54 |
54 |
getClusterHmac :: IO HashKey
|
55 |
55 |
getClusterHmac = Path.confdHmacKey >>= fmap B.unpack . B.readFile
|
56 |
56 |
|
57 |
|
-- | Parses a signed request.
|
58 |
|
parseRequest :: HashKey -> String -> Result (String, String, ConfdRequest)
|
59 |
|
parseRequest key str = do
|
60 |
|
(SignedMessage hmac msg salt) <- fromJResult "parsing request" $ J.decode str
|
61 |
|
req <- if verifyMac key (Just salt) msg hmac
|
|
57 |
-- | Parses a signed message.
|
|
58 |
parseSignedMessage :: (J.JSON a) => HashKey -> String
|
|
59 |
-> Result (String, String, a)
|
|
60 |
parseSignedMessage key str = do
|
|
61 |
(SignedMessage hmac msg salt) <- fromJResult "parsing signed message"
|
|
62 |
$ J.decode str
|
|
63 |
parsedMsg <- if verifyMac key (Just salt) msg hmac
|
62 |
64 |
then fromJResult "parsing message" $ J.decode msg
|
63 |
65 |
else Bad "HMAC verification failed"
|
64 |
|
return (salt, msg, req)
|
|
66 |
return (salt, msg, parsedMsg)
|
65 |
67 |
|
66 |
68 |
-- | Message parsing. This can either result in a good, valid message,
|
67 |
69 |
-- or fail in the Result monad.
|
68 |
70 |
parseMessage :: HashKey -> String -> Integer
|
69 |
71 |
-> Result (String, ConfdRequest)
|
70 |
72 |
parseMessage hmac msg curtime = do
|
71 |
|
(salt, origmsg, request) <- parseRequest hmac msg
|
|
73 |
(salt, origmsg, request) <- parseSignedMessage hmac msg
|
72 |
74 |
ts <- tryRead "Parsing timestamp" salt::Result Integer
|
73 |
75 |
if abs (ts - curtime) > maxClockSkew
|
74 |
76 |
then fail "Too old/too new timestamp or clock skew"
|