diff --git a/go.mod b/go.mod index 371b92b8588164f9862350b80182a5d592ca42ac..3ea0fa1712c239c1cc08581025adb4afd9f2859f 100644 --- a/go.mod +++ b/go.mod @@ -18,13 +18,14 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.7.1 gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228 - gitlab.com/elixxir/comms v0.0.4-0.20201120005227-ec9177071abb - gitlab.com/elixxir/crypto v0.0.5-0.20201118204646-9b23991834c6 + gitlab.com/elixxir/comms v0.0.4-0.20201124200043-8031463a4843 + gitlab.com/elixxir/crypto v0.0.5-0.20201124195819-54be458a0dac gitlab.com/elixxir/ekv v0.1.3 gitlab.com/elixxir/primitives v0.0.3-0.20201116174806-97f190989704 gitlab.com/xx_network/comms v0.0.4-0.20201119231004-a67d08045535 - gitlab.com/xx_network/crypto v0.0.4 + gitlab.com/xx_network/crypto v0.0.5-0.20201124194022-366c10b1bce0 gitlab.com/xx_network/primitives v0.0.3-0.20201116234927-44e42fc91e7c + gitlab.com/xx_network/ring v0.0.3-0.20201120004140-b0e268db06d1 // indirect golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 google.golang.org/protobuf v1.25.0 gopkg.in/ini.v1 v1.61.0 // indirect diff --git a/go.sum b/go.sum index 7bd0cfbf89543ee8e2f1be9b13a49923f5293859..f0cf37ef1223c2adeb4e55a26524b6cdd75b1f4a 100644 --- a/go.sum +++ b/go.sum @@ -254,6 +254,8 @@ gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228 h1:Gi6rj4mAlK0 gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228/go.mod h1:H6jztdm0k+wEV2QGK/KYA+MY9nj9Zzatux/qIvDDv3k= gitlab.com/elixxir/comms v0.0.4-0.20201120005227-ec9177071abb h1:nqceIUadPdJGLQZHGHOEA4lbb4qADYLm/f0nfeQPZ/o= gitlab.com/elixxir/comms v0.0.4-0.20201120005227-ec9177071abb/go.mod h1:Xdo7hhfg+wGShftpN4S/2tgO+6A8K+5OijlVO+wrl7s= +gitlab.com/elixxir/comms v0.0.4-0.20201124200043-8031463a4843 h1:KYcfQnnmc1oBAodVi3gMCXNWS6zoSCeyLhrrRzQP40Y= +gitlab.com/elixxir/comms v0.0.4-0.20201124200043-8031463a4843/go.mod h1:dRTzI+YApY9QZ2+eP9+0n5+KzxziZY24SyW31O4QWgM= gitlab.com/elixxir/crypto v0.0.0-20200804182833-984246dea2c4 h1:28ftZDeYEko7xptCZzeFWS1Iam95dj46TWFVVlKmw6A= gitlab.com/elixxir/crypto v0.0.0-20200804182833-984246dea2c4/go.mod h1:ucm9SFKJo+K0N2GwRRpaNr+tKXMIOVWzmyUD0SbOu2c= gitlab.com/elixxir/crypto v0.0.3 h1:znCt/x2bL4y8czTPaaFkwzdgSgW3BJc/1+dxyf1jqVw= @@ -262,6 +264,8 @@ gitlab.com/elixxir/crypto v0.0.5-0.20201110193609-6b5e881867b4 h1:1a1zZDuqZ56qU1 gitlab.com/elixxir/crypto v0.0.5-0.20201110193609-6b5e881867b4/go.mod h1:ZNgBOblhYToR4m8tj4cMvJ9UsJAUKq+p0gCp07WQmhA= gitlab.com/elixxir/crypto v0.0.5-0.20201118204646-9b23991834c6 h1:HEJHC6gyVMdCZ1PSJkFDScHnsrWAMF+PFxyL2zpNrgU= gitlab.com/elixxir/crypto v0.0.5-0.20201118204646-9b23991834c6/go.mod h1:BqvmtLM4eW+3NNOVK7U3COnnxqhJZxdCv4yziCuYhlA= +gitlab.com/elixxir/crypto v0.0.5-0.20201124195819-54be458a0dac h1:JXtuads5nAgrSku7klahF8n+CF+dmupmm0DHsL0CCEM= +gitlab.com/elixxir/crypto v0.0.5-0.20201124195819-54be458a0dac/go.mod h1:V8lricBRpa8v1ySymXQ1/lsb+8/lSak5S7ZWRT6OACY= gitlab.com/elixxir/ekv v0.1.3 h1:OE+LBMIhjGUMwc6hHJzYvEPNJQV7t1vMnJyIgxUMUo8= gitlab.com/elixxir/ekv v0.1.3/go.mod h1:e6WPUt97taFZe5PFLPb1Dupk7tqmDCTQu1kkstqJvw4= gitlab.com/elixxir/primitives v0.0.0-20200731184040-494269b53b4d/go.mod h1:OQgUZq7SjnE0b+8+iIAT2eqQF+2IFHn73tOo+aV11mg= @@ -278,6 +282,8 @@ gitlab.com/xx_network/comms v0.0.4-0.20201119231004-a67d08045535/go.mod h1:YViGb gitlab.com/xx_network/crypto v0.0.3/go.mod h1:DF2HYvvCw9wkBybXcXAgQMzX+MiGbFPjwt3t17VRqRE= gitlab.com/xx_network/crypto v0.0.4 h1:lpKOL5mTJ2awWMfgBy30oD/UvJVrWZzUimSHlOdZZxo= gitlab.com/xx_network/crypto v0.0.4/go.mod h1:+lcQEy+Th4eswFgQDwT0EXKp4AXrlubxalwQFH5O0Mk= +gitlab.com/xx_network/crypto v0.0.5-0.20201124194022-366c10b1bce0 h1:v2xX/bl9lyZJZXXFZ6glDs7F/GNGIeKAH6hzafUNi5w= +gitlab.com/xx_network/crypto v0.0.5-0.20201124194022-366c10b1bce0/go.mod h1:+lcQEy+Th4eswFgQDwT0EXKp4AXrlubxalwQFH5O0Mk= gitlab.com/xx_network/primitives v0.0.0-20200803231956-9b192c57ea7c/go.mod h1:wtdCMr7DPePz9qwctNoAUzZtbOSHSedcK++3Df3psjA= gitlab.com/xx_network/primitives v0.0.0-20200804183002-f99f7a7284da h1:CCVslUwNC7Ul7NG5nu3ThGTSVUt1TxNRX+47f5TUwnk= gitlab.com/xx_network/primitives v0.0.0-20200804183002-f99f7a7284da/go.mod h1:OK9xevzWCaPO7b1wiluVJGk7R5ZsuC7pHY5hteZFQug= @@ -285,6 +291,7 @@ gitlab.com/xx_network/primitives v0.0.2 h1:r45yKenJ9e7PylI1ZXJ1Es09oYNaYXjxVy9+u gitlab.com/xx_network/primitives v0.0.2/go.mod h1:cs0QlFpdMDI6lAo61lDRH2JZz+3aVkHy+QogOB6F/qc= gitlab.com/xx_network/primitives v0.0.3-0.20201116234927-44e42fc91e7c h1:mYId667WIN97E6KhPw4HDYyCjWzsG7gCM/HLTNTCXZQ= gitlab.com/xx_network/primitives v0.0.3-0.20201116234927-44e42fc91e7c/go.mod h1:cs0QlFpdMDI6lAo61lDRH2JZz+3aVkHy+QogOB6F/qc= +gitlab.com/xx_network/ring v0.0.2/go.mod h1:aLzpP2TiZTQut/PVHR40EJAomzugDdHXetbieRClXIM= gitlab.com/xx_network/ring v0.0.3-0.20201120004140-b0e268db06d1 h1:yqXC/naXN6Hw1fmfI6qOOMmBbmZGsYXsESVSwf6IEdM= gitlab.com/xx_network/ring v0.0.3-0.20201120004140-b0e268db06d1/go.mod h1:aLzpP2TiZTQut/PVHR40EJAomzugDdHXetbieRClXIM= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= diff --git a/ud/register.go b/ud/register.go index 84aec1a9277078b2a50ae7ba6d7f75a794a25d98..505c08d885ca23dd3d338ab66c1e39fafb5e832f 100644 --- a/ud/register.go +++ b/ud/register.go @@ -1,25 +1,75 @@ package ud import ( + "github.com/pkg/errors" pb "gitlab.com/elixxir/comms/mixmessages" - "gitlab.com/xx_network/primitives/id" + "gitlab.com/elixxir/crypto/factID" + "gitlab.com/elixxir/crypto/hash" + "gitlab.com/elixxir/primitives/fact" + "gitlab.com/xx_network/comms/connect" + "gitlab.com/xx_network/comms/messages" + "gitlab.com/xx_network/crypto/signature/rsa" ) -func (m *Manager) Register(myID *id.ID, username string) error { +type registerUserComms interface { + SendRegisterUser(*connect.Host, *pb.UDBUserRegistration) (*messages.Ack, error) +} + +// Register registers a user with user discovery. +func (m *Manager) Register(username string) error { + return m.register(username, m.comms) +} +// register registers a user with user discovery with a specified comm for +// easier testing. +func (m *Manager) register(username string, comm registerUserComms) error { + var err error + user := m.storage.User() + cryptoUser := m.storage.User().GetCryptographicIdentity() + rng := m.rng.GetStream() + + // Construct the user registration message msg := &pb.UDBUserRegistration{ - PermissioningSignature: nil, - RSAPublicPem: "", - IdentityRegistration: nil, - IdentitySignature: nil, - Frs: nil, - UID: myID.Bytes(), - XXX_NoUnkeyedLiteral: struct{}{}, - XXX_unrecognized: nil, - XXX_sizecache: 0, + PermissioningSignature: user.GetRegistrationValidationSignature(), + RSAPublicPem: string(rsa.CreatePublicKeyPem(cryptoUser.GetRSA().GetPublic())), + IdentityRegistration: &pb.Identity{ + Username: username, + DhPubKey: m.storage.E2e().GetDHPublicKey().Bytes(), + Salt: cryptoUser.GetSalt(), + }, + UID: cryptoUser.GetUserID().Marshal(), + } + + // Sign the identity data and add to user registration message + identityDigest := msg.IdentityRegistration.Digest() + msg.IdentitySignature, err = rsa.Sign(rng, cryptoUser.GetRSA(), + hash.CMixHash, identityDigest, nil) + if err != nil { + return errors.Errorf("Failed to sign user's IdentityRegistration: %+v", err) + } + + // Create new username fact + usernameFact, err := fact.NewFact(fact.Username, username) + if err != nil { + return errors.Errorf("Failed to create new username fact: %+v", err) + } + + // Hash and sign fact + hashedFact := factID.Fingerprint(usernameFact) + signedFact, err := rsa.Sign(rng, cryptoUser.GetRSA(), hash.CMixHash, hashedFact, nil) + + // Add username fact register request to the user registration message + msg.Frs = &pb.FactRegisterRequest{ + UID: cryptoUser.GetUserID().Marshal(), + Fact: &pb.Fact{ + Fact: username, + FactType: 0, + }, + FactSig: signedFact, } - _, _ = m.comms.SendRegisterUser(m.host, msg) + // Register user with user discovery + _, err = comm.SendRegisterUser(m.host, msg) - return nil + return err } diff --git a/ud/register_test.go b/ud/register_test.go new file mode 100644 index 0000000000000000000000000000000000000000..274eebe9ca63865aa20831d4dfc0a28d6d52f4f2 --- /dev/null +++ b/ud/register_test.go @@ -0,0 +1,111 @@ +package ud + +import ( + "bytes" + "gitlab.com/elixxir/client/storage" + pb "gitlab.com/elixxir/comms/mixmessages" + "gitlab.com/elixxir/crypto/factID" + "gitlab.com/elixxir/crypto/fastRNG" + "gitlab.com/elixxir/crypto/hash" + "gitlab.com/elixxir/primitives/fact" + "gitlab.com/xx_network/comms/connect" + "gitlab.com/xx_network/comms/messages" + "gitlab.com/xx_network/crypto/csprng" + "gitlab.com/xx_network/crypto/signature/rsa" + "gitlab.com/xx_network/primitives/id" + "reflect" + "testing" +) + +type testRegisterComm struct { + msg *pb.UDBUserRegistration +} + +func (t *testRegisterComm) SendRegisterUser(_ *connect.Host, msg *pb.UDBUserRegistration) (*messages.Ack, error) { + t.msg = msg + return &messages.Ack{}, nil +} + +// Happy path. +func TestManager_register(t *testing.T) { + // Create new host + host, err := connect.NewHost(&id.UDB, "0.0.0.0", nil, connect.GetDefaultHostParams()) + if err != nil { + t.Fatalf("Could not create a new host: %+v", err) + } + + // Set up manager + m := &Manager{ + host: host, + rng: fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG), + storage: storage.InitTestingSession(t), + } + + c := &testRegisterComm{} + + err = m.register("testUser", c) + if err != nil { + t.Errorf("register() returned an error: %+v", err) + } + + // Check if the UDBUserRegistration contents are correct + m.isCorrect("testUser", c.msg, t) + + // Verify the signed identity data + pubKey := m.storage.User().GetCryptographicIdentity().GetRSA().GetPublic() + err = rsa.Verify(pubKey, hash.CMixHash, c.msg.IdentityRegistration.Digest(), + c.msg.IdentitySignature, nil) + if err != nil { + t.Errorf("Failed to verify signed identity data: %+v", err) + } + + // Verify the signed fact + usernameFact, _ := fact.NewFact(fact.Username, "testUser") + err = rsa.Verify(pubKey, hash.CMixHash, factID.Fingerprint(usernameFact), + c.msg.Frs.FactSig, nil) + if err != nil { + t.Errorf("Failed to verify signed fact data: %+v", err) + } +} + +// isCorrect checks if the UDBUserRegistration has all the expected fields minus +// any signatures. +func (m *Manager) isCorrect(username string, msg *pb.UDBUserRegistration, t *testing.T) { + user := m.storage.User() + cryptoUser := m.storage.User().GetCryptographicIdentity() + + if !bytes.Equal(user.GetRegistrationValidationSignature(), msg.PermissioningSignature) { + t.Errorf("PermissioningSignature incorrect.\n\texpected: %v\n\treceived: %v", + user.GetRegistrationValidationSignature(), msg.PermissioningSignature) + } + + if string(rsa.CreatePublicKeyPem(cryptoUser.GetRSA().GetPublic())) != msg.RSAPublicPem { + t.Errorf("RSAPublicPem incorrect.\n\texpected: %v\n\treceived: %v", + string(rsa.CreatePublicKeyPem(cryptoUser.GetRSA().GetPublic())), msg.RSAPublicPem) + } + + if username != msg.IdentityRegistration.Username { + t.Errorf("IdentityRegistration Username incorrect.\n\texpected: %#v\n\treceived: %#v", + username, msg.IdentityRegistration.Username) + } + + if !bytes.Equal(m.storage.E2e().GetDHPublicKey().Bytes(), msg.IdentityRegistration.DhPubKey) { + t.Errorf("IdentityRegistration DhPubKey incorrect.\n\texpected: %#v\n\treceived: %#v", + m.storage.E2e().GetDHPublicKey().Bytes(), msg.IdentityRegistration.DhPubKey) + } + + if !bytes.Equal(cryptoUser.GetSalt(), msg.IdentityRegistration.Salt) { + t.Errorf("IdentityRegistration Salt incorrect.\n\texpected: %#v\n\treceived: %#v", + cryptoUser.GetSalt(), msg.IdentityRegistration.Salt) + } + + if !bytes.Equal(cryptoUser.GetUserID().Marshal(), msg.Frs.UID) { + t.Errorf("Frs UID incorrect.\n\texpected: %v\n\treceived: %v", + cryptoUser.GetUserID().Marshal(), msg.Frs.UID) + } + + if !reflect.DeepEqual(&pb.Fact{Fact: username}, msg.Frs.Fact) { + t.Errorf("Frs Fact incorrect.\n\texpected: %v\n\treceived: %v", + &pb.Fact{Fact: username}, msg.Frs.Fact) + } +}