diff --git a/network/nodes/mixCypher.go b/network/nodes/mixCypher.go index 5f498b770d64f662f6fb446a2150ce93cd42a6b9..c94b8007394c388c0423cada55cf7fdb7e0fbc2e 100644 --- a/network/nodes/mixCypher.go +++ b/network/nodes/mixCypher.go @@ -27,8 +27,8 @@ type mixCypher struct { g *cyclic.Group } -// Encrypts the given message for CMIX -// Panics if the passed message is not sized correctly for the group +// Encrypt encrypts the given message for CMIX. +// Panics if the passed message is not sized correctly for the group. func (mc *mixCypher) Encrypt(msg format.Message, salt []byte, roundID id.Round) (format.Message, [][]byte) { @@ -48,7 +48,7 @@ func (mc *mixCypher) Encrypt(msg format.Message, h, err := hash.NewCMixHash() if err != nil { - jww.FATAL.Panicf("Cound not get hash for KMAC generation: %+v", h) + jww.FATAL.Panicf("Could not get hash for KMAC generation: %+v", h) } KMAC := cmix.GenerateKMACs(salt, keys, roundID, h) @@ -72,13 +72,13 @@ func clientEncrypt(grp *cyclic.Group, msg format.Message, salt []byte, roundID id.Round, baseKeys []*cyclic.Int) format.Message { // get the salt for associated data - hash, err := blake2b.New256(nil) + h, err := blake2b.New256(nil) if err != nil { panic("E2E Client Encrypt could not get blake2b Hash") } - hash.Reset() - hash.Write(salt) - salt2 := hash.Sum(nil) + h.Reset() + h.Write(salt) + salt2 := h.Sum(nil) // get encryption keys keyEcrA := cmix.ClientKeyGen(grp, salt, roundID, baseKeys) diff --git a/network/nodes/mixCypher_test.go b/network/nodes/mixCypher_test.go index 7802f42f973dcd8c10a76f3af6b064c03a5986ea..12b65210b2207586182007ac312f7061fcf361fd 100644 --- a/network/nodes/mixCypher_test.go +++ b/network/nodes/mixCypher_test.go @@ -19,7 +19,7 @@ import ( "testing" ) -// tests that the encrypted paylaods and kmacs generated are consistent +// Tests that the encrypted payloads and KMACs generated are consistent. func TestRoundKeys_Encrypt_Consistency(t *testing.T) { const numKeys = 5 @@ -111,7 +111,7 @@ func TestRoundKeys_Encrypt_Consistency(t *testing.T) { prng.Read(contents) msg.SetContents(contents) - rk := MixCypher{ + rk := mixCypher{ keys: keys, g: cmixGrp, } diff --git a/network/nodes/register.go b/network/nodes/register.go index 7025e7bb831bae17463d1ea683c60070391551e3..f8b39356d25609566053c1eec7e18694ce46523b 100644 --- a/network/nodes/register.go +++ b/network/nodes/register.go @@ -56,19 +56,21 @@ func registerNodes(r *registrar, stop *stoppable.Single, inProgress, attempts *s nidStr := fmt.Sprintf("%x", gw.Node.ID) nid, err := gw.Node.GetNodeId() if err != nil { - jww.WARN.Printf("Could not process node ID for registration: %s", err) + jww.WARN.Printf( + "Could not process node ID for registration: %s", err) continue } if r.Has(nid) { - jww.INFO.Printf("not registering node %s, already registered", nid) + jww.INFO.Printf( + "Not registering node %s, already registered", nid) } if _, operating := inProgress.LoadOrStore(nidStr, struct{}{}); operating { continue } - //keep track of how many times this has been attempted + // Keep track of how many times this has been attempted numAttempts := uint(1) if nunAttemptsInterface, hasValue := attempts.LoadOrStore(nidStr, numAttempts); hasValue { numAttempts = nunAttemptsInterface.(uint) @@ -85,10 +87,11 @@ func registerNodes(r *registrar, stop *stoppable.Single, inProgress, attempts *s inProgress.Delete(nidStr) if err != nil { jww.ERROR.Printf("Failed to register nodes: %+v", err) - //if we have not reached the attempt limit for this gateway, send it back into the channel to retry + // If we have not reached the attempt limit for this gateway, + // then send it back into the channel to retry if numAttempts < maxAttempts { go func() { - //delay the send for a backoff + // Delay the send for a backoff time.Sleep(delayTable[numAttempts-1]) r.c <- gw }() @@ -100,8 +103,8 @@ func registerNodes(r *registrar, stop *stoppable.Single, inProgress, attempts *s } } -//registerWithNode serves as a helper for RegisterWithNodes -// It registers a user with a specific in the client's ndf. +// registerWithNode serves as a helper for RegisterWithNodes. +// It registers a user with a specific in the client's NDF. func registerWithNode(sender *gateway.Sender, comms RegisterNodeCommsInterface, ngw network.NodeGateway, regSig []byte, registrationTimestampNano int64, uci *user.CryptographicIdentity, r *registrar, rng csprng.Source, @@ -133,8 +136,8 @@ func registerWithNode(sender *gateway.Sender, comms RegisterNodeCommsInterface, jww.INFO.Printf("transmissionKey: %v", transmissionKey.Bytes()) } else { // Request key from server - transmissionKey, keyId, validUntil, err = requestKey(sender, comms, ngw, regSig, - registrationTimestampNano, uci, r, rng, stop) + transmissionKey, keyId, validUntil, err = requestKey(sender, comms, ngw, + regSig, registrationTimestampNano, uci, r, rng, stop) if err != nil { return errors.Errorf("Failed to request key: %+v", err) @@ -156,9 +159,9 @@ func requestKey(sender *gateway.Sender, comms RegisterNodeCommsInterface, grp := r.session.GetCmixGroup() - // FIXME: Why 256 bits? -- this is spec but not explained, it has - // to do with optimizing operations on one side and still preserves - // decent security -- cite this. + // FIXME: Why 256 bits? -- this is spec but not explained, it has to do with + // optimizing operations on one side and still preserves decent security -- + // cite this. dhPrivBytes, err := csprng.GenerateInGroup(grp.GetPBytes(), 256, rng) if err != nil { return nil, nil, 0, err @@ -170,7 +173,10 @@ func requestKey(sender *gateway.Sender, comms RegisterNodeCommsInterface, // Reconstruct client confirmation message userPubKeyRSA := rsa.CreatePublicKeyPem(uci.GetTransmissionRSA().GetPublic()) - confirmation := &pb.ClientRegistrationConfirmation{RSAPubKey: string(userPubKeyRSA), Timestamp: registrationTimestampNano} + confirmation := &pb.ClientRegistrationConfirmation{ + RSAPubKey: string(userPubKeyRSA), + Timestamp: registrationTimestampNano, + } confirmationSerialized, err := proto.Marshal(confirmation) if err != nil { return nil, nil, 0, err @@ -205,15 +211,15 @@ func requestKey(sender *gateway.Sender, comms RegisterNodeCommsInterface, return nil, nil, 0, err } - gwid := ngw.Gateway.ID - gatewayID, err := id.Unmarshal(gwid) + gwId := ngw.Gateway.ID + gatewayID, err := id.Unmarshal(gwId) if err != nil { jww.ERROR.Println("registerWithNode() failed to decode gatewayID") return nil, nil, 0, err } // Request nonce message from gateway - jww.INFO.Printf("Register: Requesting client key from gateway %v", gatewayID.String()) + jww.INFO.Printf("Register: Requesting client key from gateway %s", gatewayID) result, err := sender.SendToAny(func(host *connect.Host) (interface{}, error) { keyResponse, err := comms.SendRequestClientKeyMessage(host, @@ -223,10 +229,12 @@ func requestKey(sender *gateway.Sender, comms RegisterNodeCommsInterface, Target: gatewayID.Bytes(), }) if err != nil { - return nil, errors.WithMessage(err, "Register: Failed requesting client key from gateway") + return nil, errors.WithMessage(err, + "Register: Failed requesting client key from gateway") } if keyResponse.Error != "" { - return nil, errors.WithMessage(err, "requestKey: clientKeyResponse error") + return nil, errors.WithMessage(err, + "requestKey: clientKeyResponse error") } return keyResponse, nil }, stop) @@ -248,27 +256,31 @@ func requestKey(sender *gateway.Sender, comms RegisterNodeCommsInterface, // Load nodes certificate gatewayCert, err := tls.LoadCertificate(ngw.Gateway.TlsCertificate) if err != nil { - return nil, nil, 0, errors.WithMessagef(err, "Unable to load nodes's certificate") + return nil, nil, 0, + errors.WithMessagef(err, "Unable to load nodes's certificate") } // Extract public key nodePubKey, err := tls.ExtractPublicKey(gatewayCert) if err != nil { - return nil, nil, 0, errors.WithMessagef(err, "Unable to load nodes's public key") + return nil, nil, 0, + errors.WithMessagef(err, "Unable to load node's public key") } // Verify the response signature err = rsa.Verify(nodePubKey, opts.Hash, hashedResponse, signedKeyResponse.KeyResponseSignedByGateway.Signature, opts) if err != nil { - return nil, nil, 0, errors.WithMessagef(err, "Could not verify nodes's signature") + return nil, nil, 0, + errors.WithMessagef(err, "Could not verify nodes's signature") } // Unmarshal the response keyResponse := &pb.ClientKeyResponse{} err = proto.Unmarshal(signedKeyResponse.KeyResponse, keyResponse) if err != nil { - return nil, nil, 0, errors.WithMessagef(err, "Failed to unmarshal client key response") + return nil, nil, 0, + errors.WithMessagef(err, "Failed to unmarshal client key response") } h.Reset() @@ -288,9 +300,11 @@ func requestKey(sender *gateway.Sender, comms RegisterNodeCommsInterface, } // Decrypt the client key - clientKey, err := chacha.Decrypt(sessionKey.Bytes(), keyResponse.EncryptedClientKey) + clientKey, err := chacha.Decrypt( + sessionKey.Bytes(), keyResponse.EncryptedClientKey) if err != nil { - return nil, nil, 0, errors.WithMessagef(err, "Failed to decrypt client key") + return nil, nil, 0, + errors.WithMessagef(err, "Failed to decrypt client key") } // Construct the transmission key from the client key diff --git a/network/nodes/register_test.go b/network/nodes/register_test.go index f269d1b4fb43e0d78c6f7a67fef1b8039a6f0641..f4eba3e300d668e2483dc32e5fcb7254eac7705d 100644 --- a/network/nodes/register_test.go +++ b/network/nodes/register_test.go @@ -7,48 +7,6 @@ package nodes -import ( - //"crypto/rand" - //"gitlab.com/elixxir/client/stoppable" - //"gitlab.com/elixxir/client/storage" - pb "gitlab.com/elixxir/comms/mixmessages" - //"gitlab.com/elixxir/comms/network" - //"gitlab.com/xx_network/crypto/csprng" - //"gitlab.com/elixxir/crypto/fastRNG" - "gitlab.com/xx_network/comms/connect" - //"gitlab.com/xx_network/crypto/signature/rsa" - "gitlab.com/xx_network/primitives/id" - //"gitlab.com/xx_network/primitives/ndf" - //"testing" - //"time" -) - -// Mock client comms object -type MockClientComms struct { - request chan bool - confirm chan bool -} - -func NewMockClientComms() *MockClientComms { - return &MockClientComms{ - request: make(chan bool, 1), - confirm: make(chan bool, 1), - } -} - -func (mcc *MockClientComms) GetHost(hostId *id.ID) (*connect.Host, bool) { - return &connect.Host{}, true -} -func (mcc *MockClientComms) SendRequestClientKeyMessage(host *connect.Host, - message *pb.SignedClientKeyRequest) (*pb.SignedKeyResponse, error) { - // Use this channel to confirm that request nonce was called - mcc.request <- true - return &pb.SignedKeyResponse{ - KeyResponse: []byte("nonce"), - ClientGatewayKey: []byte("dhpub"), - }, nil -} - // func TestRegisterNodes(t *testing.T) { // privKey, err := rsa.LoadPrivateKeyFromPem([]byte("-----BEGIN PRIVATE KEY-----\n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\nOaRA5ZbdE7g7vxKRV36jT3wvD7W+\n-----END PRIVATE KEY-----\n")) // if err != nil || privKey == nil { diff --git a/network/nodes/registrar.go b/network/nodes/registrar.go index 20540292bee1f01844be54937735d84cd74af48f..dec183a4cbab00f25756f86e8750e3d898407082 100644 --- a/network/nodes/registrar.go +++ b/network/nodes/registrar.go @@ -21,10 +21,16 @@ import ( const InputChanLen = 1000 const maxAttempts = 5 -var delayTable = [5]time.Duration{0, 5 * time.Second, 30 * time.Second, 60 * time.Second, 120 * time.Second} +var delayTable = [5]time.Duration{ + 0, + 5 * time.Second, + 30 * time.Second, + 60 * time.Second, + 120 * time.Second, +} type Registrar interface { - StartProcessies(numParallel uint) stoppable.Stoppable + StartProcesses(numParallel uint) stoppable.Stoppable Has(nid *id.ID) bool GetKeys(topology *connect.Circuit) (MixCypher, error) NumRegistered() int @@ -49,7 +55,8 @@ type registrar struct { c chan network.NodeGateway } -// LoadRegistrar loads a registrar from disk, and creates a new one if it doesnt exist +// LoadRegistrar loads a registrar from disk, and creates a new one if it does +// not exist. func LoadRegistrar(kv *versioned.KV, session *storage.Session, sender *gateway.Sender, comms RegisterNodeCommsInterface, rngGen *fastRNG.StreamGenerator) (Registrar, error) { @@ -60,7 +67,7 @@ func LoadRegistrar(kv *versioned.KV, session *storage.Session, } obj, err := kv.Get(storeKey, currentKeyVersion) - //if there is no stored data, make a new node handler + // If there is no stored data, make a new node handler if err != nil { jww.WARN.Printf("Failed to load Node Registrar, creating a new object") err = r.save() @@ -84,19 +91,18 @@ func LoadRegistrar(kv *versioned.KV, session *storage.Session, return r, nil } -func (r *registrar) StartProcessies(numParallel uint) stoppable.Stoppable { - +func (r *registrar) StartProcesses(numParallel uint) stoppable.Stoppable { multi := stoppable.NewMulti("NodeRegistrations") - inProgess := &sync.Map{} - // we are relying on the in progress check to - // ensure there is only a single operator at a time, as a result this is a map of ID -> int + inProgress := &sync.Map{} + // We are relying on the in progress check to ensure there is only a single + // operator at a time, as a result this is a map of ID -> int attempts := &sync.Map{} for i := uint(0); i < numParallel; i++ { stop := stoppable.NewSingle(fmt.Sprintf("NodeRegistration %d", i)) - go registerNodes(r, stop, inProgess, attempts) + go registerNodes(r, stop, inProgress, attempts) multi.Add(stop) } @@ -115,18 +121,20 @@ func (r *registrar) GetKeys(topology *connect.Circuit) (MixCypher, error) { keys := make([]*key, topology.Len()) - // get keys for every node. If it cannot be found, add - // it to the missing nodes list so it can be + // Get keys for every node. If it cannot be found, thn add it to the missing + // nodes list so that it can be for i := 0; i < topology.Len(); i++ { nid := topology.GetNodeAtIndex(i) k, ok := r.nodes[*nid] if !ok { r.c <- network.NodeGateway{ - Node: ndf.Node{ID: nid.Marshal(), - //status must be active because it is in a round - Status: ndf.Active}, + Node: ndf.Node{ + ID: nid.Marshal(), + Status: ndf.Active, // Status must be active because it is in a round + }, } - return nil, errors.Errorf("cannot get key for %s, triggered registration", nid) + return nil, errors.Errorf( + "cannot get key for %s, triggered registration", nid) } else { keys[i] = k } @@ -140,7 +148,7 @@ func (r *registrar) GetKeys(topology *connect.Circuit) (MixCypher, error) { return rk, nil } -// Returns if the store has the nodes +// Has returns if the store has the nodes. func (r *registrar) Has(nid *id.ID) bool { r.mux.RLock() _, exists := r.nodes[*nid] diff --git a/network/nodes/registrar_test.go b/network/nodes/registrar_test.go new file mode 100644 index 0000000000000000000000000000000000000000..45312b1899af7bd3c53fd350fe9df0bfa4148dbe --- /dev/null +++ b/network/nodes/registrar_test.go @@ -0,0 +1,196 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +//////////////////////////////////////////////////////////////////////////////// + +package nodes + +import ( + "bytes" + "gitlab.com/elixxir/client/network/gateway" + "gitlab.com/elixxir/client/storage" + "gitlab.com/elixxir/client/storage/versioned" + "gitlab.com/elixxir/crypto/cyclic" + "gitlab.com/elixxir/crypto/fastRNG" + "gitlab.com/elixxir/ekv" + "gitlab.com/xx_network/comms/connect" + "gitlab.com/xx_network/crypto/csprng" + "gitlab.com/xx_network/crypto/large" + "gitlab.com/xx_network/primitives/id" + "testing" + "time" +) + +// Tests that LoadRegistrar returns a new Registrar when none exists in the KV. +func TestLoadRegistrar_New(t *testing.T) { + connect.TestingOnlyDisableTLS = true + kv := versioned.NewKV(make(ekv.Memstore)) + session := storage.InitTestingSession(t) + rngGen := fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG) + p := gateway.DefaultPoolParams() + p.MaxPoolSize = 1 + sender, err := gateway.NewSender(gateway.DefaultPoolParams(), rngGen, + getNDF(), newMockManager(), session, nil) + if err != nil { + t.Fatalf("Failed to create new sender: %+v", err) + } + + r, err := LoadRegistrar(kv, session, sender, NewMockClientComms(), rngGen) + if err != nil { + t.Fatalf("Failed to create new registrar: %+v", err) + } + + if r.(*registrar).nodes == nil { + t.Errorf("Failed to initialize nodes") + } + if r.(*registrar).kv == nil { + t.Errorf("Failed to set store.kv") + } +} + +func TestLoadRegistrar_Load(t *testing.T) { + testR, kv := makeTestRegistrar(t) + grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2)) + + // Add a test nodes key + nodeId := id.NewIdFromString("test", id.Node, t) + k := grp.NewInt(5) + testTime, err := time.Parse(time.RFC3339, + "2012-12-21T22:08:41+00:00") + if err != nil { + t.Fatalf("Could not parse precanned time: %v", err.Error()) + } + expectedValid := uint64(testTime.UnixNano()) + + expectedKeyId := []byte("expectedKeyID") + + testR.add(nodeId, k, expectedValid, expectedKeyId) + + // Load the store and check its attributes + r, err := LoadRegistrar(kv, testR.session, testR.sender, testR.comms, testR.rng) + if err != nil { + t.Fatalf("Unable to load store: %+v", err) + } + if len(r.(*registrar).nodes) != len(testR.nodes) { + t.Errorf("LoadStore failed to load nodes keys") + } + + circuit := connect.NewCircuit([]*id.ID{nodeId}) + keys, _ := r.GetKeys(circuit) + if keys.(*mixCypher).keys[0].validUntil != expectedValid { + t.Errorf("Unexpected valid until value loaded from store."+ + "\n\tExpected: %v\n\tReceived: %v", expectedValid, keys.(*mixCypher).keys[0].validUntil) + } + if !bytes.Equal(keys.(*mixCypher).keys[0].keyId, expectedKeyId) { + t.Errorf("Unexpected keyID value loaded from store."+ + "\n\tExpected: %v\n\tReceived: %v", expectedKeyId, keys.(*mixCypher).keys[0].keyId) + } +} + +func Test_registrar_GetKeys(t *testing.T) { + r, _ := makeTestRegistrar(t) + grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2)) + + // Set up the circuit + numIds := 10 + nodeIds := make([]*id.ID, numIds) + for i := 0; i < numIds; i++ { + nodeIds[i] = id.NewIdFromUInt(uint64(i)+1, id.Node, t) + k := grp.NewInt(int64(i) + 1) + r.add(nodeIds[i], k, 0, nil) + + // This is wack but it cleans up after the test + defer r.remove(nodeIds[i]) + } + + circuit := connect.NewCircuit(nodeIds) + result, err := r.GetKeys(circuit) + if err != nil { + t.Errorf("GetKeys returrned an error: %+v", err) + } + if result == nil || len(result.(*mixCypher).keys) != numIds { + t.Errorf("Expected to have %d nodes keys", numIds) + } +} + +func Test_registrar_GetKeys_Missing(t *testing.T) { + r, _ := makeTestRegistrar(t) + grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2)) + + // Set up the circuit + numIds := 10 + nodeIds := make([]*id.ID, numIds) + for i := 0; i < numIds; i++ { + nodeIds[i] = id.NewIdFromUInt(uint64(i)+1, id.Node, t) + k := grp.NewInt(int64(i) + 1) + + // Only add every other nodes so there are missing nodes + if i%2 == 0 { + r.add(nodeIds[i], k, 0, nil) + r.add(nodeIds[i], k, 0, nil) + + // This is wack but it cleans up after the test + defer r.remove(nodeIds[i]) + } + } + + circuit := connect.NewCircuit(nodeIds) + result, err := r.GetKeys(circuit) + if err == nil { + t.Error("GetKeys did not return an error when keys should be missing.") + } + if result != nil { + t.Errorf("Expected nil value for result due to missing keys!") + } +} + +func Test_registrar_Has(t *testing.T) { + r, _ := makeTestRegistrar(t) + grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2)) + + nodeId := id.NewIdFromString("test", id.Node, t) + k := grp.NewInt(5) + + r.add(nodeId, k, 0, nil) + if _, exists := r.nodes[*nodeId]; !exists { + t.Fatal("Failed to add node's key.") + } + + if !r.Has(nodeId) { + t.Fatal("Cannot find the node's ID that that was added.") + } +} + +// Tests that Has returns false when it does not have. +func Test_registrar_Has_Not(t *testing.T) { + r, _ := makeTestRegistrar(t) + + nodeId := id.NewIdFromString("test", id.Node, t) + + if r.Has(nodeId) { + t.Fatal("Found the node when it should not have been found.") + } +} + +func Test_registrar_NumRegistered(t *testing.T) { + r, _ := makeTestRegistrar(t) + grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2)) + + if r.NumRegistered() != 0 { + t.Errorf("Unexpected NumRegistered for a new Registrar."+ + "\nexpected: %d\nreceived: %d", 0, r.NumRegistered()) + } + + count := 50 + for i := 0; i < count; i++ { + r.add(id.NewIdFromUInt(uint64(i), id.Node, t), + grp.NewInt(int64(42+i)), 0, nil) + } + + if r.NumRegistered() != count { + t.Errorf("Unexpected NumRegistered."+ + "\nexpected: %d\nreceived: %d", count, r.NumRegistered()) + } +} diff --git a/network/nodes/store.go b/network/nodes/store.go index f5c29ad6c453415542e7647cc8c5f9e2c6d4c373..8a576abbde07d020d62d2b2913ccf25a5a8636d6 100644 --- a/network/nodes/store.go +++ b/network/nodes/store.go @@ -76,7 +76,7 @@ func (r *registrar) save() error { return r.kv.Set(storeKey, currentKeyVersion, &obj) } -// marshal builds a byte representation of the Store. +// marshal builds a byte representation of the registrar. func (r *registrar) marshal() ([]byte, error) { nodes := make([]id.ID, len(r.nodes)) @@ -89,8 +89,8 @@ func (r *registrar) marshal() ([]byte, error) { return json.Marshal(&nodes) } -// unmarshal restores the data for a Store from the byte representation of the -// Store +// unmarshal restores the data for a registrar from the byte representation of +// the registrar. func (r *registrar) unmarshal(b []byte) error { var nodes []id.ID @@ -102,7 +102,8 @@ func (r *registrar) unmarshal(b []byte) error { for _, nid := range nodes { k, err := loadKey(r.kv, &nid) if err != nil { - return errors.WithMessagef(err, "could not load nodes key for %s", &nid) + return errors.WithMessagef( + err, "could not load nodes key for %s", &nid) } r.nodes[nid] = k } diff --git a/network/nodes/storeKey.go b/network/nodes/storeKey.go index 3d680152fbbe9be364b32cef634f3004d33d5c6e..98b6e18cac27c1611bf6f6e2f01a2cf38551a3d2 100644 --- a/network/nodes/storeKey.go +++ b/network/nodes/storeKey.go @@ -27,7 +27,8 @@ type key struct { storeKey string } -func newKey(kv *versioned.KV, k *cyclic.Int, id *id.ID, validUntil uint64, keyId []byte) *key { +func newKey(kv *versioned.KV, k *cyclic.Int, id *id.ID, validUntil uint64, + keyId []byte) *key { nk := &key{ kv: kv, k: k, @@ -43,12 +44,12 @@ func newKey(kv *versioned.KV, k *cyclic.Int, id *id.ID, validUntil uint64, keyId return nk } -// get returns the cyclic key +// get returns the cyclic key. func (k *key) get() *cyclic.Int { return k.k } -// loads the key for the given nodes id from the versioned keystore +// loadKey loads the key for the given node ID from the versioned keystore. func loadKey(kv *versioned.KV, id *id.ID) (*key, error) { k := &key{} @@ -68,7 +69,7 @@ func loadKey(kv *versioned.KV, id *id.ID) (*key, error) { return k, nil } -// saves the key as the key for the given nodes ID in the passed keystore +// save stores the key as the key for the given nodes ID in the keystore. func (k *key) save() error { now := netTime.Now() @@ -86,7 +87,7 @@ func (k *key) save() error { return k.kv.Set(k.storeKey, currentKeyVersion, &obj) } -// deletes the key from the versioned keystore +// delete deletes the key from the versioned keystore. func (k *key) delete(kv *versioned.KV, id *id.ID) { key := keyKey(id) if err := kv.Delete(key, currentKeyVersion); err != nil { @@ -94,8 +95,8 @@ func (k *key) delete(kv *versioned.KV, id *id.ID) { } } -// makes a binary representation of the given key and key values -// in the keystore +// marshal makes a binary representation of the given key and key values in the +// keystore. func (k *key) marshal() ([]byte, error) { buff := bytes.NewBuffer(nil) keyBytes, err := k.k.GobEncode() @@ -125,7 +126,8 @@ func (k *key) marshal() ([]byte, error) { return buff.Bytes(), nil } -// resets the data of the key from the binary representation of the key passed in +// unmarshal resets the data of the key from the binary representation of the +// key passed in. func (k *key) unmarshal(b []byte) error { buff := bytes.NewBuffer(b) @@ -149,13 +151,13 @@ func (k *key) unmarshal(b []byte) error { return nil } -// Adheres to the stringer interface +// String returns a string representation of key. This functions adheres to the +// fmt.Stringer interface. func (k *key) String() string { return k.storeKey - } -// generates the key used in the keystore for the given key +// keyKey generates the key used in the keystore for the given key. func keyKey(id *id.ID) string { return "nodeKey:" + id.String() } diff --git a/network/nodes/store_test.go b/network/nodes/store_test.go index 8e1c09b3eb4d1ed3266440cf86418af5c9119ac9..3cf991dad40230db7be4ade2e0ebbf8f0d6c7f61 100644 --- a/network/nodes/store_test.go +++ b/network/nodes/store_test.go @@ -8,234 +8,27 @@ package nodes import ( - "bytes" - "gitlab.com/elixxir/client/storage/versioned" "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/ekv" - "gitlab.com/xx_network/comms/connect" "gitlab.com/xx_network/crypto/large" "gitlab.com/xx_network/primitives/id" "testing" - "time" ) -// Happy path -func TestNewStore(t *testing.T) { - kv := make(ekv.Memstore) - vkv := versioned.NewKV(kv) - +// Happy path add/remove test. +func Test_registrar_add_remove(t *testing.T) { + r, _ := makeTestRegistrar(t) grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2)) - store, err := NewStore(grp, vkv) - if err != nil { - t.Fatal(err.Error()) - } - - if store.nodes == nil { - t.Errorf("Failed to initialize nodes") - } - if store.grp == nil { - t.Errorf("Failed to set store.grp") - } - if store.kv == nil { - t.Errorf("Failed to set store.kv") - } -} - -// Happy path Add/Done test -func TestStore_AddRemove(t *testing.T) { - // Uncomment to print keys that Set and get are called on - // jww.SetStdoutThreshold(jww.LevelTrace) - - testStore, _ := makeTestStore() - nodeId := id.NewIdFromString("test", id.Node, t) - k := testStore.grp.NewInt(5) + k := grp.NewInt(5) keyId := []byte("keyId") - testStore.Add(nodeId, k, 0, keyId) - if _, exists := testStore.nodes[*nodeId]; !exists { - t.Fatal("Failed to add nodes key") - } - - testStore.Remove(nodeId) - if _, exists := testStore.nodes[*nodeId]; exists { - t.Fatal("Failed to remove nodes key") - } -} - -// Happy path Add/Has test -func TestStore_AddHas(t *testing.T) { - // Uncomment to print keys that Set and get are called on - // jww.SetStdoutThreshold(jww.LevelTrace) - - testStore, _ := makeTestStore() - - nodeId := id.NewIdFromString("test", id.Node, t) - key := testStore.grp.NewInt(5) - - testStore.Add(nodeId, key, 0, nil) - if _, exists := testStore.nodes[*nodeId]; !exists { - t.Fatal("Failed to add nodes key") - } - - if !testStore.Has(nodeId) { - t.Fatal("cannot find the nodes id that that was added") - } -} - -// Tests that has returns false when it doesnt have -func TestStore_DoesntHave(t *testing.T) { - // Uncomment to print keys that Set and get are called on - // jww.SetStdoutThreshold(jww.LevelTrace) - - testStore, _ := makeTestStore() - - nodeId := id.NewIdFromString("test", id.Node, t) - - if testStore.Has(nodeId) { - t.Fatal("found the nodes when it shouldnt have been found") - } -} - -// Happy path -func TestLoadStore(t *testing.T) { - // Uncomment to print keys that Set and get are called on - // jww.SetStdoutThreshold(jww.LevelTrace) - - testStore, kv := makeTestStore() - - // Add a test nodes key - nodeId := id.NewIdFromString("test", id.Node, t) - k := testStore.grp.NewInt(5) - testTime, err := time.Parse(time.RFC3339, - "2012-12-21T22:08:41+00:00") - if err != nil { - t.Fatalf("Could not parse precanned time: %v", err.Error()) - } - expectedValid := uint64(testTime.UnixNano()) - - expectedKeyId := []byte("expectedKeyID") - - testStore.Add(nodeId, k, uint64(expectedValid), expectedKeyId) - - // Load the store and check its attributes - store, err := LoadStore(kv) - if err != nil { - t.Fatalf("Unable to load store: %+v", err) - } - if len(store.nodes) != len(testStore.nodes) { - t.Errorf("LoadStore failed to load nodes keys") - } - - circuit := connect.NewCircuit([]*id.ID{nodeId}) - keys, _ := store.GetRoundKeys(circuit) - if keys.keys[0].validUntil != expectedValid { - t.Errorf("Unexpected valid until value loaded from store."+ - "\n\tExpected: %v\n\tReceived: %v", expectedValid, keys.keys[0].validUntil) - } - if !bytes.Equal(keys.keys[0].keyId, expectedKeyId) { - t.Errorf("Unexpected keyID value loaded from store."+ - "\n\tExpected: %v\n\tReceived: %v", expectedKeyId, keys.keys[0].keyId) - } - -} - -// Happy path -func TestStore_GetRoundKeys(t *testing.T) { - // Uncomment to print keys that Set and get are called on - // jww.SetStdoutThreshold(jww.LevelTrace) - - testStore, _ := makeTestStore() - // Set up the circuit - numIds := 10 - nodeIds := make([]*id.ID, numIds) - for i := 0; i < numIds; i++ { - nodeIds[i] = id.NewIdFromUInt(uint64(i)+1, id.Node, t) - key := testStore.grp.NewInt(int64(i) + 1) - testStore.Add(nodeIds[i], key, 0, nil) - - // This is wack but it cleans up after the test - defer testStore.Remove(nodeIds[i]) - } - - circuit := connect.NewCircuit(nodeIds) - result, missing := testStore.GetRoundKeys(circuit) - if len(missing) != 0 { - t.Errorf("Expected to have no missing keys, got %d", len(missing)) - } - if result == nil || len(result.keys) != numIds { - t.Errorf("Expected to have %d nodes keys", numIds) - } -} - -// Missing keys path -func TestStore_GetRoundKeys_Missing(t *testing.T) { - // Uncomment to print keys that Set and get are called on - // jww.SetStdoutThreshold(jww.LevelTrace) - - testStore, _ := makeTestStore() - // Set up the circuit - numIds := 10 - nodeIds := make([]*id.ID, numIds) - for i := 0; i < numIds; i++ { - nodeIds[i] = id.NewIdFromUInt(uint64(i)+1, id.Node, t) - key := testStore.grp.NewInt(int64(i) + 1) - - // Only add every other nodes so there are missing nodes - if i%2 == 0 { - testStore.Add(nodeIds[i], key, 0, nil) - testStore.Add(nodeIds[i], key, 0, nil) - - // This is wack but it cleans up after the test - defer testStore.Remove(nodeIds[i]) - } + r.add(nodeId, k, 0, keyId) + if _, exists := r.nodes[*nodeId]; !exists { + t.Fatal("Failed to add node's key.") } - circuit := connect.NewCircuit(nodeIds) - result, missing := testStore.GetRoundKeys(circuit) - if len(missing) != numIds/2 { - t.Errorf("Expected to have %d missing keys, got %d", numIds/2, len(missing)) + r.remove(nodeId) + if _, exists := r.nodes[*nodeId]; exists { + t.Fatal("Failed to remove node's key.") } - if result != nil { - t.Errorf("Expected nil value for result due to missing keys!") - } -} - -// Happy path. -func TestStore_Count(t *testing.T) { - vkv := versioned.NewKV(make(ekv.Memstore)) - grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2)) - - store, err := NewStore(grp, vkv) - if err != nil { - t.Fatalf("Failed to generate new Store: %+v", err) - } - - if store.Count() != 0 { - t.Errorf("Count() did not return the expected value for a new Store."+ - "\nexpected: %d\nreceived: %d", 0, store.Count()) - } - - count := 50 - for i := 0; i < count; i++ { - store.Add(id.NewIdFromUInt(uint64(i), id.Node, t), grp.NewInt(int64(42+i)), 0, nil) - } - - if store.Count() != count { - t.Errorf("Count() did not return the expected value."+ - "\nexpected: %d\nreceived: %d", count, store.Count()) - } -} - -// Main testing function. -func makeTestStore() (*Store, *versioned.KV) { - - kv := make(ekv.Memstore) - vkv := versioned.NewKV(kv) - - grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2)) - - testStore, _ := NewStore(grp, vkv) - - return testStore, vkv } diff --git a/network/nodes/utils_test.go b/network/nodes/utils_test.go new file mode 100644 index 0000000000000000000000000000000000000000..49d99620253db7fbc0b59cf48a02cf519b5cef8f --- /dev/null +++ b/network/nodes/utils_test.go @@ -0,0 +1,162 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +//////////////////////////////////////////////////////////////////////////////// + +package nodes + +import ( + "gitlab.com/elixxir/client/network/gateway" + "gitlab.com/elixxir/client/storage" + "gitlab.com/elixxir/client/storage/versioned" + pb "gitlab.com/elixxir/comms/mixmessages" + "gitlab.com/elixxir/crypto/fastRNG" + "gitlab.com/elixxir/ekv" + "gitlab.com/xx_network/comms/connect" + "gitlab.com/xx_network/crypto/csprng" + "gitlab.com/xx_network/primitives/id" + "gitlab.com/xx_network/primitives/ndf" + "testing" +) + +// Creates new registrar for testing. +func makeTestRegistrar(t *testing.T) (*registrar, *versioned.KV) { + connect.TestingOnlyDisableTLS = true + kv := versioned.NewKV(make(ekv.Memstore)) + session := storage.InitTestingSession(t) + rngGen := fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG) + p := gateway.DefaultPoolParams() + p.MaxPoolSize = 1 + sender, err := gateway.NewSender(gateway.DefaultPoolParams(), rngGen, + getNDF(), newMockManager(), session, nil) + if err != nil { + t.Fatalf("Failed to create new sender: %+v", err) + } + + r, err := LoadRegistrar(kv, session, sender, NewMockClientComms(), rngGen) + if err != nil { + t.Fatalf("Failed to create new registrar: %+v", err) + } + + return r.(*registrar), kv +} + +// Mock client comms object adhering to RegisterNodeCommsInterface for testing. +type MockClientComms struct { + request chan bool + confirm chan bool +} + +// Constructor for NewMockClientComms. +func NewMockClientComms() *MockClientComms { + return &MockClientComms{ + request: make(chan bool, 1), + confirm: make(chan bool, 1), + } +} + +func (mcc *MockClientComms) GetHost(_ *id.ID) (*connect.Host, bool) { + return &connect.Host{}, true +} +func (mcc *MockClientComms) SendRequestClientKeyMessage(*connect.Host, + *pb.SignedClientKeyRequest) (*pb.SignedKeyResponse, error) { + // Use this channel to confirm that request nonce was called + mcc.request <- true + return &pb.SignedKeyResponse{ + KeyResponse: []byte("nonce"), + ClientGatewayKey: []byte("dhPub"), + }, nil +} + +// Mock structure adhering to gateway.HostManager for testing. +type mockHostManager struct { + hosts map[string]*connect.Host +} + +// Constructor for mockHostManager. +func newMockManager() *mockHostManager { + return &mockHostManager{make(map[string]*connect.Host)} +} + +func (mhp *mockHostManager) GetHost(hostId *id.ID) (*connect.Host, bool) { + h, ok := mhp.hosts[hostId.String()] + return h, ok +} + +func (mhp *mockHostManager) AddHost(hid *id.ID, address string, cert []byte, + params connect.HostParams) (host *connect.Host, err error) { + host, err = connect.NewHost(hid, address, cert, params) + if err != nil { + return nil, err + } + + mhp.hosts[hid.String()] = host + + return +} + +func (mhp *mockHostManager) RemoveHost(hid *id.ID) { + delete(mhp.hosts, hid.String()) +} + +func getNDF() *ndf.NetworkDefinition { + nodeId := id.NewIdFromString("zezima", id.Node, &testing.T{}) + gwId := nodeId.DeepCopy() + gwId.SetType(id.Gateway) + return &ndf.NetworkDefinition{ + E2E: ndf.Group{ + Prime: "E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D49413394C049B7A" + + "8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688B55B3D" + + "D2AEDF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E78615" + + "75E745D31F8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC" + + "6ADC718DD2A3E041023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C" + + "4A530E8FFB1BC51DADDF453B0B2717C2BC6669ED76B4BDD5C9FF558E88F2" + + "6E5785302BEDBCA23EAC5ACE92096EE8A60642FB61E8F3D24990B8CB12EE" + + "448EEF78E184C7242DD161C7738F32BF29A841698978825B4111B4BC3E1E" + + "198455095958333D776D8B2BEEED3A1A1A221A6E37E664A64B83981C46FF" + + "DDC1A45E3D5211AAF8BFBC072768C4F50D7D7803D2D4F278DE8014A47323" + + "631D7E064DE81C0C6BFA43EF0E6998860F1390B5D3FEACAF1696015CB79C" + + "3F9C2D93D961120CD0E5F12CBB687EAB045241F96789C38E89D796138E63" + + "19BE62E35D87B1048CA28BE389B575E994DCA755471584A09EC723742DC3" + + "5873847AEF49F66E43873", + Generator: "2", + }, + CMIX: ndf.Group{ + Prime: "9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642" + + "F0B5C48C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757" + + "264E5A1A44FFE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F" + + "9716BFE6117C6B5B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091E" + + "B51743BF33050C38DE235567E1B34C3D6A5C0CEAA1A0F368213C3D19843D" + + "0B4B09DCB9FC72D39C8DE41F1BF14D4BB4563CA28371621CAD3324B6A2D3" + + "92145BEBFAC748805236F5CA2FE92B871CD8F9C36D3292B5509CA8CAA77A" + + "2ADFC7BFD77DDA6F71125A7456FEA153E433256A2261C6A06ED3693797E7" + + "995FAD5AABBCFBE3EDA2741E375404AE25B", + Generator: "5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E2480" + + "9670716C613D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D" + + "1AA58C4328A06C46A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A33" + + "8661D10461C0D135472085057F3494309FFA73C611F78B32ADBB5740C361" + + "C9F35BE90997DB2014E2EF5AA61782F52ABEB8BD6432C4DD097BC5423B28" + + "5DAFB60DC364E8161F4A2A35ACA3A10B1C4D203CC76A470A33AFDCBDD929" + + "59859ABD8B56E1725252D78EAC66E71BA9AE3F1DD2487199874393CD4D83" + + "2186800654760E1E34C09E4D155179F9EC0DC4473F996BDCE6EED1CABED8" + + "B6F116F7AD9CF505DF0F998E34AB27514B0FFE7", + }, + Gateways: []ndf.Gateway{ + { + ID: gwId.Marshal(), + Address: "0.0.0.0", + TlsCertificate: "", + }, + }, + Nodes: []ndf.Node{ + { + ID: nodeId.Marshal(), + Address: "0.0.0.0", + TlsCertificate: "", + Status: ndf.Active, + }, + }, + } +}