diff --git a/src/Simplex/Messaging/Client.hs b/src/Simplex/Messaging/Client.hs index 7a2eedeb9..c037a9f4b 100644 --- a/src/Simplex/Messaging/Client.hs +++ b/src/Simplex/Messaging/Client.hs @@ -1263,14 +1263,14 @@ proxySMPCommand c@ProtocolClient {thParams = proxyThParams, client_ = PClient {c -- proxy should send PRES to the client with EncResponse -- Always uses background timeout mode forwardSMPTransmission :: SMPClient -> CorrId -> VersionSMP -> C.PublicKeyX25519 -> EncTransmission -> ExceptT SMPClientError IO (Maybe C.CbNonce, EncResponse) -forwardSMPTransmission c@ProtocolClient {thParams, client_ = PClient {clientCorrId = g}} fwdCorrId fwdVersion fwdKey fwdTransmission = do +forwardSMPTransmission c@ProtocolClient {thParams, client_ = PClient {clientCorrId = g}} (CorrId corrId) fwdVersion fwdKey fwdTransmission = do -- prepare params sessSecret <- case thAuth thParams of Nothing -> throwE $ PCETransportError TENoServerAuth Just THAuthClient {sessSecret} -> maybe (throwE $ PCETransportError TENoServerAuth) pure sessSecret nonce <- liftIO . atomically $ C.randomCbNonce g -- wrap - let fwdT = FwdTransmission {fwdCorrId, fwdVersion, fwdKey, fwdTransmission} + let fwdT = FwdTransmission {fwdCorrId = C.StrictCbNonce corrId, fwdVersion, fwdKey, fwdTransmission} eft = EncFwdTransmission $ C.cbEncryptNoPad sessSecret nonce (smpEncode fwdT) -- send sendProtocolCommand_ c NRMBackground (Just nonce) Nothing Nothing NoEntity (Cmd SProxyService (RFWD eft)) >>= \case diff --git a/src/Simplex/Messaging/Crypto.hs b/src/Simplex/Messaging/Crypto.hs index a22833976..3546951a7 100644 --- a/src/Simplex/Messaging/Crypto.hs +++ b/src/Simplex/Messaging/Crypto.hs @@ -142,6 +142,7 @@ module Simplex.Messaging.Crypto -- * NaCl crypto_box CbNonce (unCbNonce), pattern CbNonce, + StrictCbNonce (..), cbEncrypt, cbEncryptNoPad, cbEncryptMaxLenBS, @@ -1426,6 +1427,14 @@ instance Encoding CbNonce where smpEncode = unCbNonce smpP = CryptoBoxNonce <$> A.take 24 +-- | Length-prefixed nonce that fails to parse unless it is 24 bytes, unlike cbNonce that pads or truncates. +newtype StrictCbNonce = StrictCbNonce {unStrictCbNonce :: ByteString} + deriving (Eq, Show) + +instance Encoding StrictCbNonce where + smpEncode (StrictCbNonce s) = smpEncode s + smpP = smpP >>= \s -> if B.length s == 24 then pure (StrictCbNonce s) else fail "bad nonce length" + newtype SbKey = SecretBoxKey {unSbKey :: ByteString} deriving (Eq, Show) deriving newtype (FromField) diff --git a/src/Simplex/Messaging/Protocol.hs b/src/Simplex/Messaging/Protocol.hs index 633fffb6b..7cb189cca 100644 --- a/src/Simplex/Messaging/Protocol.hs +++ b/src/Simplex/Messaging/Protocol.hs @@ -125,7 +125,6 @@ module Simplex.Messaging.Protocol SrvLoc (..), CorrId (..), pattern NoCorrId, - corrIdNonce, EntityId (..), pattern NoEntity, QueueId, @@ -251,7 +250,6 @@ import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Lazy as LB import Data.Char (isPrint, isSpace) import Data.Constraint (Dict (..)) -import Data.Either (isLeft) import Data.Functor (($>)) import Data.Int (Int64) import Data.Kind @@ -711,18 +709,18 @@ encTransmissionNonce v nonce@(C.CbNonce s) | otherwise = nonce data FwdTransmission = FwdTransmission - { fwdCorrId :: CorrId, + { fwdCorrId :: C.StrictCbNonce, fwdVersion :: VersionSMP, fwdKey :: C.PublicKeyX25519, fwdTransmission :: EncTransmission } instance Encoding FwdTransmission where - smpEncode FwdTransmission {fwdCorrId = CorrId corrId, fwdVersion, fwdKey, fwdTransmission = EncTransmission t} = - smpEncode (corrId, fwdVersion, fwdKey, Tail t) + smpEncode FwdTransmission {fwdCorrId, fwdVersion, fwdKey, fwdTransmission = EncTransmission t} = + smpEncode (fwdCorrId, fwdVersion, fwdKey, Tail t) smpP = do - (corrId, fwdVersion, fwdKey, Tail t) <- smpP - pure FwdTransmission {fwdCorrId = CorrId corrId, fwdVersion, fwdKey, fwdTransmission = EncTransmission t} + (fwdCorrId, fwdVersion, fwdKey, Tail t) <- smpP + pure FwdTransmission {fwdCorrId, fwdVersion, fwdKey, fwdTransmission = EncTransmission t} newtype EncFwdTransmission = EncFwdTransmission ByteString deriving (Show) @@ -768,16 +766,16 @@ newtype EncFwdResponse = EncFwdResponse ByteString deriving (Eq, Show) data FwdResponse = FwdResponse - { fwdCorrId :: CorrId, + { fwdCorrId :: C.StrictCbNonce, fwdResponse :: EncResponse } instance Encoding FwdResponse where - smpEncode FwdResponse {fwdCorrId = CorrId corrId, fwdResponse = EncResponse t} = - smpEncode (corrId, Tail t) + smpEncode FwdResponse {fwdCorrId, fwdResponse = EncResponse t} = + smpEncode (fwdCorrId, Tail t) smpP = do - (corrId, Tail t) <- smpP - pure FwdResponse {fwdCorrId = CorrId corrId, fwdResponse = EncResponse t} + (fwdCorrId, Tail t) <- smpP + pure FwdResponse {fwdCorrId, fwdResponse = EncResponse t} newtype EncResponse = EncResponse ByteString deriving (Eq, Show) @@ -1435,10 +1433,6 @@ instance IsString CorrId where fromString = CorrId . fromString {-# INLINE fromString #-} --- | Fails unless corrId is exactly 24 bytes, so it is never padded or truncated. -corrIdNonce :: CorrId -> Either String C.CbNonce -corrIdNonce = smpDecode . bs - instance StrEncoding CorrId where strEncode (CorrId cId) = strEncode cId strDecode s = CorrId <$> strDecode s @@ -2427,12 +2421,7 @@ tDecodeServer THandleParams {sessionId, thVersion = v, implySessId} = \case | implySessId || sessId == sessionId -> case decodeTAuthBytes authenticator serviceSig of Right tAuth -> bimap t ((tAuth,authorized,) . t) cmdOrErr where - cmdOrErr - | invalidAuthNonce = Left $ fromProtocolError @v @err @cmd PECmdSyntax - | otherwise = parseProtocol @v @err @cmd v command >>= checkCredentials tAuth entityId - invalidAuthNonce = case tAuth of - Just (TAAuthenticator _, _) -> isLeft $ corrIdNonce corrId - _ -> False + cmdOrErr = parseProtocol @v @err @cmd v command >>= checkCredentials tAuth entityId t :: a -> (CorrId, EntityId, a) t = (corrId,entityId,) Left _ -> tError corrId PEBlock diff --git a/src/Simplex/Messaging/Server.hs b/src/Simplex/Messaging/Server.hs index d7dde9f3d..434ef722d 100644 --- a/src/Simplex/Messaging/Server.hs +++ b/src/Simplex/Messaging/Server.hs @@ -64,7 +64,7 @@ import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Lazy.Char8 as LB import Data.Constraint (Dict (..)) import Data.Dynamic (toDyn) -import Data.Either (fromRight, isLeft, partitionEithers) +import Data.Either (fromRight, partitionEithers) import Data.Foldable (foldrM) import Data.Functor (($>), (<&>)) import Data.IORef @@ -1453,22 +1453,20 @@ client Just THAuthClient {peerServerCertKey} -> PKEY srvSessId vr peerServerCertKey Nothing -> ERR $ transportErr TENoServerAuth _ -> ERR $ transportErr TEVersion - PFWD fwdV pubKey encBlock - | isLeft (corrIdNonce corrId) -> pure $ Just $ ERR $ CMD SYNTAX - | otherwise -> do - ProxyAgent {smpAgent = a} <- asks proxyAgent - ServerStats {pMsgFwds, pMsgFwdsOwn} <- asks serverStats - let inc = mkIncProxyStats pMsgFwds pMsgFwdsOwn - liftIO (lookupSMPServerClient a sessId) >>= \case - Just (own, smp) -> do - inc own pRequests - forkProxiedCmd $ do - liftIO (runExceptT (forwardSMPTransmission smp corrId fwdV pubKey encBlock) `E.catches` clientHandlers) >>= \case - Right (nonce_, r) -> PRES nonce_ r <$ inc own pSuccesses - Left e -> ERR (smpProxyError e) <$ case e of - PCEProtocolError {} -> inc own pSuccesses - _ -> inc own pErrorsOther - Nothing -> inc False pRequests >> inc False pErrorsConnect $> Just (ERR $ PROXY NO_SESSION) + PFWD fwdV pubKey encBlock -> do + ProxyAgent {smpAgent = a} <- asks proxyAgent + ServerStats {pMsgFwds, pMsgFwdsOwn} <- asks serverStats + let inc = mkIncProxyStats pMsgFwds pMsgFwdsOwn + liftIO (lookupSMPServerClient a sessId) >>= \case + Just (own, smp) -> do + inc own pRequests + forkProxiedCmd $ do + liftIO (runExceptT (forwardSMPTransmission smp corrId fwdV pubKey encBlock) `E.catches` clientHandlers) >>= \case + Right (nonce_, r) -> PRES nonce_ r <$ inc own pSuccesses + Left e -> ERR (smpProxyError e) <$ case e of + PCEProtocolError {} -> inc own pSuccesses + _ -> inc own pErrorsOther + Nothing -> inc False pRequests >> inc False pErrorsConnect $> Just (ERR $ PROXY NO_SESSION) where forkProxiedCmd :: M s BrokerMsg -> M s (Maybe BrokerMsg) forkProxiedCmd = forkCmd serverClientConcurrency corrId (EntityId sessId) @@ -2127,12 +2125,12 @@ client processForwardedCommand (EncFwdTransmission s) = fmap (either (Just . ERR) id) . runExceptT $ do THAuthServer {serverPrivKey, sessSecret'} <- maybe (throwE $ transportErr TENoServerAuth) pure (thAuth thParams') sessSecret <- maybe (throwE $ transportErr TENoServerAuth) pure sessSecret' - proxyNonce <- liftEitherWith (const $ CMD SYNTAX) $ corrIdNonce corrId + let proxyNonce = C.cbNonce $ bs corrId s' <- liftEitherWith (const CRYPTO) $ C.cbDecryptNoPad sessSecret proxyNonce s FwdTransmission {fwdCorrId, fwdVersion, fwdKey, fwdTransmission = EncTransmission et} <- liftEitherWith (const $ CMD SYNTAX) $ smpDecode s' unless (fwdVersion `isCompatible` thServerVRange thParams') $ throwE $ transportErr TEVersion - clientNonce <- liftEitherWith (const $ CMD SYNTAX) $ corrIdNonce fwdCorrId let clientSecret = C.dh' fwdKey serverPrivKey + clientNonce = C.cbNonce $ C.unStrictCbNonce fwdCorrId b <- liftEitherWith (const CRYPTO) $ C.cbDecrypt clientSecret (encTransmissionNonce fwdVersion clientNonce) et let clntTHParams = smpTHParamsSetVersion fwdVersion thParams' -- only allowing single forwarded transactions diff --git a/tests/SMPProxyTests.hs b/tests/SMPProxyTests.hs index e15fcd726..4b0730caf 100644 --- a/tests/SMPProxyTests.hs +++ b/tests/SMPProxyTests.hs @@ -21,12 +21,13 @@ import Control.Logger.Simple import Control.Monad (forM, forM_, forever, replicateM_) import Control.Monad.Trans.Except (ExceptT, runExceptT) import Data.ByteString.Char8 (ByteString) +import qualified Data.ByteString.Char8 as B import Data.List.NonEmpty (NonEmpty) import qualified Data.List.NonEmpty as L import Data.Time.Clock (getCurrentTime) import SMPAgentClient import SMPClient -import ServerTests (decryptMsgV3, sendRecv, wrongSizeCorrIds) +import ServerTests (decryptMsgV3, sendRecv) import Simplex.Messaging.Agent hiding (createConnection, joinConnection, sendMessage) import qualified Simplex.Messaging.Agent as A import Simplex.Messaging.Agent.Env.SQLite (AgentConfig (..), InitialAgentServers (..)) @@ -36,13 +37,11 @@ import Simplex.Messaging.Client import qualified Simplex.Messaging.Crypto as C import Simplex.Messaging.Crypto.Ratchet (pattern PQSupportOn) import qualified Simplex.Messaging.Crypto.Ratchet as CR -import Simplex.Messaging.Encoding (smpEncode) import Simplex.Messaging.Protocol (EncRcvMsgBody (..), MsgBody, QueueReqData (..), RcvMessage (..), SubscriptionMode (..), maxMessageLength, noMsgFlags) import qualified Simplex.Messaging.Protocol as SMP import Simplex.Messaging.Server.Env.STM (AStoreType (..), ServerConfig (..)) import Simplex.Messaging.Server.MsgStore.Types (SQSType (..)) import Simplex.Messaging.Transport -import qualified Simplex.Messaging.Transport.Client as TC import Simplex.Messaging.Util (bshow, tshow) import Simplex.Messaging.Version (mkVersionRange) import System.FilePath (splitExtensions) @@ -60,9 +59,6 @@ smpProxyTests = do describe "server configuration" $ do it "refuses proxy handshake unless enabled" testNoProxy it "checks basic auth in proxy requests" testProxyAuth - describe "corrId used as nonce" $ do - it "proxy rejects PFWD with corrId of wrong size" testPFWDCorrIdSize - it "relay rejects RFWD with corrId of wrong size" testRFWDCorrIdSize describe "relay reconnection" $ do it "recovers when unresponsive relay restarts (control, no disconnect)" $ \_ -> testProxyRecoversWithoutDisconnect @@ -80,6 +76,8 @@ smpProxyTests = do xit "batching proxy requests" todo it "relay rejects forwarded command with changed version" $ \_ -> testChangedFwdVersion + it "relay rejects forwarded corrId of wrong size" $ \_ -> + testFwdCorrIdSize describe "deliver message via SMP proxy" $ do let srv1 = SMPServer testHost testPort testKeyHash srv2 = SMPServer testHost2 testPort2 testKeyHash @@ -459,48 +457,6 @@ testProxyAuth msType = do where proxyCfgAuth = updateCfg (proxyCfgMS msType) $ \cfg_ -> cfg_ {newQueueBasicAuth = Just "correct"} -testPFWDCorrIdSize :: AStoreType -> IO () -testPFWDCorrIdSize msType = - withSmpServerConfigOn (transport @TLS) (proxyCfgMS msType) testPort $ \_ -> - testSMPClient_ "127.0.0.1" testPort supportedServerSMPRelayVRange Nothing $ \(th@THandle {params} :: THandleSMP TLS 'TClient) -> do - g <- C.newRandom - (cmdKey, _ :: C.PrivateKeyX25519) <- atomically $ C.generateKeyPair g - let pfwd corrId = do - (_, _, reply) <- sendRecv th (Nothing, corrId, SMP.EntityId "unknown session", SMP.PFWD (thVersion params) cmdKey $ SMP.EncTransmission "invalid") - pure reply - corrId <- atomically $ C.randomBytes 24 g - pfwd corrId `shouldReturn` Right (SMP.ERR $ SMP.PROXY SMP.NO_SESSION) - forM_ (wrongSizeCorrIds corrId) $ \badCorrId -> - pfwd badCorrId `shouldReturn` Right (SMP.ERR $ SMP.CMD SMP.SYNTAX) - -testRFWDCorrIdSize :: AStoreType -> IO () -testRFWDCorrIdSize msType = - withSmpServerConfigOn (transport @TLS) (cfgMS msType) testPort2 $ \_ -> - testProxyModeClient $ \th@THandle {params = THandleParams {thVersion, thAuth}} -> do - Just THAuthClient {sessSecret = Just sessSecret} <- pure thAuth - g <- C.newRandom - (fwdKey, _ :: C.PrivateKeyX25519) <- atomically $ C.generateKeyPair g - let rfwd corrId fwdCorrId = do - let fwdT = SMP.FwdTransmission {fwdCorrId = SMP.CorrId fwdCorrId, fwdVersion = thVersion, fwdKey, fwdTransmission = SMP.EncTransmission "invalid"} - eft = SMP.EncFwdTransmission $ C.cbEncryptNoPad sessSecret (C.cbNonce corrId) (smpEncode fwdT) - (_, _, reply) <- sendRecv th (Nothing, corrId, NoEntity, SMP.RFWD eft) - pure reply - corrId <- atomically $ C.randomBytes 24 g - fwdCorrId <- atomically $ C.randomBytes 24 g - rfwd corrId fwdCorrId `shouldReturn` Right (SMP.ERR SMP.CRYPTO) - forM_ (wrongSizeCorrIds corrId) $ \badCorrId -> do - rfwd badCorrId fwdCorrId `shouldReturn` Right (SMP.ERR $ SMP.CMD SMP.SYNTAX) - rfwd corrId badCorrId `shouldReturn` Right (SMP.ERR $ SMP.CMD SMP.SYNTAX) - --- Connect to the relay on testPort2 the same way the proxy does, with the session secret. -testProxyModeClient :: (THandleSMP TLS 'TClient -> IO a) -> IO a -testProxyModeClient client = do - g <- C.newRandom - ks <- atomically $ C.generateKeyPair g - let tcConfig = TC.defaultTransportClientConfig {TC.clientALPN = Just alpnSupportedSMPHandshakes} - TC.runTransportClient tcConfig Nothing "127.0.0.1" testPort2 (Just testKeyHash) $ \h -> - runExceptT (smpClientHandshake h (Just ks) testKeyHash supportedClientSMPRelayVRange True Nothing) >>= either (fail . show) client - -- Connect a sender client to the proxy and request a relay session to testSMPServer2 (PRXY). -- On success the reply is PKEY; otherwise it is the proxy error for the relay connection. requestRelaySession :: IO (Either SMP.ErrorType SMP.BrokerMsg) @@ -523,6 +479,22 @@ testChangedFwdVersion = _ <- runExceptT' $ forward v runExceptT (forward $ prevVersion v) `shouldReturn` Left (PCEProtocolError SMP.CRYPTO) +testFwdCorrIdSize :: IO () +testFwdCorrIdSize = + withSmpServerConfigOn (transport @TLS) cfg testPort $ \_ -> do + g <- C.newRandom + ts <- getCurrentTime + rc <- either (fail . show) pure =<< getProtocolClient g NRMInteractive (1, testSMPServer, Nothing) defaultSMPClientConfig [] Nothing ts (\_ -> pure ()) + THAuthClient {peerServerPubKey} <- maybe (fail "getProtocolClient returned no thAuth") pure $ thAuth $ thParams rc + (cmdPubKey, cmdPrivKey) <- atomically $ C.generateKeyPair g + nonce@(C.CbNonce corrId) <- atomically $ C.randomCbNonce g + let v = currentClientSMPRelayVersion + et <- either (fail . show) (pure . SMP.EncTransmission) $ C.cbEncrypt (C.dh' peerServerPubKey cmdPrivKey) (SMP.encTransmissionNonce v nonce) "" SMP.paddedProxiedTLength + let forward cId = runExceptT $ forwardSMPTransmission rc (SMP.CorrId cId) v cmdPubKey et + Right _ <- forward corrId + forM_ (["", B.take 23 corrId, corrId <> "x"] :: [ByteString]) $ \cId -> + forward cId `shouldReturn` Left (PCEProtocolError $ SMP.CMD SMP.SYNTAX) + -- Shared "phase 2" of the reconnection tests: start a healthy relay, confirm it is reachable -- directly (PING, not via the proxy) so a proxy failure can only mean the proxy didn't reconnect, -- let any stored connection error expire, then require the proxy to establish the session (PKEY). diff --git a/tests/ServerTests.hs b/tests/ServerTests.hs index d16f3a210..116b4f0ec 100644 --- a/tests/ServerTests.hs +++ b/tests/ServerTests.hs @@ -97,7 +97,6 @@ serverTests = do describe "Restore messages (old / v2)" testRestoreExpireMessages describe "Save prometheus metrics" testPrometheusMetrics describe "Timing of AUTH error" testTiming - describe "Authenticator nonce" testAuthenticatorCorrIdSize describe "Message notifications" $ do testMessageNotifications testMessageServiceNotifications @@ -1303,9 +1302,9 @@ testTiming = g <- C.newRandom (rPub, rKey) <- atomically $ C.generateAuthKeyPair goodKeyAlg g (dhPub, dhPriv :: C.PrivateKeyX25519) <- atomically $ C.generateKeyPair g - Resp "abcdabcdabcdabcdabcdabcd" NoEntity (Ids rId sId srvDh) <- signSendRecv rh rKey ("abcdabcdabcdabcdabcdabcd", NoEntity, New rPub dhPub) + Resp "abcd" NoEntity (Ids rId sId srvDh) <- signSendRecv rh rKey ("abcd", NoEntity, New rPub dhPub) let dec = decryptMsgV3 $ C.dh' srvDh dhPriv - Resp "cdabcdabcdabcdabcdabcdab" _ resp <- signSendRecv rh rKey ("cdabcdabcdabcdabcdabcdab", rId, SUB) + Resp "cdab" _ resp <- signSendRecv rh rKey ("cdab", rId, SUB) case resp of OK -> pure () SOK Nothing -> pure () @@ -1315,9 +1314,9 @@ testTiming = runTimingTest rh badKey rId SUB (sPub, sKey) <- atomically $ C.generateAuthKeyPair goodKeyAlg g - Resp "dabcdabcdabcdabcdabcdabc" _ OK <- signSendRecv rh rKey ("dabcdabcdabcdabcdabcdabc", rId, KEY sPub) + Resp "dabc" _ OK <- signSendRecv rh rKey ("dabc", rId, KEY sPub) - Resp "bcdabcdabcdabcdabcdabcda" _ OK <- signSendRecv sh sKey ("bcdabcdabcdabcdabcdabcda", sId, _SEND "hello") + Resp "bcda" _ OK <- signSendRecv sh sKey ("bcda", sId, _SEND "hello") Resp "" _ (Msg mId msg) <- tGet1 rh (dec mId msg, Right "hello") #== "delivered from queue" @@ -1328,15 +1327,15 @@ testTiming = threadDelay 100000 _ <- timeRepeat n $ do -- "warm up" the server - Resp "dabcdabcdabcdabcdabcdabc" _ (ERR AUTH) <- signSendRecv h badKey ("dabcdabcdabcdabcdabcdabc", EntityId "1234", cmd) + Resp "dabc" _ (ERR AUTH) <- signSendRecv h badKey ("dabc", EntityId "1234", cmd) return () threadDelay 100000 timeWrongKey <- timeRepeat n $ do - Resp "cdabcdabcdabcdabcdabcdab" _ (ERR AUTH) <- signSendRecv h badKey ("cdabcdabcdabcdabcdabcdab", qId, cmd) + Resp "cdab" _ (ERR AUTH) <- signSendRecv h badKey ("cdab", qId, cmd) return () threadDelay 100000 timeNoQueue <- timeRepeat n $ do - Resp "dabcdabcdabcdabcdabcdabc" _ (ERR AUTH) <- signSendRecv h badKey ("dabcdabcdabcdabcdabcdabc", EntityId "1234", cmd) + Resp "dabc" _ (ERR AUTH) <- signSendRecv h badKey ("dabc", EntityId "1234", cmd) return () let ok = similarTime timeNoQueue timeWrongKey msType unless ok . putStrLn . unwords $ @@ -1348,35 +1347,6 @@ testTiming = ] ok `shouldBe` True -testAuthenticatorCorrIdSize :: SpecWith (ASrvTransport, AStoreType) -testAuthenticatorCorrIdSize = - it "should reject X25519 authenticator unless corrId is 24 bytes" $ \(ATransport t, msType) -> - smpTest2 t msType $ \r s -> do - g <- C.newRandom - let newCorrId = atomically $ C.randomBytes 24 g - rejected cId entId = (CorrId cId, entId, Right (ERR $ CMD SYNTAX)) - badCorrIds <- wrongSizeCorrIds <$> newCorrId - (rPub, rKey) <- atomically $ C.generateAuthKeyPair C.SX25519 g - (dhPub, dhPriv :: C.PrivateKeyX25519) <- atomically $ C.generateKeyPair g - forM_ badCorrIds $ \cId -> - signSendRecv r rKey (cId, NoEntity, New rPub dhPub) `shouldReturn` rejected cId NoEntity - corrId1 <- newCorrId - Resp _ NoEntity (Ids rId sId srvDh) <- signSendRecv r rKey (corrId1, NoEntity, New rPub dhPub) - (sPub, sKey) <- atomically $ C.generateAuthKeyPair C.SEd25519 g - corrId2 <- newCorrId - Resp _ _ OK <- signSendRecv r rKey (corrId2, rId, KEY sPub) - Resp "bcda" _ OK <- signSendRecv s sKey ("bcda", sId, _SEND "hello") - Resp "" _ (Msg mId msg) <- tGet1 r - (decryptMsgV3 (C.dh' srvDh dhPriv) mId msg, Right "hello") #== "delivered from queue" - forM_ badCorrIds $ \cId -> - signSendRecv r rKey (cId, rId, ACK mId) `shouldReturn` rejected cId rId - corrId3 <- newCorrId - Resp _ _ OK <- signSendRecv r rKey (corrId3, rId, ACK mId) - pure () - -wrongSizeCorrIds :: ByteString -> [ByteString] -wrongSizeCorrIds corrId = ["", B.take 4 corrId, corrId <> "x"] - testMessageNotifications :: SpecWith (ASrvTransport, AStoreType) testMessageNotifications = it "should create simplex connection, subscribe notifier and deliver notifications" $ \(ATransport t, msType) -> do