Files
simplexmq/tests/SMPProxyTests.hs
Evgeny Poberezkin a3b229f668 SMP proxy: low level client and server implementation (#1096)
* SMP proxy: low level client and server implementation

* SMP proxy: server implementation (#1098)

* wip

* PRXY command

* progress

* SMP Proxy: client-level implementation (#1101)

* buildable

* encode messages

* update pkey

* fix queue types

* wrap SEND in proxy lookup

* WIP proxy client

* WIP

* post-rebase fixes

* encode something with something

* cleanup

* update

* fix nonce/corrId in batchingTests

* WIP: dig into createSMPProxySession

* agent

* test progress

* pass the test

* parameterize transport handle with transport peer to include server certificate (#1100)

* parameterize transport handle with transport peer to include server certificate

* include server certificate into THandle

* load server chain and sign key

* fix key type

* fix for 8.10

---------

Co-authored-by: Alexander Bondarenko <486682+dpwiz@users.noreply.github.com>
Co-authored-by: IC Rainbow <aenor.realm@gmail.com>

* cleanup

* add 2-server test

* remove subsumed test

* checkCredentials for BrokerMsg

* skip batching tests

* remove userId param

* remove agent changes

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>

---------

Co-authored-by: Alexander Bondarenko <486682+dpwiz@users.noreply.github.com>

* remove unused type

* icrease test timeout

* reduce transport block

* envelope sizes

* don't fork unless have proxied commands to process

---------

Co-authored-by: Alexander Bondarenko <486682+dpwiz@users.noreply.github.com>
Co-authored-by: IC Rainbow <aenor.realm@gmail.com>
2024-04-18 22:35:17 +01:00

138 lines
6.8 KiB
Haskell

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeApplications #-}
module SMPProxyTests where
import AgentTests.FunctionalAPITests (runRight_)
import Data.ByteString.Char8 (ByteString)
import SMPAgentClient (testSMPServer, testSMPServer2)
import SMPClient
import qualified SMPClient as SMP
import ServerTests (decryptMsgV3, sendRecv)
import Simplex.Messaging.Client
import qualified Simplex.Messaging.Crypto as C
import Simplex.Messaging.Protocol
import Simplex.Messaging.Server.Env.STM (ServerConfig (..))
import Simplex.Messaging.Transport
import Simplex.Messaging.Version (mkVersionRange)
import Test.Hspec
import UnliftIO
smpProxyTests :: Spec
smpProxyTests = do
describe "server configuration" $ do
it "refuses proxy handshake unless enabled" testNoProxy
it "checks basic auth in proxy requests" testProxyAuth
describe "proxy requests" $ do
describe "bad relay URIs" $ do
xit "host not resolved" todo
xit "when SMP port blackholed" todo
xit "no SMP service at host/port" todo
xit "bad SMP fingerprint" todo
xit "batching proxy requests" todo
describe "forwarding requests" $ do
describe "deliver message via SMP proxy" $ do
it "same server" $
withSmpServerConfigOn (transport @TLS) proxyCfg testPort $ \_ -> do
let proxyServ = SMPServer SMP.testHost SMP.testPort SMP.testKeyHash
let relayServ = proxyServ
deliverMessageViaProxy proxyServ relayServ C.SEd448 "hello 1" "hello 2"
it "different servers" $
withSmpServerConfigOn (transport @TLS) proxyCfg testPort $ \_ ->
withSmpServerConfigOn (transport @TLS) cfgV7 testPort2 $ \_ -> do
let proxyServ = SMPServer SMP.testHost SMP.testPort SMP.testKeyHash
let relayServ = SMPServer SMP.testHost SMP.testPort2 SMP.testKeyHash
deliverMessageViaProxy proxyServ relayServ C.SEd448 "hello 1" "hello 2"
xit "max message size, Ed448 keys" $
withSmpServerConfigOn (transport @TLS) proxyCfg testPort $ \_ ->
withSmpServerConfigOn (transport @TLS) cfgV7 testPort2 $ \_ -> do
g <- C.newRandom
msg <- atomically $ C.randomBytes maxMessageLength g
msg' <- atomically $ C.randomBytes maxMessageLength g
let proxyServ = SMPServer SMP.testHost SMP.testPort SMP.testKeyHash
let relayServ = SMPServer SMP.testHost SMP.testPort2 SMP.testKeyHash
deliverMessageViaProxy proxyServ relayServ C.SEd448 msg msg'
it "max message size, Ed25519 keys" $
withSmpServerConfigOn (transport @TLS) proxyCfg testPort $ \_ ->
withSmpServerConfigOn (transport @TLS) cfgV7 testPort2 $ \_ -> do
g <- C.newRandom
msg <- atomically $ C.randomBytes maxMessageLength g
msg' <- atomically $ C.randomBytes maxMessageLength g
let proxyServ = SMPServer SMP.testHost SMP.testPort SMP.testKeyHash
let relayServ = SMPServer SMP.testHost SMP.testPort2 SMP.testKeyHash
deliverMessageViaProxy proxyServ relayServ C.SEd25519 msg msg'
it "max message size, X25519 keys" $
withSmpServerConfigOn (transport @TLS) proxyCfg testPort $ \_ ->
withSmpServerConfigOn (transport @TLS) cfgV7 testPort2 $ \_ -> do
g <- C.newRandom
msg <- atomically $ C.randomBytes maxMessageLength g
msg' <- atomically $ C.randomBytes maxMessageLength g
let proxyServ = SMPServer SMP.testHost SMP.testPort SMP.testKeyHash
let relayServ = SMPServer SMP.testHost SMP.testPort2 SMP.testKeyHash
deliverMessageViaProxy proxyServ relayServ C.SX25519 msg msg'
xit "sender-proxy-relay-recipient works" todo
xit "similar timing for proxied and direct sends" todo
deliverMessageViaProxy :: (C.AlgorithmI a, C.AuthAlgorithm a) => SMPServer -> SMPServer -> C.SAlgorithm a -> ByteString -> ByteString -> IO ()
deliverMessageViaProxy proxyServ relayServ alg msg msg' = do
g <- C.newRandom
-- set up proxy
Right pc <- getProtocolClient g (1, proxyServ, Nothing) defaultSMPClientConfig {serverVRange = mkVersionRange batchCmdsSMPVersion sendingProxySMPVersion} Nothing (\_ -> pure ())
THAuthClient {} <- maybe (fail "getProtocolClient returned no thAuth") pure $ thAuth $ thParams pc
-- set up relay
msgQ <- newTBQueueIO 4
Right rc <- getProtocolClient g (2, relayServ, Nothing) defaultSMPClientConfig {serverVRange = mkVersionRange batchCmdsSMPVersion authCmdsSMPVersion} (Just msgQ) (\_ -> pure ())
runRight_ $ do
-- prepare receiving queue
(rPub, rPriv) <- atomically $ C.generateAuthKeyPair alg g
(rdhPub, rdhPriv :: C.PrivateKeyX25519) <- atomically $ C.generateKeyPair g
QIK {rcvId, sndId, rcvPublicDhKey = srvDh} <- createSMPQueue rc (rPub, rPriv) rdhPub (Just "correct") SMSubscribe
let dec = decryptMsgV3 $ C.dh' srvDh rdhPriv
-- get proxy session
(sessId, v, relayKey) <- createSMPProxySession pc relayServ (Just "correct")
-- send via proxy to unsecured queue
proxySMPMessage pc sessId v relayKey Nothing sndId noMsgFlags msg
-- receive 1
(_tSess, _v, _sid, _ety, MSG RcvMessage {msgId, msgBody = EncRcvMsgBody encBody}) <- atomically $ readTBQueue msgQ
liftIO $ dec msgId encBody `shouldBe` Right msg
ackSMPMessage rc rPriv rcvId msgId
-- secure queue
(sPub, sPriv) <- atomically $ C.generateAuthKeyPair alg g
secureSMPQueue rc rPriv rcvId sPub
-- send via proxy to secured queue
proxySMPMessage pc sessId v relayKey (Just sPriv) sndId noMsgFlags msg'
-- receive 2
(_tSess, _v, _sid, _ety, MSG RcvMessage {msgId = msgId', msgBody = EncRcvMsgBody encBody'}) <- atomically $ readTBQueue msgQ
liftIO $ dec msgId' encBody' `shouldBe` Right msg'
ackSMPMessage rc rPriv rcvId msgId'
proxyVRange :: VersionRangeSMP
proxyVRange = mkVersionRange batchCmdsSMPVersion sendingProxySMPVersion
testNoProxy :: IO ()
testNoProxy = do
withSmpServerConfigOn (transport @TLS) cfg testPort2 $ \_ -> do
testSMPClient_ "127.0.0.1" testPort2 proxyVRange $ \(th :: THandleSMP TLS 'TClient) -> do
(_, _, (_corrId, _entityId, reply)) <- sendRecv th (Nothing, "0", "", PRXY testSMPServer Nothing)
reply `shouldBe` Right (ERR AUTH)
testProxyAuth :: IO ()
testProxyAuth = do
withSmpServerConfigOn (transport @TLS) proxyCfgAuth testPort $ \_ -> do
testSMPClient_ "127.0.0.1" testPort proxyVRange $ \(th :: THandleSMP TLS 'TClient) -> do
(_, _s, (_corrId, _entityId, reply)) <- sendRecv th (Nothing, "0", "", PRXY testSMPServer2 $ Just "wrong")
reply `shouldBe` Right (ERR AUTH)
where
proxyCfgAuth = proxyCfg {newQueueBasicAuth = Just "correct"}
todo :: IO ()
todo = do
fail "TODO"