diff --git a/bindings/channels.go b/bindings/channels.go index e956d8aded98be8a5f00cdcf9b2c8a37d180f716..1fc12dbb2414bb8dc0f097cb64b7c3c1212fdc0d 100644 --- a/bindings/channels.go +++ b/bindings/channels.go @@ -355,7 +355,7 @@ func LoadChannelsManager(cmixID int, storageTag string, // // Example JSON: // { -// "Channel": "\u003cSpeakeasy-v1:My_Channel,description:Here is information about my channel.,level:Public,secrets:8AS3SczFvAYZftWuj4ZkOM9muFPIwq/0HuVCUJgTK8w=,GpPl1510/G07J4RfdYX9J5plTX3WNLVm+uuGmCwgFeU=,5,1,mRfdUGM6WxWjjCuLzO+2+zc3BQh2zMT2CHD8ZnBwpVI=\u003e", +// "Channel": "\u003cSpeakeasy-v2:Test_Channel|description:Channel description.|level:Public|secrets:8AS3SczFvAYZftWuj4ZkOM9muFPIwq/0HuVCUJgTK8w=|GpPl1510/G07J4RfdYX9J5plTX3WNLVm+uuGmCwgFeU=|5|1|mRfdUGM6WxWjjCuLzO+2+zc3BQh2zMT2CHD8ZnBwpVI=\u003e", // "PrivateKey": "-----BEGIN RSA PRIVATE KEY-----\nMDECAQACBgDMIU9LpQIDAQABAgYAvCd9ewECAw0tzQIDD305AgMFu4UCAwd+kQID\nAQxc\n-----END RSA PRIVATE KEY-----" // } type ChannelGeneration struct { @@ -454,6 +454,74 @@ func makeChannelPrivateKeyStoreKey(channelID *id.ID) string { return channelPrivateKeyStoreKey + "/" + channelID.String() } +// DecodePublicURL decodes the channel URL into a channel pretty print. This +// function can only be used for public channel URLs. To get the privacy level +// of a channel URL, use [GetShareUrlType]. +// +// Parameters: +// - url - The channel's share URL. Should be received from another user or +// generated via [GetShareURL]. +// +// Returns: +// - The channel pretty print. +func DecodePublicURL(url string) (string, error) { + c, err := cryptoBroadcast.DecodeShareURL(url, "") + if err != nil { + return "", err + } + + return c.PrettyPrint(), nil +} + +// DecodePrivateURL decodes the channel URL, using the password, into a channel +// pretty print. This function can only be used for private or secret channel +// URLs. To get the privacy level of a channel URL, use [GetShareUrlType]. +// +// Parameters: +// - url - The channel's share URL. Should be received from another user or +// generated via [GetShareURL]. +// - password - The password needed to decrypt the secret data in the URL. +// +// Returns: +// - The channel pretty print. +func DecodePrivateURL(url, password string) (string, error) { + c, err := cryptoBroadcast.DecodeShareURL(url, password) + if err != nil { + return "", err + } + + return c.PrettyPrint(), nil +} + +// GetChannelJSON returns the JSON of the channel for the given pretty print. +// +// Parameters: +// - prettyPrint - The pretty print of the channel. +// +// Returns: +// - JSON of the [broadcast.Channel] object. +// +// Example JSON of [broadcast.Channel]: +// { +// "ReceptionID": "Ja/+Jh+1IXZYUOn+IzE3Fw/VqHOscomD0Q35p4Ai//kD", +// "Name": "My_Channel", +// "Description": "Here is information about my channel.", +// "Salt": "+tlrU/htO6rrV3UFDfpQALUiuelFZ+Cw9eZCwqRHk+g=", +// "RsaPubKeyHash": "PViT1mYkGBj6AYmE803O2RpA7BX24EjgBdldu3pIm4o=", +// "RsaPubKeyLength": 5, +// "RSASubPayloads": 1, +// "Secret": "JxZt/wPx2luoPdHY6jwbXqNlKnixVU/oa9DgypZOuyI=", +// "Level": 0 +// } +func GetChannelJSON(prettyPrint string) ([]byte, error) { + c, err := cryptoBroadcast.NewChannelFromPrettyPrint(prettyPrint) + if err != nil { + return nil, nil + } + + return json.Marshal(c) +} + // ChannelInfo contains information about a channel. // // Example of ChannelInfo JSON: @@ -474,7 +542,7 @@ type ChannelInfo struct { // - prettyPrint - The pretty print of the channel. // // The pretty print will be of the format: -// <Speakeasy-v1:Test Channel,description:This is a test channel,secrets:YxHhRAKy2D4XU2oW5xnW/3yaqOeh8nO+ZSd3nUmiQ3c=,6pXN2H9FXcOj7pjJIZoq6nMi4tGX2s53fWH5ze2dU1g=,493,1,MVjkHlm0JuPxQNAn6WHsPdOw9M/BUF39p7XB/QEkQyc=> +// <Speakeasy-v2:Test_Channel|description:Channel description.|level:Public|secrets:+oHcqDbJPZaT3xD5NcdLY8OjOMtSQNKdKgLPmr7ugdU=|rCI0wr01dHFStjSFMvsBzFZClvDIrHLL5xbCOPaUOJ0=|493|1|7cBhJxVfQxWo+DypOISRpeWdQBhuQpAZtUbQHjBm8NQ=> // // Returns: // - []byte - JSON of [ChannelInfo], which describes all relevant channel info. @@ -508,7 +576,7 @@ func getChannelInfo(prettyPrint string) (*cryptoBroadcast.Channel, []byte, error // another user or generated via GenerateChannel. // // The pretty print will be of the format: -// <Speakeasy-v1:Test Channel,description:This is a test channel,secrets:YxHhRAKy2D4XU2oW5xnW/3yaqOeh8nO+ZSd3nUmiQ3c=,6pXN2H9FXcOj7pjJIZoq6nMi4tGX2s53fWH5ze2dU1g=,493,1,MVjkHlm0JuPxQNAn6WHsPdOw9M/BUF39p7XB/QEkQyc=> +// <Speakeasy-v2:Test_Channel|description:Channel description.|level:Public|secrets:+oHcqDbJPZaT3xD5NcdLY8OjOMtSQNKdKgLPmr7ugdU=|rCI0wr01dHFStjSFMvsBzFZClvDIrHLL5xbCOPaUOJ0=|493|1|7cBhJxVfQxWo+DypOISRpeWdQBhuQpAZtUbQHjBm8NQ=> // // Returns: // - []byte - JSON of [ChannelInfo], which describes all relevant channel info. @@ -524,40 +592,6 @@ func (cm *ChannelsManager) JoinChannel(channelPretty string) ([]byte, error) { return info, err } -// JoinChannelFromURL joins the given channel from a URL. It will fail if the -// channel has already been joined. A password is required unless it is of the -// privacy level [broadcast.Public], in which case it can be left empty. To get -// the privacy level of a channel URL, use [GetShareUrlType]. -// -// Parameters: -// - url - The channel's share URL. Should be received from another user or -// generated via [GetShareURL]. -// - password - The password needed to decrypt the secret data in the URL. Only -// required for private or secret channels. -// -// Returns: -// - []byte - [ChannelInfo] describes all relevant channel info. -func (cm *ChannelsManager) JoinChannelFromURL(url, password string) ([]byte, error) { - c, err := cryptoBroadcast.DecodeShareURL(url, password) - if err != nil { - return nil, err - } - - info, err := json.Marshal(&ChannelInfo{ - Name: c.Name, - Description: c.Description, - ChannelID: c.ReceptionID.String(), - }) - if err != nil { - return nil, err - } - - // Join the channel using the API - err = cm.api.JoinChannel(c) - - return info, err -} - // GetChannels returns the IDs of all channels that have been joined. // // Returns: diff --git a/channels/manager.go b/channels/manager.go index d4159c5c12e8fc73b837953f043b83b2e1dd4052..5517ffa9bb147bb403a8b6a02e9afe3ed2e35fb7 100644 --- a/channels/manager.go +++ b/channels/manager.go @@ -191,6 +191,8 @@ func (m *manager) GetChannel(chID *id.ID) (*cryptoBroadcast.Channel, error) { jc, err := m.getChannel(chID) if err != nil { return nil, err + } else if jc.broadcast == nil { + return nil, errors.New("broadcast.Channel on joinedChannel is nil") } return jc.broadcast.Get(), nil } diff --git a/channels/sendTracker.go b/channels/sendTracker.go index 023785fa7f4063b6dc30e509419cd79f7978fab4..437340a518d723591701fcf9296af96576b10c75 100644 --- a/channels/sendTracker.go +++ b/channels/sendTracker.go @@ -106,7 +106,7 @@ func loadSendTracker(net Client, kv *versioned.KV, trigger triggerEventFunc, st.unsent = make(map[uint64]*tracked) //register to check all outstanding rounds when the network becomes healthy - /*var callBackID uint64 + var callBackID uint64 callBackID = net.AddHealthCallback(func(f bool) { if !f { return @@ -120,7 +120,7 @@ func loadSendTracker(net Client, kv *versioned.KV, trigger triggerEventFunc, } st.net.GetRoundResults(getRoundResultsTimeout, rr.callback, rr.round) } - })*/ + }) return st } @@ -337,19 +337,19 @@ func (st *sendTracker) handleSend(uuid uint64, t.RoundID = round.ID //add the roundID - roundsList, _ := st.byRound[round.ID] + roundsList, existsRound := st.byRound[round.ID] st.byRound[round.ID] = append(roundsList, t) //add the round st.byMessageID[messageID] = t - /*if !existsRound { + if !existsRound { rr := &roundResults{ round: round.ID, st: st, } st.net.GetRoundResults(getRoundResultsTimeout, rr.callback, rr.round) - }*/ + } delete(st.unsent, uuid) @@ -486,12 +486,11 @@ func (rr *roundResults) callback(allRoundsSucceeded, timedOut bool, results map[ } rr.st.mux.Unlock() - - for i := range registered { - round := results[rr.round].Round - ts := mutateTimestamp(round.Timestamps[states.QUEUED], registered[i].MsgID) - go rr.st.updateStatus(registered[i].UUID, registered[i].MsgID, ts, - round, status) + if status == Failed { + for i := range registered { + round := results[rr.round].Round + go rr.st.updateStatus(registered[i].UUID, registered[i].MsgID, time.Time{}, + round, Failed) + } } - } diff --git a/cmix/follow.go b/cmix/follow.go index 7e75082ce0df42dd33860e1d3e65d4092de7096e..8e4dd03080c757aeca1d482d0e34660b65ab7924 100644 --- a/cmix/follow.go +++ b/cmix/follow.go @@ -87,7 +87,6 @@ func (c *client) followNetwork(report ClientErrorReport, stop.ToStopped() return case <-ticker.C: - operator := func(toTrack []receptionID.IdentityUse) error { // set up tracking tools diff --git a/cmix/gateway/hostPool.go b/cmix/gateway/hostPool.go index 3c5582fbadb560c485b76c77be9cda353b40d835..d39e71596ef644a444f5cd6056e97e9a10ea3f39 100644 --- a/cmix/gateway/hostPool.go +++ b/cmix/gateway/hostPool.go @@ -48,6 +48,7 @@ var errorsList = []string{ "Host is in cool down", grpc.ErrClientConnClosing.Error(), connect.TooManyProxyError, + "Failed to fetch", } // HostManager Interface allowing storage and retrieval of Host objects @@ -127,7 +128,7 @@ type poolParamsDisk struct { // DefaultPoolParams returns a default set of PoolParams. func DefaultPoolParams() PoolParams { p := PoolParams{ - MaxPoolSize: 30, + MaxPoolSize: 5, ProxyAttempts: 5, PoolSize: 0, MaxPings: 0, diff --git a/cmix/nodes/register.go b/cmix/nodes/register.go index 5d2249ec617e7d39af16bcdd58cc0bd0d7879558..8cada7d120e663cf9ef075d11fe72c3c409c7859 100644 --- a/cmix/nodes/register.go +++ b/cmix/nodes/register.go @@ -134,6 +134,8 @@ func registerWithNode(sender gateway.Sender, comms RegisterNodeCommsInterface, var transmissionKey *cyclic.Int var validUntil uint64 var keyId []byte + + start := time.Now() // TODO: should move this to a pre-canned user initialization if s.IsPrecanned() { userNum := int(s.GetTransmissionID().Bytes()[7]) @@ -156,7 +158,8 @@ func registerWithNode(sender gateway.Sender, comms RegisterNodeCommsInterface, r.add(nodeID, transmissionKey, validUntil, keyId) - jww.INFO.Printf("Completed registration with node %s", nodeID) + jww.INFO.Printf("Completed registration with node %s,"+ + " took %d", nodeID, time.Since(start)) return nil } diff --git a/cmix/nodes/registrar.go b/cmix/nodes/registrar.go index dc61852f183937b5f4f9eadcda2cdfacd28d20a9..5ca5f108d201de75fcb739c43ea1bf2cea24951b 100644 --- a/cmix/nodes/registrar.go +++ b/cmix/nodes/registrar.go @@ -24,15 +24,15 @@ import ( ) const InputChanLen = 1000 -const maxAttempts = 5 +const maxAttempts = 2 // Backoff for attempting to register with a cMix node. var delayTable = [5]time.Duration{ 0, - 5 * time.Second, 30 * time.Second, 60 * time.Second, 120 * time.Second, + 240 * time.Second, } // registrar is an implementation of the Registrar interface. diff --git a/cmix/nodes/request.go b/cmix/nodes/request.go index 281b9a1190d42e06422473269761ecef94b3a8c0..abee1dfff97fb6621bc7079635332de833f82e00 100644 --- a/cmix/nodes/request.go +++ b/cmix/nodes/request.go @@ -9,6 +9,7 @@ package nodes import ( "io" + "time" "github.com/golang/protobuf/proto" "github.com/pkg/errors" @@ -26,7 +27,6 @@ import ( "gitlab.com/xx_network/crypto/chacha" "gitlab.com/xx_network/crypto/csprng" "gitlab.com/xx_network/crypto/signature/rsa" - "gitlab.com/xx_network/crypto/tls" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/netTime" ) @@ -42,9 +42,9 @@ func requestKey(sender gateway.Sender, comms RegisterNodeCommsInterface, // Generate a Diffie-Hellman keypair grp := r.session.GetCmixGroup() + start := time.Now() prime := grp.GetPBytes() - keyLen := len(prime) - dhPrivBytes, err := csprng.GenerateInGroup(prime, keyLen, rng) + dhPrivBytes, err := csprng.GenerateInGroup(prime, 32, rng) if err != nil { return nil, nil, 0, err } @@ -67,9 +67,11 @@ func requestKey(sender gateway.Sender, comms RegisterNodeCommsInterface, // Request nonce message from gateway jww.INFO.Printf("Register: Requesting client key from "+ - "gateway %s", gatewayID) + "gateway %s, setup took %s", gatewayID, time.Since(start)) + start = time.Now() result, err := sender.SendToAny(func(host *connect.Host) (interface{}, error) { + startInternal := time.Now() keyResponse, err2 := comms.SendRequestClientKeyMessage(host, signedKeyReq) if err2 != nil { return nil, errors.WithMessagef(err2, @@ -79,9 +81,11 @@ func requestKey(sender gateway.Sender, comms RegisterNodeCommsInterface, return nil, errors.WithMessage(err2, "requestKey: clientKeyResponse error") } + jww.TRACE.Printf("just comm reg request took %s", time.Since(startInternal)) return keyResponse, nil }, stop) + jww.TRACE.Printf("full reg request took %s", time.Since(start)) if err != nil { return nil, nil, 0, err @@ -170,22 +174,8 @@ func processRequestResponse(signedKeyResponse *pb.SignedKeyResponse, h.Write(signedKeyResponse.KeyResponse) hashedResponse := h.Sum(nil) - // Load nodes certificate - gatewayCert, err := tls.LoadCertificate(ngw.Gateway.TlsCertificate) - if err != nil { - return nil, nil, 0, - errors.Errorf("Unable to load nodes's certificate: %+v", err) - } - - // Extract public key - nodePubKey, err := tls.ExtractPublicKey(gatewayCert) - if err != nil { - return nil, nil, 0, - errors.Errorf("Unable to load node's public key: %v", err) - } - // Verify the response signature - err = verifyNodeSignature(nodePubKey, opts.Hash, hashedResponse, + err := verifyNodeSignature(ngw.Gateway.TlsCertificate, opts.Hash, hashedResponse, signedKeyResponse.KeyResponseSignedByGateway.Signature, opts) if err != nil { return nil, nil, 0, @@ -203,11 +193,14 @@ func processRequestResponse(signedKeyResponse *pb.SignedKeyResponse, // Convert Node DH Public key to a cyclic.Int nodeDHPub := grp.NewIntFromBytes(keyResponse.NodeDHPubKey) + start := time.Now() // Construct the session key h.Reset() sessionKey := registration.GenerateBaseKey(grp, nodeDHPub, dhPrivKey, h) + jww.TRACE.Printf("DH for reg took %s", time.Since(start)) + // Verify the HMAC if !registration.VerifyClientHMAC(sessionKey.Bytes(), keyResponse.EncryptedClientKey, opts.Hash.New, diff --git a/cmix/nodes/verifyNodeSig.go b/cmix/nodes/verifyNodeSig.go index 5fff372159890c1228e8c2e340dac68302a14f80..55ae44c551fceffc76c170ee213d3e7b7db3dc8b 100644 --- a/cmix/nodes/verifyNodeSig.go +++ b/cmix/nodes/verifyNodeSig.go @@ -11,12 +11,27 @@ package nodes import ( "crypto" + "github.com/pkg/errors" + "gitlab.com/xx_network/crypto/tls" "gitlab.com/xx_network/crypto/signature/rsa" ) -func verifyNodeSignature(pub *rsa.PublicKey, hash crypto.Hash, +func verifyNodeSignature(certContents string, hash crypto.Hash, hashed []byte, sig []byte, opts *rsa.Options) error { + + // Load nodes certificate + gatewayCert, err := tls.LoadCertificate(certContents) + if err != nil { + return errors.Errorf("Unable to load nodes's certificate: %+v", err) + } + + // Extract public key + nodePubKey, err := tls.ExtractPublicKey(gatewayCert) + if err != nil { + return errors.Errorf("Unable to load node's public key: %v", err) + } + // Verify the response signature - return rsa.Verify(pub, hash, hashed, sig, opts) + return rsa.Verify(nodePubKey, hash, hashed, sig, opts) } diff --git a/cmix/nodes/verifyNodeSig_js.go b/cmix/nodes/verifyNodeSig_js.go index 79b35ef789f4c263b88bdb2ee7853cb5a11ba80d..6bc339bd38273160ce8a13515225c944d2d7f3a8 100644 --- a/cmix/nodes/verifyNodeSig_js.go +++ b/cmix/nodes/verifyNodeSig_js.go @@ -16,7 +16,7 @@ import ( "gitlab.com/xx_network/crypto/signature/rsa" ) -func verifyNodeSignature(pub *rsa.PublicKey, hash crypto.Hash, +func verifyNodeSignature(pub string, hash crypto.Hash, hashed []byte, sig []byte, opts *rsa.Options) error { jww.WARN.Printf("node signature checking disabled for wasm") return nil diff --git a/fileTransfer/store/received.go b/fileTransfer/store/received.go index 189025a711b89537022a99ec72d19eaf98e63c91..6ec51f2e0188bc4d1ab05b7ec2c2ee044588951c 100644 --- a/fileTransfer/store/received.go +++ b/fileTransfer/store/received.go @@ -100,7 +100,7 @@ func (r *Received) AddTransfer(key *ftCrypto.TransferKey, _, exists := r.transfers[*tid] if exists { - return nil, errors.Errorf(errAddExistingReceivedTransfer, tid) + return nil, errors.Errorf(errAddExistingReceivedTransfer, *tid) } rt, err := newReceivedTransfer( diff --git a/fileTransfer/store/sent.go b/fileTransfer/store/sent.go index a7f89a598dd79ec14b421b0101d0dae5ab7e05cf..d5e22ad8e976bb7d21c7e5e0c100496c19b363b3 100644 --- a/fileTransfer/store/sent.go +++ b/fileTransfer/store/sent.go @@ -108,7 +108,7 @@ func (s *Sent) AddTransfer(recipient *id.ID, key *ftCrypto.TransferKey, _, exists := s.transfers[*tid] if exists { - return nil, errors.Errorf(errAddExistingSentTransfer, tid) + return nil, errors.Errorf(errAddExistingSentTransfer, *tid) } st, err := newSentTransfer( diff --git a/go.mod b/go.mod index 7e4bb2b4cf97cd3fffa7a1adbd190662c9d5f96f..93c725381b1893a1929c179ade479613ecb73dce 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/stretchr/testify v1.8.0 gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f gitlab.com/elixxir/comms v0.0.4-0.20221017173926-4eaa6061dfaa - gitlab.com/elixxir/crypto v0.0.7-0.20221021185743-d26832a1197a + gitlab.com/elixxir/crypto v0.0.7-0.20221022003355-d8a6158b32a7 gitlab.com/elixxir/ekv v0.2.1 gitlab.com/elixxir/primitives v0.0.3-0.20221017172918-6176818d1aba gitlab.com/xx_network/comms v0.0.4-0.20221017172508-09e33697dc15 diff --git a/go.sum b/go.sum index 1100c0e9d8b109cb703decf229acaeeaa4773217..8514c15d109db684ab1bd8a4a276ef897135b40d 100644 --- a/go.sum +++ b/go.sum @@ -636,10 +636,8 @@ gitlab.com/elixxir/comms v0.0.4-0.20221017173926-4eaa6061dfaa/go.mod h1:rW7xdbHn gitlab.com/elixxir/crypto v0.0.0-20200804182833-984246dea2c4/go.mod h1:ucm9SFKJo+K0N2GwRRpaNr+tKXMIOVWzmyUD0SbOu2c= gitlab.com/elixxir/crypto v0.0.3/go.mod h1:ZNgBOblhYToR4m8tj4cMvJ9UsJAUKq+p0gCp07WQmhA= gitlab.com/elixxir/crypto v0.0.7-0.20221017173452-565da4101a3b/go.mod h1:1rftbwSVdy49LkBIkPr+w+P2mDOerYeBKoZuB3r0yqI= -gitlab.com/elixxir/crypto v0.0.7-0.20221017204335-9201b3672f3a h1:RxobrpD5owwdyNg5KTqBINJ8z0zsXsbu+UhMEC80wIE= -gitlab.com/elixxir/crypto v0.0.7-0.20221017204335-9201b3672f3a/go.mod h1:1rftbwSVdy49LkBIkPr+w+P2mDOerYeBKoZuB3r0yqI= -gitlab.com/elixxir/crypto v0.0.7-0.20221021185743-d26832a1197a h1:niF6yQflBFYXKl95pJLMWQCmwH2D29lovZlTqoAzbEY= -gitlab.com/elixxir/crypto v0.0.7-0.20221021185743-d26832a1197a/go.mod h1:1rftbwSVdy49LkBIkPr+w+P2mDOerYeBKoZuB3r0yqI= +gitlab.com/elixxir/crypto v0.0.7-0.20221022003355-d8a6158b32a7 h1:+8DHBxZxJcmJSmcUFK4ZjjXgwV3wSo9O4+4NCaLdO4c= +gitlab.com/elixxir/crypto v0.0.7-0.20221022003355-d8a6158b32a7/go.mod h1:P/S3pEPYl7fuHQ1m4mL2pIaCxAjYIXrJml/pnfofI+U= gitlab.com/elixxir/ekv v0.2.1 h1:dtwbt6KmAXG2Tik5d60iDz2fLhoFBgWwST03p7T+9Is= gitlab.com/elixxir/ekv v0.2.1/go.mod h1:USLD7xeDnuZEavygdrgzNEwZXeLQJK/w1a+htpN+JEU= gitlab.com/elixxir/primitives v0.0.0-20200731184040-494269b53b4d/go.mod h1:OQgUZq7SjnE0b+8+iIAT2eqQF+2IFHn73tOo+aV11mg=