summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoman Smrž <roman.smrz@seznam.cz>2019-10-11 22:19:15 +0200
committerRoman Smrž <roman.smrz@seznam.cz>2019-10-11 22:19:15 +0200
commit61b04eb5fda0d1e94f673ad1c11f328a318bb09d (patch)
treef9dc3edde8de7f50e17bcd0bcc3873f8cda6c89c
parent681c68ef5843c13df1a8e5da3540b2b00ba2eb03 (diff)
Identity merging and verification
-rw-r--r--erebos.cabal1
-rw-r--r--src/Channel.hs26
-rw-r--r--src/Identity.hs195
-rw-r--r--src/Main.hs31
-rw-r--r--src/Message.hs15
-rw-r--r--src/Network.hs26
-rw-r--r--src/PubKey.hs5
7 files changed, 215 insertions, 84 deletions
diff --git a/erebos.cabal b/erebos.cabal
index cf50a74..8e35452 100644
--- a/erebos.cabal
+++ b/erebos.cabal
@@ -34,6 +34,7 @@ executable erebos
MultiWayIf,
RankNTypes,
ScopedTypeVariables,
+ StandaloneDeriving,
TupleSections,
TypeFamilies
diff --git a/src/Channel.hs b/src/Channel.hs
index 4627d70..50e1b81 100644
--- a/src/Channel.hs
+++ b/src/Channel.hs
@@ -32,7 +32,7 @@ import PubKey
import Storage
data Channel = Channel
- { chPeers :: [Stored Identity]
+ { chPeers :: [Stored (Signed IdentityData)]
, chKey :: ScrubbedBytes
}
deriving (Show)
@@ -40,7 +40,7 @@ data Channel = Channel
type ChannelRequest = Signed ChannelRequestData
data ChannelRequestData = ChannelRequest
- { crPeers :: [Stored Identity]
+ { crPeers :: [Stored (Signed IdentityData)]
, crKey :: Stored PublicKexKey
}
@@ -88,22 +88,22 @@ instance Storable ChannelAcceptData where
<*> loadRef "key"
-createChannelRequest :: Storage -> Stored Identity -> Stored Identity -> IO (Stored ChannelRequest)
+createChannelRequest :: Storage -> UnifiedIdentity -> UnifiedIdentity -> IO (Stored ChannelRequest)
createChannelRequest st self peer = do
(_, xpublic) <- generateKeys st
- Just skey <- loadKey $ idKeyMessage $ fromStored $ signedData $ fromStored self
- wrappedStore st =<< sign skey =<< wrappedStore st ChannelRequest { crPeers = sort [self, peer], crKey = xpublic }
+ Just skey <- loadKey $ idKeyMessage self
+ wrappedStore st =<< sign skey =<< wrappedStore st ChannelRequest { crPeers = sort [idData self, idData peer], crKey = xpublic }
-acceptChannelRequest :: Stored Identity -> Stored Identity -> Stored ChannelRequest -> ExceptT [String] IO (Stored ChannelAccept, Stored Channel)
+acceptChannelRequest :: UnifiedIdentity -> UnifiedIdentity -> Stored ChannelRequest -> ExceptT [String] IO (Stored ChannelAccept, Stored Channel)
acceptChannelRequest self peer req = do
- guard $ (crPeers $ fromStored $ signedData $ fromStored req) == sort [self, peer]
- guard $ (idKeyMessage $ fromStored $ signedData $ fromStored peer) `elem` (map (sigKey . fromStored) $ signedSignature $ fromStored req)
+ guard $ (crPeers $ fromStored $ signedData $ fromStored req) == sort (map idData [self, peer])
+ guard $ (idKeyMessage peer) `elem` (map (sigKey . fromStored) $ signedSignature $ fromStored req)
let st = storedStorage req
KeySizeFixed ksize = cipherKeySize (undefined :: AES128)
liftIO $ do
(xsecret, xpublic) <- generateKeys st
- Just skey <- loadKey $ idKeyMessage $ fromStored $ signedData $ fromStored self
+ Just skey <- loadKey $ idKeyMessage self
acc <- wrappedStore st =<< sign skey =<< wrappedStore st ChannelAccept { caRequest = req, caKey = xpublic }
ch <- wrappedStore st Channel
{ chPeers = crPeers $ fromStored $ signedData $ fromStored req
@@ -112,15 +112,15 @@ acceptChannelRequest self peer req = do
}
return (acc, ch)
-acceptedChannel :: Stored Identity -> Stored Identity -> Stored ChannelAccept -> ExceptT [String] IO (Stored Channel)
+acceptedChannel :: UnifiedIdentity -> UnifiedIdentity -> Stored ChannelAccept -> ExceptT [String] IO (Stored Channel)
acceptedChannel self peer acc = do
let st = storedStorage acc
req = caRequest $ fromStored $ signedData $ fromStored acc
KeySizeFixed ksize = cipherKeySize (undefined :: AES128)
- guard $ (crPeers $ fromStored $ signedData $ fromStored req) == sort [self, peer]
- guard $ (idKeyMessage $ fromStored $ signedData $ fromStored peer) `elem` (map (sigKey . fromStored) $ signedSignature $ fromStored acc)
- guard $ (idKeyMessage $ fromStored $ signedData $ fromStored self) `elem` (map (sigKey . fromStored) $ signedSignature $ fromStored req)
+ guard $ (crPeers $ fromStored $ signedData $ fromStored req) == sort (map idData [self, peer])
+ guard $ idKeyMessage peer `elem` (map (sigKey . fromStored) $ signedSignature $ fromStored acc)
+ guard $ idKeyMessage self `elem` (map (sigKey . fromStored) $ signedSignature $ fromStored req)
Just xsecret <- liftIO $ loadKey $ crKey $ fromStored $ signedData $ fromStored req
liftIO $ wrappedStore st Channel
diff --git a/src/Identity.hs b/src/Identity.hs
index 96346d8..5a7f8fc 100644
--- a/src/Identity.hs
+++ b/src/Identity.hs
@@ -1,62 +1,185 @@
+{-# LANGUAGE UndecidableInstances #-}
+
module Identity (
- Identity, IdentityData(..),
- emptyIdentity,
+ Identity, ComposedIdentity, UnifiedIdentity, IdentityData(..),
+ idData, idDataF, idName, idOwner, idKeyIdentity, idKeyMessage,
+
+ emptyIdentityData,
+ verifyIdentity, verifyIdentityF,
+ mergeIdentity, toComposedIdentity,
+
finalOwner,
displayIdentity,
) where
+import Control.Monad
+import qualified Control.Monad.Identity as I
+
+import Data.Foldable
+import Data.Function
+import Data.List
import Data.Maybe
+import Data.Ord
+import Data.Set (Set)
+import qualified Data.Set as S
import Data.Text (Text)
import qualified Data.Text as T
import PubKey
import Storage
-type Identity = Signed IdentityData
-
-data IdentityData = Identity
- { idName :: Maybe Text
- , idPrev :: Maybe (Stored Identity)
- , idOwner :: Maybe (Stored Identity)
- , idKeyIdentity :: Stored PublicKey
- , idKeyMessage :: Stored PublicKey
+data Identity m = Identity
+ { idData_ :: m (Stored (Signed IdentityData))
+ , idName_ :: Maybe Text
+ , idOwner_ :: Maybe UnifiedIdentity
+ , idKeyIdentity_ :: Stored PublicKey
+ , idKeyMessage_ :: Stored PublicKey
}
- deriving (Show)
-emptyIdentity :: Stored PublicKey -> Stored PublicKey -> IdentityData
-emptyIdentity key kmsg = Identity
- { idName = Nothing
- , idPrev = Nothing
- , idOwner = Nothing
- , idKeyIdentity = key
- , idKeyMessage = kmsg
+deriving instance Show (m (Stored (Signed IdentityData))) => Show (Identity m)
+
+type ComposedIdentity = Identity []
+type UnifiedIdentity = Identity I.Identity
+
+instance Eq UnifiedIdentity where
+ (==) = (==) `on` idData
+
+data IdentityData = IdentityData
+ { iddPrev :: [Stored (Signed IdentityData)]
+ , iddName :: Maybe Text
+ , iddOwner :: Maybe (Stored (Signed IdentityData))
+ , iddKeyIdentity :: Stored PublicKey
+ , iddKeyMessage :: Maybe (Stored PublicKey)
}
+ deriving (Show)
instance Storable IdentityData where
store' idt = storeRec $ do
- storeMbText "name" $ idName idt
- storeMbRef "prev" $ idPrev idt
- storeMbRef "owner" $ idOwner idt
- storeRef "key-id" $ idKeyIdentity idt
- storeRef "key-msg" $ idKeyMessage idt
-
- load' = loadRec $ Identity
- <$> loadMbText "name"
- <*> loadMbRef "prev"
+ mapM_ (storeRef "PREV") $ iddPrev idt
+ storeMbText "name" $ iddName idt
+ storeMbRef "owner" $ iddOwner idt
+ storeRef "key-id" $ iddKeyIdentity idt
+ storeMbRef "key-msg" $ iddKeyMessage idt
+
+ load' = loadRec $ IdentityData
+ <$> loadRefs "PREV"
+ <*> loadMbText "name"
<*> loadMbRef "owner"
<*> loadRef "key-id"
- <*> loadRef "key-msg"
+ <*> loadMbRef "key-msg"
+
+idData :: UnifiedIdentity -> Stored (Signed IdentityData)
+idData = I.runIdentity . idDataF
+
+idDataF :: Identity m -> m (Stored (Signed IdentityData))
+idDataF = idData_
+
+idName :: Identity m -> Maybe Text
+idName = idName_
+
+idOwner :: Identity m -> Maybe UnifiedIdentity
+idOwner = idOwner_
+
+idKeyIdentity :: Identity m -> Stored PublicKey
+idKeyIdentity = idKeyIdentity_
+
+idKeyMessage :: Identity m -> Stored PublicKey
+idKeyMessage = idKeyMessage_
+
+
+emptyIdentityData :: Stored PublicKey -> IdentityData
+emptyIdentityData key = IdentityData
+ { iddName = Nothing
+ , iddPrev = []
+ , iddOwner = Nothing
+ , iddKeyIdentity = key
+ , iddKeyMessage = Nothing
+ }
+
+verifyIdentity :: Stored (Signed IdentityData) -> Maybe UnifiedIdentity
+verifyIdentity = verifyIdentityF . I.Identity
+
+verifyIdentityF :: Foldable m => m (Stored (Signed IdentityData)) -> Maybe (Identity m)
+verifyIdentityF mdata = do
+ let idata = toList mdata -- TODO: eliminate ancestors
+ guard $ not $ null idata
+ mapM_ verifySignatures $ gatherPrevious S.empty idata
+ Identity
+ <$> pure mdata
+ <*> pure (lookupProperty iddName idata)
+ <*> case lookupProperty iddOwner idata of
+ Nothing -> return Nothing
+ Just owner -> Just <$> verifyIdentity owner
+ <*> pure (iddKeyIdentity $ fromStored $ signedData $ fromStored $ minimum idata)
+ <*> lookupProperty iddKeyMessage idata
+
+gatherPrevious :: Set (Stored (Signed IdentityData)) -> [Stored (Signed IdentityData)] -> Set (Stored (Signed IdentityData))
+gatherPrevious res (n:ns) | n `S.member` res = gatherPrevious res ns
+ | otherwise = gatherPrevious (S.insert n res) $ (iddPrev $ fromStored $ signedData $ fromStored n) ++ ns
+gatherPrevious res [] = res
+
+verifySignatures :: Stored (Signed IdentityData) -> Maybe ()
+verifySignatures sidd = do
+ let idd = fromStored $ signedData $ fromStored sidd
+ required = concat
+ [ [ iddKeyIdentity idd ]
+ , map (iddKeyIdentity . fromStored . signedData . fromStored) $ iddPrev idd
+ , map (iddKeyIdentity . fromStored . signedData . fromStored) $ toList $ iddOwner idd
+ ]
+ guard $ all (fromStored sidd `isSignedBy`) required
+
+lookupProperty :: forall a. (IdentityData -> Maybe a) -> [Stored (Signed IdentityData)] -> Maybe a
+lookupProperty sel topHeads = findResult filteredLayers
+ where findPropHeads :: Stored (Signed IdentityData) -> [(Stored (Signed IdentityData), a)]
+ findPropHeads sobj | Just x <- sel $ fromStored $ signedData $ fromStored sobj = [(sobj, x)]
+ | otherwise = findPropHeads =<< (iddPrev $ fromStored $ signedData $ fromStored sobj)
+
+ propHeads :: [(Stored (Signed IdentityData), a)]
+ propHeads = findPropHeads =<< topHeads
+
+ historyLayers :: [Set (Stored (Signed IdentityData))]
+ historyLayers = flip unfoldr (map fst propHeads, S.empty) $ \(hs, cur) ->
+ case filter (`S.notMember` cur) $ (iddPrev . fromStored . signedData . fromStored) =<< hs of
+ [] -> Nothing
+ added -> let next = foldr S.insert cur added
+ in Just (next, (added, next))
+
+ filteredLayers :: [[(Stored (Signed IdentityData), a)]]
+ filteredLayers = scanl (\cur obsolete -> filter ((`S.notMember` obsolete) . fst) cur) propHeads historyLayers
+
+ findResult ([(_, x)] : _) = Just x
+ findResult ([] : _) = Nothing
+ findResult [] = Nothing
+ findResult [xs] = Just $ snd $ minimumBy (comparing fst) xs
+ findResult (_:rest) = findResult rest
+
+mergeIdentity :: Foldable m => Identity m -> IO UnifiedIdentity
+mergeIdentity idt | [sdata] <- toList $ idDataF idt = return $ idt { idData_ = I.Identity sdata }
+mergeIdentity idt = do
+ (sid:_) <- return $ toList $ idDataF idt
+ let st = storedStorage sid
+ public = idKeyIdentity idt
+ Just secret <- loadKey public
+ sdata <- wrappedStore st =<< sign secret =<< wrappedStore st (emptyIdentityData public)
+ { iddPrev = toList $ idDataF idt }
+ return $ idt { idData_ = I.Identity sdata }
+
+
+toComposedIdentity :: Foldable m => Identity m -> ComposedIdentity
+toComposedIdentity idt = idt { idData_ = toList $ idDataF idt }
+
-unfoldOwners :: Stored Identity -> [Stored Identity]
-unfoldOwners cur = cur : case idOwner $ fromStored $ signedData $ fromStored cur of
+unfoldOwners :: (Foldable m, Applicative m) => Identity m -> [Identity m]
+unfoldOwners cur = cur : case idOwner cur of
Nothing -> []
- Just prev -> unfoldOwners prev
+ Just owner@Identity { idData_ = I.Identity pid } ->
+ unfoldOwners owner { idData_ = pure pid }
-finalOwner :: Stored Identity -> Stored Identity
+finalOwner :: (Foldable m, Applicative m) => Identity m -> Identity m
finalOwner = last . unfoldOwners
-displayIdentity :: Stored Identity -> Text
-displayIdentity sidentity = T.concat
- [ T.intercalate (T.pack " / ") $ map (fromMaybe (T.pack "<unnamed>") . idName . fromStored . signedData . fromStored) owners
+displayIdentity :: (Foldable m, Applicative m) => Identity m -> Text
+displayIdentity identity = T.concat
+ [ T.intercalate (T.pack " / ") $ map (fromMaybe (T.pack "<unnamed>") . idName) owners
]
- where owners = reverse $ unfoldOwners sidentity
+ where owners = reverse $ unfoldOwners identity
diff --git a/src/Main.hs b/src/Main.hs
index 4a6d3cd..1785581 100644
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -28,7 +28,7 @@ import Storage
data Erebos = Erebos
- { erbIdentity :: Stored Identity
+ { erbIdentity :: Stored (Signed IdentityData)
, erbMessages :: StoredList DirectMessageThread
}
@@ -53,9 +53,10 @@ loadErebosHead st = loadHeadDef st "erebos" $ do
(devSecret, devPublic) <- generateKeys st
(_devSecretMsg, devPublicMsg) <- generateKeys st
- owner <- wrappedStore st =<< sign secret =<< wrappedStore st (emptyIdentity public publicMsg) { idName = Just name }
- identity <- wrappedStore st =<< signAdd devSecret =<< sign secret =<<
- wrappedStore st (emptyIdentity devPublic devPublicMsg) { idOwner = Just owner }
+ owner <- wrappedStore st =<< sign secret =<< wrappedStore st (emptyIdentityData public)
+ { iddName = Just name, iddKeyMessage = Just publicMsg }
+ identity <- wrappedStore st =<< signAdd devSecret =<< sign secret =<< wrappedStore st (emptyIdentityData devPublic)
+ { iddOwner = Just owner, iddKeyMessage = Just devPublicMsg }
msgs <- emptySList st
return $ Erebos
@@ -101,7 +102,7 @@ interactiveLoop :: Storage -> String -> IO ()
interactiveLoop st bhost = runInputT defaultSettings $ do
erebosHead <- liftIO $ loadErebosHead st
let serebos = wrappedLoad (headRef erebosHead) :: Stored Erebos
- self = erbIdentity $ fromStored serebos
+ Just self = verifyIdentity $ erbIdentity $ fromStored serebos
outputStrLn $ T.unpack $ displayIdentity self
haveTerminalUI >>= \case True -> return ()
@@ -109,7 +110,7 @@ interactiveLoop st bhost = runInputT defaultSettings $ do
extPrint <- getExternalPrint
let extPrintLn str = extPrint $ str ++ "\n";
(chanPeer, chanSvc) <- liftIO $
- startServer extPrintLn bhost $ erbIdentity $ fromStored serebos
+ startServer extPrintLn bhost self
peers <- liftIO $ newMVar []
@@ -131,9 +132,9 @@ interactiveLoop st bhost = runInputT defaultSettings $ do
msg = fromStored smsg
extPrintLn $ formatMessage tzone msg
if | Just powner <- finalOwner <$> peerIdentity peer
- , powner == msgFrom msg
+ , idData powner == msgFrom msg
-> updateErebosHead_ st $ \erb -> do
- slist <- case find ((== powner) . msgPeer . fromStored) (storedFromSList $ erbMessages $ fromStored erb) of
+ slist <- case find ((== idData powner) . msgPeer . fromStored) (storedFromSList $ erbMessages $ fromStored erb) of
Just thread -> do thread' <- wrappedStore st (fromStored thread) { msgHead = smsg : msgHead (fromStored thread) }
slistReplaceS thread thread' $ erbMessages $ fromStored erb
Nothing -> slistAdd (emptyDirectThread powner) { msgHead = [smsg] } $ erbMessages $ fromStored erb
@@ -151,7 +152,7 @@ interactiveLoop st bhost = runInputT defaultSettings $ do
let process cstate = do
let pname = case csPeer cstate of
Nothing -> ""
- Just peer -> maybe "<unnamed>" T.unpack $ idName . fromStored . signedData . fromStored . finalOwner <=< peerIdentity $ peer
+ Just peer -> maybe "<unnamed>" T.unpack $ idName . finalOwner <=< peerIdentity $ peer
input <- getInputLines $ pname ++ "> "
let (cmd, line) = case input of
'/':rest -> let (scmd, args) = dropWhile isSpace <$> span isAlphaNum rest
@@ -171,7 +172,7 @@ interactiveLoop st bhost = runInputT defaultSettings $ do
data CommandInput = CommandInput
- { ciSelf :: Stored Identity
+ { ciSelf :: UnifiedIdentity
, ciLine :: String
, ciPeers :: CommandM [Peer]
}
@@ -207,13 +208,13 @@ cmdSetPeer n | n < 1 = liftIO $ putStrLn "Invalid peer index"
cmdSend :: Command
cmdSend = void $ runMaybeT $ do
self <- asks ciSelf
- let st = storedStorage self
+ let st = storedStorage $ idData self
Just peer <- gets csPeer
Just powner <- return $ finalOwner <$> peerIdentity peer
_:_ <- return $ peerChannels peer
text <- asks ciLine
smsg <- liftIO $ updateErebosHead st $ \erb -> do
- (slist, smsg) <- case find ((== powner) . msgPeer . fromStored) (storedFromSList $ erbMessages $ fromStored erb) of
+ (slist, smsg) <- case find ((== idData powner) . msgPeer . fromStored) (storedFromSList $ erbMessages $ fromStored erb) of
Just thread -> do
(smsg, thread') <- createDirectMessage self (fromStored thread) (T.pack text)
(,smsg) <$> slistReplaceS thread thread' (erbMessages $ fromStored erb)
@@ -230,13 +231,13 @@ cmdSend = void $ runMaybeT $ do
cmdHistory :: Command
cmdHistory = void $ runMaybeT $ do
self <- asks ciSelf
- let st = storedStorage self
+ let st = storedStorage $ idData self
Just peer <- gets csPeer
Just powner <- return $ finalOwner <$> peerIdentity peer
Just erebosHead <- liftIO $ loadHead st "erebos"
let erebos = wrappedLoad (headRef erebosHead)
- Just thread <- return $ find ((==powner) . msgPeer) $ fromSList $ erbMessages $ fromStored erebos
+ Just thread <- return $ find ((== idData powner) . msgPeer) $ fromSList $ erbMessages $ fromStored erebos
tzone <- liftIO $ getCurrentTimeZone
liftIO $ mapM_ (putStrLn . formatMessage tzone) $ reverse $ take 50 $ threadToList thread
@@ -244,7 +245,7 @@ cmdHistory = void $ runMaybeT $ do
formatMessage :: TimeZone -> DirectMessage -> String
formatMessage tzone msg = concat
[ formatTime defaultTimeLocale "[%H:%M] " $ utcToLocalTime tzone $ zonedTimeToUTC $ msgTime msg
- , maybe "<unnamed>" T.unpack $ idName $ fromStored $ signedData $ fromStored $ msgFrom msg
+ , maybe "<unnamed>" T.unpack $ iddName $ fromStored $ signedData $ fromStored $ msgFrom msg
, ": "
, T.unpack $ msgText msg
]
diff --git a/src/Message.hs b/src/Message.hs
index 0a1a70e..8892edb 100644
--- a/src/Message.hs
+++ b/src/Message.hs
@@ -11,17 +11,18 @@ import Data.Text (Text)
import Data.Time.LocalTime
import Identity
+import PubKey
import Storage
data DirectMessage = DirectMessage
- { msgFrom :: Stored Identity
+ { msgFrom :: Stored (Signed IdentityData)
, msgPrev :: [Stored DirectMessage]
, msgTime :: ZonedTime
, msgText :: Text
}
data DirectMessageThread = DirectMessageThread
- { msgPeer :: Stored Identity
+ { msgPeer :: Stored (Signed IdentityData)
, msgHead :: [Stored DirectMessage]
, msgSeen :: [Stored DirectMessage]
}
@@ -51,15 +52,15 @@ instance Storable DirectMessageThread where
<*> loadRefs "seen"
-emptyDirectThread :: Stored Identity -> DirectMessageThread
-emptyDirectThread peer = DirectMessageThread peer [] []
+emptyDirectThread :: UnifiedIdentity -> DirectMessageThread
+emptyDirectThread peer = DirectMessageThread (idData peer) [] []
-createDirectMessage :: Stored Identity -> DirectMessageThread -> Text -> IO (Stored DirectMessage, Stored DirectMessageThread)
+createDirectMessage :: UnifiedIdentity -> DirectMessageThread -> Text -> IO (Stored DirectMessage, Stored DirectMessageThread)
createDirectMessage self thread msg = do
- let st = storedStorage self
+ let st = storedStorage $ idData self
time <- getZonedTime
smsg <- wrappedStore st DirectMessage
- { msgFrom = finalOwner self
+ { msgFrom = idData $ finalOwner self
, msgPrev = msgHead thread
, msgTime = time
, msgText = msg
diff --git a/src/Network.hs b/src/Network.hs
index eb72ed2..053dbe5 100644
--- a/src/Network.hs
+++ b/src/Network.hs
@@ -30,7 +30,7 @@ discoveryPort = "29665"
data Peer = Peer
{ peerAddress :: PeerAddress
- , peerIdentity :: Maybe (Stored Identity)
+ , peerIdentity :: Maybe UnifiedIdentity
, peerChannels :: [Channel]
, peerSocket :: Socket
, peerStorage :: Storage
@@ -113,8 +113,9 @@ serviceFromObject (Rec items)
serviceFromObject _ = Nothing
-startServer :: (String -> IO ()) -> String -> Stored Identity -> IO (Chan Peer, Chan (Peer, T.Text, Ref))
-startServer logd bhost sidentity = do
+startServer :: (String -> IO ()) -> String -> UnifiedIdentity -> IO (Chan Peer, Chan (Peer, T.Text, Ref))
+startServer logd bhost identity = do
+ let sidentity = idData identity
chanPeer <- newChan
chanSvc <- newChan
peers <- newMVar M.empty
@@ -174,14 +175,15 @@ startServer logd bhost sidentity = do
then do forM_ objs $ storeObject ist
copyRef pst from >>= \case
Nothing -> logd $ "Incomplete peer identity"
- Just sfrom -> do
- let peer = Peer (DatagramAddress paddr) (Just $ wrappedLoad sfrom) [] sock pst ist
+ Just sfrom | Just pidentity <- verifyIdentity (wrappedLoad sfrom) -> do
+ let peer = Peer (DatagramAddress paddr) (Just pidentity) [] sock pst ist
modifyMVar_ peers $ return . M.insert paddr peer
writeChan chanPeer peer
void $ sendTo sock (BL.toStrict $ BL.concat
[ serializeObject $ transportToObject $ IdentityResponse (partialRef ist $ storedRef sidentity)
, BL.concat $ map (lazyLoadBytes . storedRef) $ collectStoredObjects $ wrappedLoad $ storedRef sidentity
]) paddr
+ Just _ -> logd $ "Peer identity verification failed"
else logd $ "Mismatched content"
packet _ paddr (IdentityResponse ref) [] _ _ = do
@@ -195,12 +197,11 @@ startServer logd bhost sidentity = do
then do forM_ objs $ storeObject ist
copyRef pst ref >>= \case
Nothing -> logd $ "Incomplete peer identity"
- Just sref -> do
- let pidentity = wrappedLoad sref
- peer = Peer (DatagramAddress paddr) (Just pidentity) [] sock pst ist
+ Just sref | Just pidentity <- verifyIdentity (wrappedLoad sref) -> do
+ let peer = Peer (DatagramAddress paddr) (Just pidentity) [] sock pst ist
modifyMVar_ peers $ return . M.insert paddr peer
writeChan chanPeer peer
- req <- createChannelRequest pst sidentity pidentity
+ req <- createChannelRequest pst identity pidentity
void $ sendTo sock (BL.toStrict $ BL.concat
[ serializeObject $ transportToObject $ TrChannelRequest (partialRef ist $ storedRef req)
, lazyLoadBytes $ storedRef req
@@ -208,6 +209,7 @@ startServer logd bhost sidentity = do
, lazyLoadBytes $ storedRef $ crKey $ fromStored $ signedData $ fromStored req
, BL.concat $ map (lazyLoadBytes . storedRef) $ signedSignature $ fromStored req
]) paddr
+ Just _ -> logd $ "Peer identity verification failed"
else logd $ "Mismatched content"
packet _ paddr (TrChannelRequest _) [] _ _ = do
@@ -225,7 +227,7 @@ startServer logd bhost sidentity = do
let request = wrappedLoad sref :: Stored ChannelRequest
modifyMVar_ peers $ \pval -> case M.lookup paddr pval of
Just peer | Just pid <- peerIdentity peer ->
- runExceptT (acceptChannelRequest sidentity pid request) >>= \case
+ runExceptT (acceptChannelRequest identity pid request) >>= \case
Left errs -> do mapM_ logd ("Invalid channel request" : errs)
return pval
Right (acc, channel) -> do
@@ -260,7 +262,7 @@ startServer logd bhost sidentity = do
let accepted = wrappedLoad sref :: Stored ChannelAccept
modifyMVar_ peers $ \pval -> case M.lookup paddr pval of
Just peer | Just pid <- peerIdentity peer ->
- runExceptT (acceptedChannel sidentity pid accepted) >>= \case
+ runExceptT (acceptedChannel identity pid accepted) >>= \case
Left errs -> do mapM_ logd ("Invalid channel accept" : errs)
return pval
Right channel -> do
@@ -284,7 +286,7 @@ startServer logd bhost sidentity = do
return (chanPeer, chanSvc)
-sendToPeer :: Storable a => Stored Identity -> Peer -> T.Text -> a -> IO ()
+sendToPeer :: Storable a => UnifiedIdentity -> Peer -> T.Text -> a -> IO ()
sendToPeer _ peer@Peer { peerChannels = ch:_ } svc obj = do
let st = peerInStorage peer
ref <- store st obj
diff --git a/src/PubKey.hs b/src/PubKey.hs
index 6dc8080..d7134c8 100644
--- a/src/PubKey.hs
+++ b/src/PubKey.hs
@@ -2,7 +2,7 @@ module PubKey (
PublicKey, SecretKey,
KeyPair(generateKeys), loadKey,
Signature(sigKey), Signed, signedData, signedSignature,
- sign, signAdd,
+ sign, signAdd, isSignedBy,
PublicKexKey, SecretKexKey,
dhSecret,
@@ -103,6 +103,9 @@ signAdd (SecretKey secret spublic) (Signed val sigs) = do
ssig <- wrappedStore (storedStorage val) $ Signature spublic sig
return $ Signed val (ssig : sigs)
+isSignedBy :: Signed a -> Stored PublicKey -> Bool
+isSignedBy sig key = key `elem` map (sigKey . fromStored) (signedSignature sig)
+
data PublicKexKey = PublicKexKey CX.PublicKey
deriving (Show)