From 17af5e1f47001cc0182f26613fa32e5b3d0ec22e Mon Sep 17 00:00:00 2001 From: rshiv Date: Wed, 10 Nov 2021 13:02:15 +0000 Subject: [PATCH] deploy: 939d10a519a51e31221a6a23f1a64284fad6b2e1 --- examples/v2/chat2.nim | 3 +- examples/v2/config_chat2.nim | 5 ++ examples/v2/matterbridge/chat2bridge.nim | 4 +- tests/v2/resources/test_cert.pem | 27 ++++++ tests/v2/resources/test_key.pem | 52 ++++++++++++ tests/v2/test_wakunode.nim | 103 ++++++++++++++++++++++- waku/common/wakubridge.nim | 4 +- waku/v2/node/config.nim | 15 ++++ waku/v2/node/wakunode2.nim | 49 +++++++---- waku/v2/utils/peers.nim | 6 +- waku/v2/utils/wakuswitch.nim | 50 ++++++++++- 11 files changed, 291 insertions(+), 27 deletions(-) create mode 100644 tests/v2/resources/test_cert.pem create mode 100644 tests/v2/resources/test_key.pem diff --git a/examples/v2/chat2.nim b/examples/v2/chat2.nim index f6d95af5f..fb06a5237 100644 --- a/examples/v2/chat2.nim +++ b/examples/v2/chat2.nim @@ -324,7 +324,8 @@ proc processInput(rfd: AsyncFD, rng: ref BrHmacDrbgContext) {.async.} = Port(uint16(conf.tcpPort) + conf.portsShift), extIp, extTcpPort, wsBindPort = Port(uint16(conf.websocketPort) + conf.portsShift), - wsEnabled = conf.websocketSupport) + wsEnabled = conf.websocketSupport, + wssEnabled = conf.websocketSecureSupport) await node.start() diff --git a/examples/v2/config_chat2.nim b/examples/v2/config_chat2.nim index 775776aa5..7519afcfc 100644 --- a/examples/v2/config_chat2.nim +++ b/examples/v2/config_chat2.nim @@ -225,6 +225,11 @@ type desc: "WebSocket listening port." defaultValue: 8000 name: "websocket-port" }: Port + + websocketSecureSupport* {. + desc: "WebSocket Secure Support." + defaultValue: false + name: "websocket-secure-support" }: bool # NOTE: Keys are different in nim-libp2p proc parseCmdArg*(T: type crypto.PrivateKey, p: TaintedString): T = diff --git a/examples/v2/matterbridge/chat2bridge.nim b/examples/v2/matterbridge/chat2bridge.nim index 2cee50b21..a80b36386 100644 --- a/examples/v2/matterbridge/chat2bridge.nim +++ b/examples/v2/matterbridge/chat2bridge.nim @@ -2,7 +2,7 @@ import std/[tables, times, strutils, hashes, sequtils], - chronos, confutils, chronicles, chronicles/topics_registry, + chronos, confutils, chronicles, chronicles/topics_registry, chronos/streams/tlsstream, metrics, metrics/chronos_httpserver, stew/[byteutils, endians2], stew/shims/net as stewNet, json_rpc/rpcserver, @@ -140,7 +140,7 @@ proc new*(T: type Chat2MatterBridge, nodev2BindIp: ValidIpAddress, nodev2BindPort: Port, nodev2ExtIp = none[ValidIpAddress](), nodev2ExtPort = none[Port](), contentTopic: string): T - {.raises: [Defect, ValueError, KeyError, LPError].} = + {.raises: [Defect, ValueError, KeyError, TLSStreamProtocolError, IOError, LPError].} = # Setup Matterbridge let diff --git a/tests/v2/resources/test_cert.pem b/tests/v2/resources/test_cert.pem new file mode 100644 index 000000000..9e2d2c28b --- /dev/null +++ b/tests/v2/resources/test_cert.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEpDCCAowCCQCIBoVqadPoyTANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls +b2NhbGhvc3QwHhcNMjExMTA4MTIxMjA1WhcNMjIxMTA4MTIxMjA1WjAUMRIwEAYD +VQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC4 +BlPGbbcI1Y7GHYEftahLrPsU2N5Ukx+WGcCqaP6ZQeupUESTzIyxnZ6LQ6lJcPfH +wEx9U/0RK74PscKhUfTU9iSozxD/6dUs3pYGB6Mxh9zBChwEtpTjJw0THTFh7OAa +3jyGqI/JxSzi8ylXa+vJJBu3dhKIoHnM4Qbh9vS5/8WqOQzWhm77EAEnau4TDzRh +gGAnOyBfYinyOeYIV6rV+q2Xd4SJHDm0CVd2mRGkoQaiEURcDixF2D8WZP1FXPkZ +3941BJXllCii3tzPi0UjivcRe2IJk8QyG1m/oxYOFbcV6oFNXnmYqOpFNCnp/Mjy +JlE/UGn2z2cPWauM0ALzcYMT8yE3vh7tDpQHSL+JMO6NQU/WWFi6XR7fHCIbCJRx +jjFmxO5nLO3sBtV/EonRNbi1JI+AMVVbOsbjWAyYJYnEF5fvIHp3G1ulIdA383Jj +/sar8PVfvK1GBc1EyOJE38PdOXtoFjBbyjV/acCUwk+2qoVm8cDLIjb6lLzBiASj +WcaxNFNuEF6znzJDtmdTe1X42u+igTzH4TGgjBH0AO7iD20lFYeDCdS1hUCQBdQf +AkT0rYgWNf8CiYvnSz69g7aK31RBSpqLgxSiZ0cfrIQzBno++C5UhCwOhcyUjNqh +ITrrmk1nmfAfgMQY1sEHCIsh0pAJxaomKRCVEho2IwIDAQABMA0GCSqGSIb3DQEB +CwUAA4ICAQAt5TQCtIisfUbhFCdFH5YH7e4C+CzI2iaHQWJoox2pkK/wi6z/jhyV +5eLHe/lCgBJvinMT5vwI3R2aWIsEM6I7LL83pvSY8SMLP8GRA0WPyrt71GbXuF2q +zYx5aRb6fe81YdcPEcFYKJR71/6pjhdGM/iTBqPUKgnu43UUNGu2AyrMLnp25mkK +HfG8eTYigQBMRuvGWYk8gIr2IYin9Xl1OQH5zCIfl16JfVKS1J3qKnEs0bdpChUa +oL8NbVOWP/i3+Pw62fZyIB4oaaKYl2GHIEXdGsdmBARcldKv1F5e9hdY3QwIauOP +gYjeACUqAhfw8LYrwVvAILsiN1xr4JVSj/+U9lQUAh67OwGkLEZOmEUMWl1ZCD0G +0jNPvSV91LBlr7XHIvAq9U0I4QgLinm2XhJwL4Loxn0JSOaUeZEqTb1J76YgC5Gp +D1EyWKTA6eOfBJQXBevb3jD8G+1PP7oFZ9icR+9YZT2QAbcse7fY+jfUm8nfIpmZ +1eFuPtS9dc3pozNX1VugGN/FdfReHCv2PC5a+J8srVESceF8hySbRPz15gpTkVk2 +4yRv9y/MIq8f2dCRUpYuQLmV3H9bk1s3ZInUZa0cmrdUShwjuZcEKYvZQb91MreB +WiJQ4fqWYutzI9bu/FMQQ/gU0EItLsskGxIF8StGZiK2n0zw8gtpOw== +-----END CERTIFICATE----- diff --git a/tests/v2/resources/test_key.pem b/tests/v2/resources/test_key.pem new file mode 100644 index 000000000..37f019af5 --- /dev/null +++ b/tests/v2/resources/test_key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +hColpQjmubESg8P0ERqyExMmvdP9b+s= +-----END PRIVATE KEY----- diff --git a/tests/v2/test_wakunode.nim b/tests/v2/test_wakunode.nim index f09981f4c..458c177ba 100644 --- a/tests/v2/test_wakunode.nim +++ b/tests/v2/test_wakunode.nim @@ -2,7 +2,7 @@ import testutils/unittests, - chronicles, chronos, stew/shims/net as stewNet, stew/byteutils, + chronicles, chronos, stew/shims/net as stewNet, stew/byteutils, std/os, libp2p/crypto/crypto, libp2p/crypto/secp, libp2p/peerid, @@ -27,9 +27,13 @@ when defined(rln): import ../../waku/v2/protocol/waku_rln_relay/[waku_rln_relay_utils, waku_rln_relay_types] const RLNRELAY_PUBSUB_TOPIC = "waku/2/rlnrelay/proto" +template sourceDir: string = currentSourcePath.parentDir() +const KEY_PATH = sourceDir / "resources/test_key.pem" +const CERT_PATH = sourceDir / "resources/test_cert.pem" procSuite "WakuNode": let rng = keys.newRng() + asyncTest "Message published with content filter is retrievable": let nodeKey = crypto.PrivateKey.random(Secp256k1, rng[])[] @@ -1164,4 +1168,101 @@ asyncTest "Messages relaying fails with non-overlapping transports (TCP or Webso check: (await completionFut.withTimeout(5.seconds)) == false await node1.stop() + await node2.stop() + +asyncTest "Messages are relayed between nodes with multiple transports (TCP and secure Websockets)": + let + nodeKey1 = crypto.PrivateKey.random(Secp256k1, rng[])[] + node1 = WakuNode.new(nodeKey1, ValidIpAddress.init("0.0.0.0"), + bindPort = Port(60000), wsBindPort = Port(8000), wssEnabled = true, secureKey = KEY_PATH, secureCert = CERT_PATH) + nodeKey2 = crypto.PrivateKey.random(Secp256k1, rng[])[] + node2 = WakuNode.new(nodeKey2, ValidIpAddress.init("0.0.0.0"), + bindPort = Port(60002)) + pubSubTopic = "test" + contentTopic = ContentTopic("/waku/2/default-content/proto") + payload = "hello world".toBytes() + message = WakuMessage(payload: payload, contentTopic: contentTopic) + + await node1.start() + node1.mountRelay(@[pubSubTopic]) + + await node2.start() + node2.mountRelay(@[pubSubTopic]) + + await node1.connectToNodes(@[node2.peerInfo.toRemotePeerInfo()]) + + var completionFut = newFuture[bool]() + proc relayHandler(topic: string, data: seq[byte]) {.async, gcsafe.} = + let msg = WakuMessage.init(data) + if msg.isOk(): + let val = msg.value() + check: + topic == pubSubTopic + val.contentTopic == contentTopic + val.payload == payload + completionFut.complete(true) + + node1.subscribe(pubSubTopic, relayHandler) + await sleepAsync(2000.millis) + + await node2.publish(pubSubTopic, message) + await sleepAsync(2000.millis) + + + check: + (await completionFut.withTimeout(5.seconds)) == true + await node1.stop() + await node2.stop() + +asyncTest "Messages fails with wrong key path": + let + nodeKey1 = crypto.PrivateKey.random(Secp256k1, rng[])[] + + expect IOError: + # gibberish + discard WakuNode.new(nodeKey1, ValidIpAddress.init("0.0.0.0"), + bindPort = Port(60000), wsBindPort = Port(8000), wssEnabled = true, secureKey = "../../waku/v2/node/key_dummy.txt") + +asyncTest "Messages are relayed between nodes with multiple transports (websocket and secure Websockets)": + let + nodeKey1 = crypto.PrivateKey.random(Secp256k1, rng[])[] + node1 = WakuNode.new(nodeKey1, ValidIpAddress.init("0.0.0.0"), + bindPort = Port(60000), wsBindPort = Port(8000), wssEnabled = true, secureKey = KEY_PATH, secureCert = CERT_PATH) + nodeKey2 = crypto.PrivateKey.random(Secp256k1, rng[])[] + node2 = WakuNode.new(nodeKey2, ValidIpAddress.init("0.0.0.0"), + bindPort = Port(60002),wsBindPort = Port(8100), wsEnabled = true ) + pubSubTopic = "test" + contentTopic = ContentTopic("/waku/2/default-content/proto") + payload = "hello world".toBytes() + message = WakuMessage(payload: payload, contentTopic: contentTopic) + + await node1.start() + node1.mountRelay(@[pubSubTopic]) + + await node2.start() + node2.mountRelay(@[pubSubTopic]) + + await node1.connectToNodes(@[node2.peerInfo.toRemotePeerInfo()]) + + var completionFut = newFuture[bool]() + proc relayHandler(topic: string, data: seq[byte]) {.async, gcsafe.} = + let msg = WakuMessage.init(data) + if msg.isOk(): + let val = msg.value() + check: + topic == pubSubTopic + val.contentTopic == contentTopic + val.payload == payload + completionFut.complete(true) + + node1.subscribe(pubSubTopic, relayHandler) + await sleepAsync(2000.millis) + + await node2.publish(pubSubTopic, message) + await sleepAsync(2000.millis) + + + check: + (await completionFut.withTimeout(5.seconds)) == true + await node1.stop() await node2.stop() \ No newline at end of file diff --git a/waku/common/wakubridge.nim b/waku/common/wakubridge.nim index 61d68ca4f..b134ce075 100644 --- a/waku/common/wakubridge.nim +++ b/waku/common/wakubridge.nim @@ -2,7 +2,7 @@ import std/[tables, hashes, sequtils], - chronos, confutils, chronicles, chronicles/topics_registry, + chronos, confutils, chronicles, chronicles/topics_registry, chronos/streams/tlsstream, metrics, metrics/chronos_httpserver, stew/byteutils, stew/shims/net as stewNet, json_rpc/rpcserver, @@ -150,7 +150,7 @@ proc new*(T: type WakuBridge, nodev2ExtIp = none[ValidIpAddress](), nodev2ExtPort = none[Port](), # Bridge configuration nodev2PubsubTopic: wakunode2.Topic): T - {.raises: [Defect, LPError].} = + {.raises: [Defect,IOError, TLSStreamProtocolError, LPError].} = # Setup Waku v1 node var diff --git a/waku/v2/node/config.nim b/waku/v2/node/config.nim index de176c3cb..183e06972 100644 --- a/waku/v2/node/config.nim +++ b/waku/v2/node/config.nim @@ -247,6 +247,21 @@ type desc: "WebSocket listening port." defaultValue: 8000 name: "websocket-port" }: Port + + websocketSecureSupport* {. + desc: "Enable secure websocket: true|false", + defaultValue: false + name: "websocket-secure-support"}: bool + + websocketSecureKeyPath* {. + desc: "Secure websocket key path: '/path/to/key.txt' ", + defaultValue: "" + name: "websocket-secure-key-path"}: string + + websocketSecureCertPath* {. + desc: "Secure websocket Certificate path: '/path/to/cert.txt' ", + defaultValue: "" + name: "websocket-secure-cert-path"}: string # NOTE: Keys are different in nim-libp2p proc parseCmdArg*(T: type crypto.PrivateKey, p: TaintedString): T = diff --git a/waku/v2/node/wakunode2.nim b/waku/v2/node/wakunode2.nim index 503852330..abc38d068 100644 --- a/waku/v2/node/wakunode2.nim +++ b/waku/v2/node/wakunode2.nim @@ -130,6 +130,9 @@ template tcpEndPoint(address, port): auto = template addWsFlag() = MultiAddress.init("/ws").tryGet() +template addWssFlag() = + MultiAddress.init("/wss").tryGet() + proc new*(T: type WakuNode, nodeKey: crypto.PrivateKey, bindIp: ValidIpAddress, bindPort: Port, @@ -137,8 +140,11 @@ proc new*(T: type WakuNode, nodeKey: crypto.PrivateKey, peerStorage: PeerStorage = nil, maxConnections = builders.MaxConnections, wsBindPort: Port = (Port)8000, - wsEnabled: bool = false): T - {.raises: [Defect, LPError].} = + wsEnabled: bool = false, + wssEnabled: bool = false, + secureKey: string = "", + secureCert: string = ""): T + {.raises: [Defect, LPError, IOError,TLSStreamProtocolError].} = ## Creates a Waku Node. ## ## Status: Implemented. @@ -146,11 +152,16 @@ proc new*(T: type WakuNode, nodeKey: crypto.PrivateKey, let rng = crypto.newRng() hostAddress = tcpEndPoint(bindIp, bindPort) - wsHostAddress = tcpEndPoint(bindIp, wsbindPort) & addWsFlag + wsHostAddress = if wssEnabled: tcpEndPoint(bindIp, wsbindPort) & addWssFlag + else: tcpEndPoint(bindIp, wsbindPort) & addWsFlag announcedAddresses = if extIp.isNone() or extPort.isNone(): @[] - elif wsEnabled == false: @[tcpEndPoint(extIp.get(), extPort.get())] + elif wsEnabled == false and wssEnabled == false: + @[tcpEndPoint(extIp.get(), extPort.get())] + elif wssEnabled: + @[tcpEndPoint(extIp.get(), extPort.get()), + tcpEndPoint(extIp.get(), wsBindPort) & addWssFlag] else : @[tcpEndPoint(extIp.get(), extPort.get()), - tcpEndPoint(extIp.get(), wsBindPort) & addWsFlag] + tcpEndPoint(extIp.get(), wsBindPort) & addWsFlag] peerInfo = PeerInfo.new(nodekey) enrIp = if extIp.isSome(): extIp else: some(bindIp) @@ -158,7 +169,7 @@ proc new*(T: type WakuNode, nodeKey: crypto.PrivateKey, else: some(bindPort) enr = createEnr(nodeKey, enrIp, enrTcpPort, none(Port)) - if wsEnabled == true: + if wsEnabled == true or wssEnabled == true: info "Initializing networking", hostAddress, wsHostAddress, announcedAddresses peerInfo.addrs.add(wsHostAddress) @@ -168,14 +179,17 @@ proc new*(T: type WakuNode, nodeKey: crypto.PrivateKey, peerInfo.addrs.add(hostAddress) for multiaddr in announcedAddresses: peerInfo.addrs.add(multiaddr) # Announced addresses in index > 0 - + var switch = newWakuSwitch(some(nodekey), hostAddress, wsHostAddress, transportFlags = {ServerFlags.ReuseAddr}, rng = rng, maxConnections = maxConnections, - wsEnabled = wsEnabled) + wsEnabled = wsEnabled, + wssEnabled = wssEnabled, + secureKeyPath = secureKey, + secureCertPath = secureCert) let wakuNode = WakuNode( peerManager: PeerManager.new(switch, peerStorage), @@ -923,14 +937,17 @@ when isMainModule: else: extTcpPort - - let node = WakuNode.new(conf.nodekey, - conf.listenAddress, Port(uint16(conf.tcpPort) + conf.portsShift), - extIp, extPort, - pStorage, - conf.maxConnections.int, - Port(uint16(conf.websocketPort) + conf.portsShift), - conf.websocketSupport) + node = WakuNode.new(conf.nodekey, + conf.listenAddress, Port(uint16(conf.tcpPort) + conf.portsShift), + extIp, extPort, + pStorage, + conf.maxConnections.int, + Port(uint16(conf.websocketPort) + conf.portsShift), + conf.websocketSupport, + conf.websocketSecureSupport, + conf.websocketSecureKeyPath, + conf.websocketSecureCertPath + ) if conf.discv5Discovery: let discv5UdpPort = Port(uint16(conf.discv5UdpPort) + conf.portsShift) diff --git a/waku/v2/utils/peers.nim b/waku/v2/utils/peers.nim index a0859ad6c..6e11d2df2 100644 --- a/waku/v2/utils/peers.nim +++ b/waku/v2/utils/peers.nim @@ -70,7 +70,7 @@ proc parseRemotePeerInfo*(address: string): RemotePeerInfo {.raises: [Defect, Va var - ipPart, tcpPart, p2pPart, wsPart: MultiAddress + ipPart, tcpPart, p2pPart, wsPart, wssPart: MultiAddress for addrPart in multiAddr.items(): case addrPart[].protoName()[] @@ -82,12 +82,14 @@ proc parseRemotePeerInfo*(address: string): RemotePeerInfo {.raises: [Defect, Va p2pPart = addrPart.tryGet() of "ws": wsPart = addrPart.tryGet() + of "wss": + wssPart = addrPart.tryGet() # nim-libp2p dialing requires remote peers to be initialised with a peerId and a wire address let peerIdStr = p2pPart.toString()[].split("/")[^1] - wireAddr = ipPart & tcpPart & wsPart + wireAddr = ipPart & tcpPart & wsPart & wssPart if (not wireAddr.validWireAddr()): raise newException(ValueError, "Invalid node multi-address") diff --git a/waku/v2/utils/wakuswitch.nim b/waku/v2/utils/wakuswitch.nim index ce5e2c896..ab369b8fa 100644 --- a/waku/v2/utils/wakuswitch.nim +++ b/waku/v2/utils/wakuswitch.nim @@ -1,6 +1,7 @@ # Waku Switch utils. +{.push raises: [TLSStreamProtocolError, IOError, Defect].} import - std/[options, sequtils], + std/[options, sequtils, strutils], chronos, chronicles, stew/byteutils, eth/keys, @@ -14,6 +15,40 @@ import proc withWsTransport*(b: SwitchBuilder): SwitchBuilder = b.withTransport(proc(upgr: Upgrade): Transport = WsTransport.new(upgr)) +proc getSecureKey(path : string): TLSPrivateKey + {.raises: [Defect,TLSStreamProtocolError, IOError].} = + trace "Key path is.", path=path + var stringkey: string = readFile(path) + try: + let key = TLSPrivateKey.init(stringkey) + return key + except: + raise newException(TLSStreamProtocolError,"Secure key init failed") + + + +proc getSecureCert(path : string): TLSCertificate + {.raises: [Defect,TLSStreamProtocolError, IOError].} = + trace "Certificate path is.", path=path + var stringCert: string = readFile(path) + try: + let cert = TLSCertificate.init(stringCert) + return cert + except: + raise newException(TLSStreamProtocolError,"Certificate init failed") + +proc withWssTransport*(b: SwitchBuilder, + secureKeyPath: string, + secureCertPath: string): SwitchBuilder = + let key : TLSPrivateKey = getSecureKey(secureKeyPath) + let cert : TLSCertificate = getSecureCert(secureCertPath) + b.withTransport(proc(upgr: Upgrade): Transport = WsTransport.new(upgr, + tlsPrivateKey = key, + tlsCertificate = cert, + {TLSFlags.NoVerifyHost, TLSFlags.NoVerifyServerName})) + + + proc newWakuSwitch*( privKey = none(crypto.PrivateKey), address = MultiAddress.init("/ip4/127.0.0.1/tcp/0").tryGet(), @@ -30,8 +65,14 @@ proc newWakuSwitch*( maxOut = -1, maxConnsPerPeer = MaxConnectionsPerPeer, nameResolver: NameResolver = nil, - wsEnabled: bool = false): Switch - {.raises: [Defect, LPError].} = + wsEnabled: bool = false, + wssEnabled: bool = false, + secureKeyPath: string = "", + secureCertPath: string = ""): Switch + {.raises: [Defect,TLSStreamProtocolError,IOError, LPError].} = + + if wsEnabled == true and wssEnabled == true: + debug "Websocket and secure websocket are enabled simultaneously." var b = SwitchBuilder .new() @@ -49,6 +90,9 @@ proc newWakuSwitch*( if wsEnabled == true: b = b.withAddresses(@[wsAddress, address]) b = b.withWsTransport() + if wssEnabled == true: + b = b.withAddresses(@[wsAddress, address]) + b = b.withWssTransport(secureKeyPath, secureCertPath) else : b = b.withAddress(address)