From 05cecb38c8bc8814159f3583b70495061a21ab6c Mon Sep 17 00:00:00 2001 From: Vu Quoc Huy Date: Thu, 28 Sep 2017 08:27:47 +0200 Subject: [PATCH] Registration should happen in epoch --- coniksclient/cli/internal/cmd/run.go | 3 +++ coniksserver/server_test.go | 14 ++++++++------ protocol/client/consistencychecks_test.go | 16 ++++++++++++++++ protocol/directory/directory.go | 8 +++++++- protocol/directory/directory_test.go | 22 ++++++++++++++++++++++ protocol/error.go | 3 +++ protocol/message.go | 1 + 7 files changed, 60 insertions(+), 7 deletions(-) diff --git a/coniksclient/cli/internal/cmd/run.go b/coniksclient/cli/internal/cmd/run.go index 536d4ed..2bae1b5 100644 --- a/coniksclient/cli/internal/cmd/run.go +++ b/coniksclient/cli/internal/cmd/run.go @@ -155,6 +155,9 @@ func register(cc *client.ConsistencyChecks, conf *coniksclient.Config, name stri switch response.Error { case protocol.ReqNameExisted: return (`Are you trying to update your binding? Unfortunately, KeyChange isn't supported yet.`) + case protocol.ErrOutdatedEpoch: + // FIXME + return (`You need to fetch the latest STR first. Unfortunately, we haven't implemented fetching STR functionality yet.`) case protocol.ReqSuccess: recvKey, err := response.GetKey() if err != nil { diff --git a/coniksserver/server_test.go b/coniksserver/server_test.go index 8c1028e..cf295e6 100644 --- a/coniksserver/server_test.go +++ b/coniksserver/server_test.go @@ -202,7 +202,7 @@ func TestUpdateDirectory(t *testing.T) { server, teardown := startServer(t, 1, true, "") defer teardown() str0 := server.dir.LatestSTR() - rs := createMultiRegistrationRequests(10) + rs := createMultiRegistrationRequests(10, str0.Epoch) for i := range rs { req := server.handleOps(rs[i]) if req.Error != protocol.ReqSuccess { @@ -217,12 +217,13 @@ func TestUpdateDirectory(t *testing.T) { } } -func createMultiRegistrationRequests(N uint64) []*protocol.Request { +func createMultiRegistrationRequests(N, epoch uint64) []*protocol.Request { var rs []*protocol.Request for i := uint64(0); i < N; i++ { r := &protocol.Request{ Type: protocol.RegistrationType, Request: &protocol.RegistrationRequest{ + Epoch: epoch, Username: "user" + string(i), Key: []byte("key" + string(i)), AllowPublicLookup: true, @@ -237,8 +238,8 @@ func createMultiRegistrationRequests(N uint64) []*protocol.Request { func TestRegisterDuplicateUserInOneEpoch(t *testing.T) { server, teardown := startServer(t, 60, true, "") defer teardown() - r0 := createMultiRegistrationRequests(1)[0] - r1 := createMultiRegistrationRequests(1)[0] + r0 := createMultiRegistrationRequests(1, server.dir.LatestSTR().Epoch)[0] + r1 := createMultiRegistrationRequests(1, server.dir.LatestSTR().Epoch)[0] rev := server.handleOps(r0) if rev.Error != protocol.ReqSuccess { t.Fatal("Error while submitting registration request") @@ -262,14 +263,15 @@ func TestRegisterDuplicateUserInOneEpoch(t *testing.T) { func TestRegisterDuplicateUserInDifferentEpoches(t *testing.T) { server, teardown := startServer(t, 1, true, "") defer teardown() - r0 := createMultiRegistrationRequests(1)[0] + r0 := createMultiRegistrationRequests(1, server.dir.LatestSTR().Epoch)[0] rev := server.handleOps(r0) if rev.Error != protocol.ReqSuccess { t.Fatal("Error while submitting registration request") } timer := time.NewTimer(2 * time.Second) <-timer.C - rev = server.handleOps(r0) + r1 := createMultiRegistrationRequests(1, server.dir.LatestSTR().Epoch)[0] + rev = server.handleOps(r1) response, ok := rev.DirectoryResponse.(*protocol.DirectoryProof) if !ok { t.Fatal("Expect a directory proof response") diff --git a/protocol/client/consistencychecks_test.go b/protocol/client/consistencychecks_test.go index 153b93f..9e893ba 100644 --- a/protocol/client/consistencychecks_test.go +++ b/protocol/client/consistencychecks_test.go @@ -17,6 +17,7 @@ var ( func registerAndVerify(d *directory.ConiksDirectory, cc *ConsistencyChecks, name string, key []byte) error { request := &protocol.RegistrationRequest{ + Epoch: d.LatestSTR().Epoch, Username: name, Key: key, } @@ -103,6 +104,21 @@ func TestVerifyRegistrationResponseWithTB(t *testing.T) { } } +func TestRegistrationOutdatedEpoch(t *testing.T) { + d, pk := directory.NewTestDirectory(t, true) + cc := New(d.LatestSTR(), true, pk) + request := &protocol.RegistrationRequest{ + Epoch: d.LatestSTR().Epoch, + Username: alice, + Key: key, + } + d.Update() + res := d.Register(request) + if err := cc.HandleResponse(protocol.RegistrationType, res, alice, key); err != protocol.ErrOutdatedEpoch { + t.Error(err) + } +} + func TestVerifyFullfilledPromise(t *testing.T) { d, pk := directory.NewTestDirectory(t, true) diff --git a/protocol/directory/directory.go b/protocol/directory/directory.go index 3412bc4..401481f 100644 --- a/protocol/directory/directory.go +++ b/protocol/directory/directory.go @@ -128,10 +128,16 @@ func (d *ConiksDirectory) NewTB(name string, key []byte) *protocol.TemporaryBind // a message.NewErrorResponse(ErrDirectory). func (d *ConiksDirectory) Register(req *protocol.RegistrationRequest) *protocol.Response { // make sure the request is well-formed - if len(req.Username) <= 0 || len(req.Key) <= 0 { + if len(req.Username) <= 0 || len(req.Key) <= 0 || + req.Epoch > d.LatestSTR().Epoch { return protocol.NewErrorResponse(protocol.ErrMalformedMessage) } + // check whether this registration request happens in epoch + if req.Epoch < d.LatestSTR().Epoch { + return protocol.NewErrorResponse(protocol.ErrOutdatedEpoch) + } + // check whether the name already exists // in the directory before we register ap, err := d.pad.Lookup(req.Username) diff --git a/protocol/directory/directory_test.go b/protocol/directory/directory_test.go index 3482085..a34bd33 100644 --- a/protocol/directory/directory_test.go +++ b/protocol/directory/directory_test.go @@ -13,6 +13,7 @@ func TestRegisterWithTB(t *testing.T) { d, _ := NewTestDirectory(t, true) res := d.Register(&protocol.RegistrationRequest{ + Epoch: d.LatestSTR().Epoch, Username: "alice", Key: []byte("key")}) df := res.DirectoryResponse.(*protocol.DirectoryProof) @@ -37,6 +38,7 @@ func TestRegisterWithTB(t *testing.T) { func TestRegisterExistedUserWithTB(t *testing.T) { d, _ := NewTestDirectory(t, true) res := d.Register(&protocol.RegistrationRequest{ + Epoch: d.LatestSTR().Epoch, Username: "alice", Key: []byte("key")}) if res.Error != protocol.ReqSuccess { @@ -47,6 +49,7 @@ func TestRegisterExistedUserWithTB(t *testing.T) { // along with a TB of registering user // and error ReqNameExisted res = d.Register(&protocol.RegistrationRequest{ + Epoch: d.LatestSTR().Epoch, Username: "alice", Key: []byte("key")}) df := res.DirectoryResponse.(*protocol.DirectoryProof) @@ -65,6 +68,7 @@ func TestRegisterExistedUserWithTB(t *testing.T) { // expect return a proof of inclusion // and error ReqNameExisted res = d.Register(&protocol.RegistrationRequest{ + Epoch: d.LatestSTR().Epoch, Username: "alice", Key: []byte("key")}) df = res.DirectoryResponse.(*protocol.DirectoryProof) @@ -79,6 +83,21 @@ func TestRegisterExistedUserWithTB(t *testing.T) { } } +func TestRegisterInOutdatedEpoch(t *testing.T) { + // expect return a proof of absence + // along with a TB of registering user + d, _ := NewTestDirectory(t, true) + d.Update() + + res := d.Register(&protocol.RegistrationRequest{ + Epoch: d.LatestSTR().Epoch - 1, + Username: "alice", + Key: []byte("key")}) + if res.Error != protocol.ErrOutdatedEpoch { + t.Fatal("Expect ", protocol.ErrOutdatedEpoch, "got", res.Error) + } +} + func TestNewDirectoryPanicWithoutTB(t *testing.T) { // workaround for #110 defer func() { @@ -93,6 +112,7 @@ func TestNewDirectoryPanicWithoutTB(t *testing.T) { func TestKeyLookupWithTB(t *testing.T) { d, _ := NewTestDirectory(t, true) res := d.Register(&protocol.RegistrationRequest{ + Epoch: d.LatestSTR().Epoch, Username: "alice", Key: []byte("key")}) tb := res.DirectoryResponse.(*protocol.DirectoryProof).TB @@ -134,6 +154,7 @@ func TestDirectoryMonitoring(t *testing.T) { d, _ := NewTestDirectory(t, true) d.Register(&protocol.RegistrationRequest{ + Epoch: d.LatestSTR().Epoch, Username: "alice", Key: []byte("key")}) @@ -201,6 +222,7 @@ func TestDirectoryKeyLookupInEpoch(t *testing.T) { } d.Register(&protocol.RegistrationRequest{ + Epoch: d.LatestSTR().Epoch, Username: "alice", Key: []byte("key")}) for i := 0; i < N; i++ { diff --git a/protocol/error.go b/protocol/error.go index 2521423..994c2a4 100644 --- a/protocol/error.go +++ b/protocol/error.go @@ -23,6 +23,7 @@ const ( ErrDirectory ErrAuditLog ErrMalformedMessage + ErrOutdatedEpoch ) // These codes indicate the result @@ -49,6 +50,7 @@ var Errors = map[error]bool{ ErrMalformedMessage: true, ErrDirectory: true, ErrAuditLog: true, + ErrOutdatedEpoch: true, } var ( @@ -60,6 +62,7 @@ var ( ErrMalformedMessage: "[coniks] Malformed message", ErrDirectory: "[coniks] Directory error", ErrAuditLog: "[coniks] Audit log error", + ErrOutdatedEpoch: "[coniks] The requested epoch is outdated", CheckBadSignature: "[coniks] Directory's signature on STR or TB is invalid", CheckBadVRFProof: "[coniks] Returned index is not valid for the given name", diff --git a/protocol/message.go b/protocol/message.go index 9bc46ed..f038555 100644 --- a/protocol/message.go +++ b/protocol/message.go @@ -36,6 +36,7 @@ type Request struct { // The response to a successful request is a DirectoryProof with a TB for // the requested username and public key. type RegistrationRequest struct { + Epoch uint64 Username string Key []byte AllowUnsignedKeychange bool `json:",omitempty"`