From 31c22593243b2916f08b98e58a5ac483fc84aabe Mon Sep 17 00:00:00 2001 From: Vu Quoc Huy Date: Wed, 25 Oct 2017 23:08:14 +0200 Subject: [PATCH] Refactor tests (comment some tests which will be rewritten later) --- coniksbots/twitterbot_test.go | 2 +- coniksclient/encoding.go | 32 +- coniksclient/encoding_test.go | 12 +- crypto/testutil.go | 29 ++ merkletree/testutil.go | 28 ++ protocol/auditlog/auditlog_test.go | 38 +-- protocol/auditlog/testutil.go | 14 +- protocol/auditor/auditor.go | 4 - protocol/auditor/auditor_test.go | 17 +- protocol/auditor/common_test.go | 34 ++- protocol/client/consistencychecks_test.go | 197 ------------- protocol/directory/directory_test.go | 340 +++++----------------- protocol/directory/testutil.go | 29 +- protocol/error.go | 4 +- protocol/message.go | 6 +- protocol/tests/client_auditlog_test.go | 1 + protocol/tests/directory_auditlog_test.go | 1 + protocol/tests/directory_client_test.go | 1 + 18 files changed, 226 insertions(+), 563 deletions(-) create mode 100644 crypto/testutil.go create mode 100644 merkletree/testutil.go create mode 100644 protocol/tests/client_auditlog_test.go create mode 100644 protocol/tests/directory_auditlog_test.go create mode 100644 protocol/tests/directory_client_test.go diff --git a/coniksbots/twitterbot_test.go b/coniksbots/twitterbot_test.go index 584b28c..ad7c359 100644 --- a/coniksbots/twitterbot_test.go +++ b/coniksbots/twitterbot_test.go @@ -23,7 +23,7 @@ func TestCannotUnmarshallRequest(t *testing.T) { func TestInvalidRequestType(t *testing.T) { username := "alice" request, _ := json.Marshal(&protocol.Request{ - Type: protocol.KeyLookupType, + Type: protocol.KeyLookupInEpochType, Request: &protocol.RegistrationRequest{ Username: username + "@twitter", Key: []byte{1, 2, 3}, diff --git a/coniksclient/encoding.go b/coniksclient/encoding.go index b57304c..5ac584b 100644 --- a/coniksclient/encoding.go +++ b/coniksclient/encoding.go @@ -14,8 +14,8 @@ func UnmarshalResponse(t int, msg []byte) *protocol.Response { Error protocol.ErrorCode DirectoryResponse json.RawMessage } - var res Response - if err := json.Unmarshal(msg, &res); err != nil { + var resp Response + if err := json.Unmarshal(msg, &resp); err != nil { return &protocol.Response{ Error: protocol.ErrMalformedMessage, } @@ -23,27 +23,39 @@ func UnmarshalResponse(t int, msg []byte) *protocol.Response { // DirectoryResponse is omitempty for the places // where Error is in Errors - if res.DirectoryResponse == nil { - if !protocol.Errors[res.Error] { + if resp.DirectoryResponse == nil { + response := &protocol.Response{ + Error: resp.Error, + } + if err := response.Validate(); err != nil { return &protocol.Response{ Error: protocol.ErrMalformedMessage, } } - return &protocol.Response{ - Error: res.Error, - } + return response } switch t { - case protocol.RegistrationType, protocol.KeyLookupType, protocol.KeyLookupInEpochType, protocol.MonitoringType: + case protocol.RegistrationType, protocol.KeyLookupInEpochType, protocol.MonitoringType: response := new(protocol.DirectoryProof) - if err := json.Unmarshal(res.DirectoryResponse, &response); err != nil { + if err := json.Unmarshal(resp.DirectoryResponse, &response); err != nil { + return &protocol.Response{ + Error: protocol.ErrMalformedMessage, + } + } + return &protocol.Response{ + Error: resp.Error, + DirectoryResponse: response, + } + case protocol.STRType: + response := new(protocol.STRHistoryRange) + if err := json.Unmarshal(resp.DirectoryResponse, &response); err != nil { return &protocol.Response{ Error: protocol.ErrMalformedMessage, } } return &protocol.Response{ - Error: res.Error, + Error: resp.Error, DirectoryResponse: response, } default: diff --git a/coniksclient/encoding_test.go b/coniksclient/encoding_test.go index c3f524c..f137d8e 100644 --- a/coniksclient/encoding_test.go +++ b/coniksclient/encoding_test.go @@ -37,13 +37,13 @@ func TestUnmarshalMalformedErrorResponse(t *testing.T) { } func TestUnmarshalSampleMessage(t *testing.T) { - d, _ := directory.NewTestDirectory(t, true) - res := d.Register(&protocol.RegistrationRequest{ - Username: "alice", - Key: []byte("key")}) + d := directory.NewTestDirectory(t) + res := d.GetSTRHistory(&protocol.STRHistoryRequest{ + StartEpoch: 0, + EndEpoch: 0}) msg, _ := coniksserver.MarshalResponse(res) - response := UnmarshalResponse(protocol.RegistrationType, []byte(msg)) - str := response.DirectoryResponse.(*protocol.DirectoryProof).STR[0] + response := UnmarshalResponse(protocol.STRType, []byte(msg)) + str := response.DirectoryResponse.(*protocol.STRHistoryRange).STR[0] if !bytes.Equal(d.LatestSTR().Serialize(), str.Serialize()) { t.Error("Cannot unmarshal Associate Data properly") } diff --git a/crypto/testutil.go b/crypto/testutil.go new file mode 100644 index 0000000..d8b7bb8 --- /dev/null +++ b/crypto/testutil.go @@ -0,0 +1,29 @@ +package crypto + +import ( + "bytes" + "testing" + + "github.com/coniks-sys/coniks-go/crypto/sign" + "github.com/coniks-sys/coniks-go/crypto/vrf" +) + +// StaticVRF returns a static VRF private key for _tests_. +func StaticVRF(t *testing.T) vrf.PrivateKey { + sk, err := vrf.GenerateKey(bytes.NewReader( + []byte("deterministic tests need 256 bit"))) + if err != nil { + t.Fatal(err) + } + return sk +} + +// StaticSigning returns a static private signing key for _tests_. +func StaticSigning(t *testing.T) sign.PrivateKey { + sk, err := sign.GenerateKey(bytes.NewReader( + []byte("deterministic tests need 256 bit"))) + if err != nil { + t.Fatal(err) + } + return sk +} diff --git a/merkletree/testutil.go b/merkletree/testutil.go new file mode 100644 index 0000000..74b1f5e --- /dev/null +++ b/merkletree/testutil.go @@ -0,0 +1,28 @@ +package merkletree + +import ( + "testing" + + "github.com/coniks-sys/coniks-go/crypto" +) + +// StaticPAD returns a pad with a static initial STR for _tests_. +func StaticPAD(t *testing.T, ad AssocData) *PAD { + pad, err := NewPAD(ad, crypto.StaticSigning(t), crypto.StaticVRF(t), 10) + if err != nil { + t.Fatal(err) + } + str := NewSTR(pad.signKey, pad.ad, staticTree(t), 0, []byte{}) + pad.latestSTR = str + pad.snapshots[0] = pad.latestSTR + return pad +} + +func staticTree(t *testing.T) *MerkleTree { + m, err := NewMerkleTree() + if err != nil { + t.Fatal(err) + } + m.nonce = []byte{} + return m +} diff --git a/protocol/auditlog/auditlog_test.go b/protocol/auditlog/auditlog_test.go index 4fcff98..e1c79ab 100644 --- a/protocol/auditlog/auditlog_test.go +++ b/protocol/auditlog/auditlog_test.go @@ -10,7 +10,7 @@ import ( func TestInsertEmptyHistory(t *testing.T) { // create basic test directory and audit log with 1 STR - _, _, _ = NewTestAuditLog(t, 0) + NewTestAuditLog(t, 0) } func TestUpdateHistory(t *testing.T) { @@ -32,7 +32,7 @@ func TestUpdateHistory(t *testing.T) { func TestInsertPriorHistory(t *testing.T) { // create basic test directory and audit log with 11 STRs - _, _, _ = NewTestAuditLog(t, 10) + NewTestAuditLog(t, 10) } func TestInsertExistingHistory(t *testing.T) { @@ -74,16 +74,16 @@ func TestAuditLogBadEpochRange(t *testing.T) { dirInitHash := auditor.ComputeDirectoryIdentity(hist[0]) h, _ := aud.get(dirInitHash) - err1 := h.Audit(resp) - if err1 != nil { - t.Fatalf("Error occurred while auditing STR history: %s", err1.Error()) + err := h.Audit(resp) + if err != nil { + t.Fatalf("Error occurred while auditing STR history: %s", err.Error()) } // now try to audit the same range again: should fail because the // verified epoch is at 1 - err1 = h.Audit(resp) - if err1 != protocol.CheckBadSTR { - t.Fatalf("Expecting CheckBadSTR, got %s", err1.Error()) + err = h.Audit(resp) + if err != protocol.CheckBadSTR { + t.Fatalf("Expecting CheckBadSTR, got %s", err.Error()) } } @@ -172,8 +172,8 @@ func TestGetObservedSTRMultipleEpochs(t *testing.T) { h, _ := aud.get(dirInitHash) resp := protocol.NewSTRHistoryRange([]*protocol.DirSTR{d.LatestSTR()}) - err1 := h.Audit(resp) - if err1 != nil { + err := h.Audit(resp) + if err != nil { t.Fatal("Error occurred updating audit log after auditing request") } @@ -339,9 +339,9 @@ func TestSTRHistoryRequestLatest(t *testing.T) { dirInitHash := auditor.ComputeDirectoryIdentity(hist[0]) h, _ := aud.get(dirInitHash) - err1 := h.Audit(resp) - if err1 != nil { - t.Fatalf("Error occurred auditing the latest STR: %s", err1.Error()) + err := h.Audit(resp) + if err != nil { + t.Fatalf("Error occurred auditing the latest STR: %s", err.Error()) } } @@ -375,9 +375,9 @@ func TestSTRHistoryRequestRangeLatest(t *testing.T) { dirInitHash := auditor.ComputeDirectoryIdentity(hist[0]) h, _ := aud.get(dirInitHash) - err1 := h.Audit(resp) - if err1 != nil { - t.Fatalf("Error occurred auditing the latest STR: %s", err1.Error()) + err := h.Audit(resp) + if err != nil { + t.Fatalf("Error occurred auditing the latest STR: %s", err.Error()) } } @@ -411,8 +411,8 @@ func TestSTRHistoryRequestInEpoch(t *testing.T) { dirInitHash := auditor.ComputeDirectoryIdentity(hist[0]) h, _ := aud.get(dirInitHash) - err1 := h.Audit(resp) - if err1 != nil { - t.Fatalf("Error occurred auditing the latest STR: %s", err1.Error()) + err := h.Audit(resp) + if err != nil { + t.Fatalf("Error occurred auditing the latest STR: %s", err.Error()) } } diff --git a/protocol/auditlog/testutil.go b/protocol/auditlog/testutil.go index 0086aad..465943c 100644 --- a/protocol/auditlog/testutil.go +++ b/protocol/auditlog/testutil.go @@ -3,6 +3,7 @@ package auditlog import ( "testing" + "github.com/coniks-sys/coniks-go/crypto" "github.com/coniks-sys/coniks-go/protocol" "github.com/coniks-sys/coniks-go/protocol/directory" ) @@ -15,21 +16,22 @@ import ( // STRs as it always includes the STR after the last directory update func NewTestAuditLog(t *testing.T, numEpochs int) ( *directory.ConiksDirectory, ConiksAuditLog, []*protocol.DirSTR) { - d, pk := directory.NewTestDirectory(t, true) + d := directory.NewTestDirectory(t) aud := New() - var hist []*protocol.DirSTR + var snaps []*protocol.DirSTR for ep := 0; ep < numEpochs; ep++ { - hist = append(hist, d.LatestSTR()) + snaps = append(snaps, d.LatestSTR()) d.Update() } // always include the actual latest STR - hist = append(hist, d.LatestSTR()) + snaps = append(snaps, d.LatestSTR()) - err := aud.InitHistory("test-server", pk, hist) + pk, _ := crypto.StaticSigning(t).Public() + err := aud.InitHistory("test-server", pk, snaps) if err != nil { t.Fatalf("Error inserting a new history with %d STRs", numEpochs+1) } - return d, aud, hist + return d, aud, snaps } diff --git a/protocol/auditor/auditor.go b/protocol/auditor/auditor.go index 4d54bee..d6e2f0b 100644 --- a/protocol/auditor/auditor.go +++ b/protocol/auditor/auditor.go @@ -91,10 +91,6 @@ func (a *AudState) CheckSTRAgainstVerified(str *protocol.DirSTR) error { // Maybe it has something to do w/ #81 and client // transitioning between epochs. // Try to verify w/ what's been saved - - // FIXME: we are returning the error immediately - // without saving the inconsistent STR - // see: https://github.com/coniks-sys/coniks-go/pull/74#commitcomment-19804686 switch { case str.Epoch == a.verifiedSTR.Epoch: // Checking an STR in the same epoch diff --git a/protocol/auditor/auditor_test.go b/protocol/auditor/auditor_test.go index 7d283f5..f18aa2b 100644 --- a/protocol/auditor/auditor_test.go +++ b/protocol/auditor/auditor_test.go @@ -3,13 +3,14 @@ package auditor import ( "testing" + "github.com/coniks-sys/coniks-go/crypto" "github.com/coniks-sys/coniks-go/protocol" "github.com/coniks-sys/coniks-go/protocol/directory" ) func TestAuditBadSTRSignature(t *testing.T) { - // create basic test directory - d, pk := directory.NewTestDirectory(t, true) + d := directory.NewTestDirectory(t) + pk, _ := crypto.StaticSigning(t).Public() // create a generic auditor state aud := New(pk, d.LatestSTR()) @@ -35,8 +36,8 @@ func TestAuditBadSTRSignature(t *testing.T) { // used to be TestVerifyWithError in consistencychecks_test.go func TestAuditBadSameEpoch(t *testing.T) { - // create basic test directory - d, pk := directory.NewTestDirectory(t, true) + d := directory.NewTestDirectory(t) + pk, _ := crypto.StaticSigning(t).Public() // create a generic auditor state aud := New(pk, d.LatestSTR()) @@ -57,8 +58,8 @@ func TestAuditBadSameEpoch(t *testing.T) { } func TestAuditBadNewSTREpoch(t *testing.T) { - // create basic test directory - d, pk := directory.NewTestDirectory(t, true) + d := directory.NewTestDirectory(t) + pk, _ := crypto.StaticSigning(t).Public() // create a generic auditor state aud := New(pk, d.LatestSTR()) @@ -95,8 +96,8 @@ func TestAuditBadNewSTREpoch(t *testing.T) { } func TestAuditMalformedSTRRange(t *testing.T) { - // create basic test directory - d, pk := directory.NewTestDirectory(t, true) + d := directory.NewTestDirectory(t) + pk, _ := crypto.StaticSigning(t).Public() // create a generic auditor state aud := New(pk, d.LatestSTR()) diff --git a/protocol/auditor/common_test.go b/protocol/auditor/common_test.go index 613e9c6..1302ac9 100644 --- a/protocol/auditor/common_test.go +++ b/protocol/auditor/common_test.go @@ -1,32 +1,29 @@ package auditor import ( + "bytes" + "encoding/hex" "testing" - "github.com/coniks-sys/coniks-go/crypto" "github.com/coniks-sys/coniks-go/protocol" "github.com/coniks-sys/coniks-go/protocol/directory" ) func TestComputeDirectoryIdentity(t *testing.T) { - d, _ := directory.NewTestDirectory(t, true) - // str0 := d.LatestSTR() + d := directory.NewTestDirectory(t) + str0 := d.LatestSTR() d.Update() str1 := d.LatestSTR() - var unknown [crypto.HashSizeByte]byte - type args struct { - str *protocol.DirSTR - } + tests := []struct { name string - args args - want [crypto.HashSizeByte]byte + str *protocol.DirSTR + want []byte }{ - // {"normal", args{str0}, ""}, - {"panic", args{str1}, unknown}, + {"normal", str0, dh("fd0584f79054f8113f21e5450e0ad21c9221fc159334c7bc1644e3e2a0fb5060")}, + {"panic", str1, []byte{}}, } for _, tt := range tests { - // FIXME: Refactor testing. See #18. t.Run(tt.name, func(t *testing.T) { if tt.name == "panic" { defer func() { @@ -35,9 +32,18 @@ func TestComputeDirectoryIdentity(t *testing.T) { } }() } - if got := ComputeDirectoryIdentity(tt.args.str); got != tt.want { - t.Errorf("ComputeDirectoryIdentity() = %v, want %v", got, tt.want) + if got, want := ComputeDirectoryIdentity(tt.str), tt.want; !bytes.Equal(got[:], want) { + t.Errorf("ComputeDirectoryIdentity() = %#v, want %#v", got, want) } }) } } + +// decode hex string to byte array +func dh(h string) []byte { + result, err := hex.DecodeString(h) + if err != nil { + panic(err) + } + return result +} diff --git a/protocol/client/consistencychecks_test.go b/protocol/client/consistencychecks_test.go index 153b93f..da13c8e 100644 --- a/protocol/client/consistencychecks_test.go +++ b/protocol/client/consistencychecks_test.go @@ -1,198 +1 @@ package client - -import ( - "bytes" - "testing" - - "github.com/coniks-sys/coniks-go/protocol" - "github.com/coniks-sys/coniks-go/protocol/directory" -) - -var ( - alice = "alice" - bob = "bob" - key = []byte("key") -) - -func registerAndVerify(d *directory.ConiksDirectory, cc *ConsistencyChecks, - name string, key []byte) error { - request := &protocol.RegistrationRequest{ - Username: name, - Key: key, - } - res := d.Register(request) - return cc.HandleResponse(protocol.RegistrationType, res, name, key) -} - -func lookupAndVerify(d *directory.ConiksDirectory, cc *ConsistencyChecks, - name string, key []byte) error { - request := &protocol.KeyLookupRequest{ - Username: name, - } - res := d.KeyLookup(request) - return cc.HandleResponse(protocol.KeyLookupType, res, name, key) -} - -func TestMalformedClientMessage(t *testing.T) { - d, pk := directory.NewTestDirectory(t, true) - cc := New(d.LatestSTR(), true, pk) - - request := &protocol.RegistrationRequest{ - Username: "", // invalid username - Key: key, - } - res := d.Register(request) - if err := cc.HandleResponse(protocol.RegistrationType, res, "", key); err != protocol.ErrMalformedMessage { - t.Error("Unexpected verification result", - "got", err) - } -} - -func TestMalformedDirectoryMessage(t *testing.T) { - d, pk := directory.NewTestDirectory(t, true) - cc := New(d.LatestSTR(), true, pk) - - request := &protocol.RegistrationRequest{ - Username: "alice", - Key: key, - } - res := d.Register(request) - // modify response message - res.DirectoryResponse.(*protocol.DirectoryProof).STR = nil - if err := cc.HandleResponse(protocol.RegistrationType, res, "alice", key); err != protocol.ErrMalformedMessage { - t.Error("Unexpected verification result") - } -} - -func TestVerifyRegistrationResponseWithTB(t *testing.T) { - d, pk := directory.NewTestDirectory(t, true) - - cc := New(d.LatestSTR(), true, pk) - - if err := registerAndVerify(d, cc, alice, key); err != nil { - t.Error(err) - } - - if len(cc.TBs) != 1 { - t.Fatal("Expect the directory to return a signed promise") - } - - // test error name existed - if err := registerAndVerify(d, cc, alice, key); err != nil { - t.Error(err) - } - - // test error name existed with different key - if err := registerAndVerify(d, cc, alice, []byte{1, 2, 3}); err != protocol.CheckBindingsDiffer { - t.Error(err) - } - if len(cc.TBs) != 1 { - t.Fatal("Expect the directory to return a signed promise") - } - - // re-register in a different epoch - // Since the fulfilled promise verification would be perform - // when the client is monitoring, we do _not_ expect a TB's verification here. - d.Update() - - if err := registerAndVerify(d, cc, alice, key); err != nil { - t.Error(err) - } - if err := registerAndVerify(d, cc, alice, []byte{1, 2, 3}); err != protocol.CheckBindingsDiffer { - t.Error(err) - } -} - -func TestVerifyFullfilledPromise(t *testing.T) { - d, pk := directory.NewTestDirectory(t, true) - - cc := New(d.LatestSTR(), true, pk) - - if err := registerAndVerify(d, cc, alice, key); err != nil { - t.Error(err) - } - if err := registerAndVerify(d, cc, bob, key); err != nil { - t.Error(err) - } - - if len(cc.TBs) != 2 { - t.Fatal("Expect the directory to return signed promises") - } - - d.Update() - - for i := 0; i < 2; i++ { - if err := lookupAndVerify(d, cc, alice, key); err != nil { - t.Error(err) - } - } - - // should contain the TBs of bob - if len(cc.TBs) != 1 || cc.TBs[bob] == nil { - t.Error("Expect the directory to insert the binding as promised") - } - - if err := lookupAndVerify(d, cc, bob, key); err != nil { - t.Error(err) - } - if len(cc.TBs) != 0 { - t.Error("Expect the directory to insert the binding as promised") - } -} - -func TestVerifyKeyLookupResponseWithTB(t *testing.T) { - d, pk := directory.NewTestDirectory(t, true) - - cc := New(d.LatestSTR(), true, pk) - - // do lookup first - if err := lookupAndVerify(d, cc, alice, key); err != nil { - t.Error(err) - } - - // register - if err := registerAndVerify(d, cc, alice, key); err != nil { - t.Error(err) - } - - // do lookup in the same epoch - TB TOFU - // and get the key from the response. The key would be extracted from the TB - request := &protocol.KeyLookupRequest{ - Username: alice, - } - res := d.KeyLookup(request) - if res.Error != protocol.ReqSuccess { - t.Error("Expect", protocol.ReqSuccess, "got", res.Error) - } - if err := cc.HandleResponse(protocol.KeyLookupType, res, alice, nil); err != nil { - t.Error("Expect", nil, "got", err) - } - recvKey, e := res.GetKey() - if e != nil && !bytes.Equal(recvKey, key) { - t.Error("The directory has returned a wrong key.") - } - - d.Update() - - // do lookup in the different epoch - // this time, the key would be extracted from the AP. - request = &protocol.KeyLookupRequest{ - Username: alice, - } - res = d.KeyLookup(request) - if res.Error != protocol.ReqSuccess { - t.Error("Expect", protocol.ReqSuccess, "got", res.Error) - } - if err := cc.HandleResponse(protocol.KeyLookupType, res, alice, nil); err != nil { - t.Error("Expect nil", "got", err) - } - recvKey, e = res.GetKey() - if e != nil && !bytes.Equal(recvKey, key) { - t.Error("The directory has returned a wrong key.") - } - - // test error name not found - if err := lookupAndVerify(d, cc, bob, key); err != nil { - t.Error(err) - } -} diff --git a/protocol/directory/directory_test.go b/protocol/directory/directory_test.go index 3482085..fc885bd 100644 --- a/protocol/directory/directory_test.go +++ b/protocol/directory/directory_test.go @@ -1,270 +1,13 @@ package directory import ( - "bytes" "testing" "github.com/coniks-sys/coniks-go/protocol" ) -func TestRegisterWithTB(t *testing.T) { - // expect return a proof of absence - // along with a TB of registering user - d, _ := NewTestDirectory(t, true) - - res := d.Register(&protocol.RegistrationRequest{ - Username: "alice", - Key: []byte("key")}) - df := res.DirectoryResponse.(*protocol.DirectoryProof) - if res.Error != protocol.ReqSuccess { - t.Fatal("Unable to register") - } - if ap := df.AP[0]; ap == nil || bytes.Equal(ap.LookupIndex, ap.Leaf.Index) { - t.Fatal("Expect a proof of absence") - } - if df.TB == nil { - t.Fatal("Expect returned TB is not nil") - } - if d.tbs["alice"] == nil { - t.Fatal("Expect TBs array has registering user") - } - d.Update() - if len(d.tbs) != 0 { - t.Fatal("Expect TBs array is empty") - } -} - -func TestRegisterExistedUserWithTB(t *testing.T) { - d, _ := NewTestDirectory(t, true) - res := d.Register(&protocol.RegistrationRequest{ - Username: "alice", - Key: []byte("key")}) - if res.Error != protocol.ReqSuccess { - t.Fatal("Unable to register") - } - // register in the same epoch - // expect return a proof of absence - // along with a TB of registering user - // and error ReqNameExisted - res = d.Register(&protocol.RegistrationRequest{ - Username: "alice", - Key: []byte("key")}) - df := res.DirectoryResponse.(*protocol.DirectoryProof) - if res.Error != protocol.ReqNameExisted { - t.Fatal("Expect error code", protocol.ReqNameExisted, "got", res.Error) - } - if ap := df.AP[0]; ap == nil || bytes.Equal(ap.LookupIndex, ap.Leaf.Index) { - t.Fatal("Expect a proof of absence") - } - if df.TB == nil { - t.Fatal("Expect returned TB is not nil") - } - - d.Update() - // register in different epochs - // expect return a proof of inclusion - // and error ReqNameExisted - res = d.Register(&protocol.RegistrationRequest{ - Username: "alice", - Key: []byte("key")}) - df = res.DirectoryResponse.(*protocol.DirectoryProof) - if res.Error != protocol.ReqNameExisted { - t.Fatal("Expect error code", protocol.ReqNameExisted, "got", res.Error) - } - if ap := df.AP[0]; ap == nil || !bytes.Equal(ap.LookupIndex, ap.Leaf.Index) { - t.Fatal("Expect a proof of inclusion") - } - if df.TB != nil { - t.Fatal("Expect returned TB is nil") - } -} - -func TestNewDirectoryPanicWithoutTB(t *testing.T) { - // workaround for #110 - defer func() { - if r := recover(); r == nil { - t.Errorf("The code did not panic") - } - }() - - NewTestDirectory(t, false) -} - -func TestKeyLookupWithTB(t *testing.T) { - d, _ := NewTestDirectory(t, true) - res := d.Register(&protocol.RegistrationRequest{ - Username: "alice", - Key: []byte("key")}) - tb := res.DirectoryResponse.(*protocol.DirectoryProof).TB - // lookup in the same epoch - // expect a proof of absence and the TB of looking up user - res = d.KeyLookup(&protocol.KeyLookupRequest{Username: "alice"}) - df := res.DirectoryResponse.(*protocol.DirectoryProof) - if res.Error != protocol.ReqSuccess { - t.Fatal("Expect no error", "got", res.Error) - } - if ap := df.AP[0]; ap == nil || bytes.Equal(ap.LookupIndex, ap.Leaf.Index) { - t.Fatal("Expect a proof of absence") - } - if df.TB == nil || !bytes.Equal(df.TB.Value, []byte("key")) { - t.Fatal("Expect the TB of looking up user") - } - // assert that the server returns the same TB - if !bytes.Equal(df.TB.Signature, tb.Signature) || - !bytes.Equal(df.TB.Index, tb.Index) || - !bytes.Equal(df.TB.Value, tb.Value) { - t.Fatal("Expect the same TB for the registration and lookup") - } - - d.Update() - // lookup in epoch after registering epoch - // expect a proof of inclusion - res = d.KeyLookup(&protocol.KeyLookupRequest{Username: "alice"}) - df = res.DirectoryResponse.(*protocol.DirectoryProof) - if ap := df.AP[0]; ap == nil || !bytes.Equal(ap.LookupIndex, ap.Leaf.Index) { - t.Fatal("Expect a proof of inclusion") - } - if df.TB != nil { - t.Fatal("Expect returned TB is nil") - } -} - -func TestDirectoryMonitoring(t *testing.T) { - N := 10 - - d, _ := NewTestDirectory(t, true) - d.Register(&protocol.RegistrationRequest{ - Username: "alice", - Key: []byte("key")}) - - d.Update() - savedSTR := d.LatestSTR() - for i := 2; i < N; i++ { - d.Update() - } - - // missed from epoch 2 - res := d.Monitor(&protocol.MonitoringRequest{ - Username: "alice", StartEpoch: uint64(2), EndEpoch: d.LatestSTR().Epoch, - }) - df := res.DirectoryResponse.(*protocol.DirectoryProof) - if res.Error != protocol.ReqSuccess { - t.Fatal("Unable to perform key lookup in epoch", 2) - } - expectNumberOfSTR := 10 - 2 - if len(df.AP) != expectNumberOfSTR || len(df.STR) != expectNumberOfSTR { - t.Fatal("Expect", expectNumberOfSTR, "auth paths/STRs", "got", len(df.AP), "auth paths and", len(df.STR), "STRs") - } - - for i := 0; i < expectNumberOfSTR; i++ { - str := df.STR[i] - if !str.VerifyHashChain(savedSTR) { - t.Fatal("Hash chain does not verify at epoch", i) - } - // we can ignore the auth path verification - // since it is already tested in merkletree package - savedSTR = str - } - - // assert the number of STRs returned is correct - res = d.Monitor(&protocol.MonitoringRequest{ - Username: "alice", StartEpoch: uint64(2), EndEpoch: d.LatestSTR().Epoch + 5, - }) - df = res.DirectoryResponse.(*protocol.DirectoryProof) - if res.Error != protocol.ReqSuccess { - t.Fatal("Unable to perform key lookup in epoch", 2) - } - if len(df.AP) != expectNumberOfSTR || len(df.STR) != expectNumberOfSTR { - t.Fatal("Expect", expectNumberOfSTR, "auth paths/STRs", "got", len(df.AP), "auth paths and", len(df.STR), "STRs") - } -} - -func TestDirectoryKeyLookupInEpoch(t *testing.T) { - N := 3 - - d, _ := NewTestDirectory(t, true) - for i := 0; i < N; i++ { - d.Update() - } - - // lookup at epoch 1, expect a proof of absence & ReqNameNotFound - res := d.KeyLookupInEpoch(&protocol.KeyLookupInEpochRequest{Username: "alice", Epoch: uint64(1)}) - df := res.DirectoryResponse.(*protocol.DirectoryProof) - if res.Error != protocol.ReqNameNotFound { - t.Fatal("Expect error", protocol.ReqNameNotFound, "got", res.Error) - } - if len(df.AP) != 1 { - t.Fatal("Expect only 1 auth path in response") - } - if len(df.STR) != int(d.LatestSTR().Epoch) { - t.Fatal("Expect", d.LatestSTR().Epoch, "STRs", "got", len(df.STR)) - } - - d.Register(&protocol.RegistrationRequest{ - Username: "alice", - Key: []byte("key")}) - for i := 0; i < N; i++ { - d.Update() - } - - res = d.KeyLookupInEpoch(&protocol.KeyLookupInEpochRequest{Username: "alice", Epoch: uint64(5)}) - df = res.DirectoryResponse.(*protocol.DirectoryProof) - if res.Error != protocol.ReqSuccess { - t.Fatal("Expect error", protocol.ReqSuccess, "got", res.Error) - } - if len(df.AP) != 1 { - t.Fatal("Expect only 1 auth path in response") - } - if len(df.STR) != 2 { - t.Fatal("Expect", 2, "STRs", "got", len(df.STR)) - } -} - -func TestDirectoryKeyLookupInEpochBadEpoch(t *testing.T) { - N := 3 - - d, _ := NewTestDirectory(t, true) - for i := 0; i < N; i++ { - d.Update() - } - - // Send an invalid KeyLookupInEpochRequest (epoch > d.LatestEpoch()) - // Expect ErrMalformedMessage - res := d.KeyLookupInEpoch(&protocol.KeyLookupInEpochRequest{Username: "alice", Epoch: uint64(6)}) - if res.Error != protocol.ErrMalformedMessage { - t.Fatal("Expect error", protocol.ErrMalformedMessage, "got", res.Error) - } -} - -func TestMonitoringBadStartEpoch(t *testing.T) { - N := 3 - - d, _ := NewTestDirectory(t, true) - for i := 0; i < N; i++ { - d.Update() - } - - // Send an invalid MonitoringRequest (startEpoch > d.LatestEpoch()) - // Expect ErrMalformedMessage - res := d.Monitor(&protocol.MonitoringRequest{ - Username: "alice", StartEpoch: uint64(6), EndEpoch: uint64(10), - }) - if res.Error != protocol.ErrMalformedMessage { - t.Fatal("Expect error", protocol.ErrMalformedMessage, "got", res.Error) - } - - // Send an invalid MonitoringRequest (startEpoch > EndEpoch) - // Expect ErrMalformedMessage - res = d.Monitor(&protocol.MonitoringRequest{ - Username: "alice", StartEpoch: uint64(2), EndEpoch: uint64(0), - }) - if res.Error != protocol.ErrMalformedMessage { - t.Fatal("Expect error", protocol.ErrMalformedMessage, "got", res.Error) - } -} - func TestPoliciesChanges(t *testing.T) { - d, _ := NewTestDirectory(t, true) + d := NewTestDirectory(t) if p := d.LatestSTR().Policies.EpochDeadline; p != 1 { t.Fatal("Unexpected policies", "want", 1, "got", p) } @@ -290,25 +33,74 @@ func TestPoliciesChanges(t *testing.T) { } } -func TestSTRHistoryRequestBadRange(t *testing.T) { - // create basic test directory - d, _ := NewTestDirectory(t, true) - - d.Update() - - res := d.GetSTRHistory(&protocol.STRHistoryRequest{ - StartEpoch: uint64(4), - EndEpoch: uint64(2)}) +func TestDirectoryKeyLookupInEpochBadEpoch(t *testing.T) { + d := NewTestDirectory(t) + tests := []struct { + name string + userName string + ep uint64 + want error + }{ + {"invalid username", "", 0, protocol.ErrMalformedMessage}, + {"bad end epoch", "Alice", 2, protocol.ErrMalformedMessage}, + } + for _, tt := range tests { + res := d.KeyLookupInEpoch(&protocol.KeyLookupInEpochRequest{ + Username: tt.userName, + Epoch: tt.ep, + }) + if res.Error != tt.want { + t.Errorf("Expect ErrMalformedMessage for %s", tt.name) + } + } +} - if res.Error != protocol.ErrMalformedMessage { - t.Fatal("Expect ErrMalformedMessage for bad STR history end epoch") +func TestBadRequestMonitoring(t *testing.T) { + d := NewTestDirectory(t) + + tests := []struct { + name string + userName string + startEp uint64 + endEp uint64 + want error + }{ + {"invalid username", "", 0, 0, protocol.ErrMalformedMessage}, + {"bad end epoch", "Alice", 4, 2, protocol.ErrMalformedMessage}, + {"out-of-bounds", "Alice", 2, d.LatestSTR().Epoch, protocol.ErrMalformedMessage}, + } + for _, tt := range tests { + res := d.Monitor(&protocol.MonitoringRequest{ + Username: tt.userName, + StartEpoch: tt.startEp, + EndEpoch: tt.endEp, + }) + if res.Error != tt.want { + t.Errorf("Expect ErrMalformedMessage for %s", tt.name) + } } +} - res = d.GetSTRHistory(&protocol.STRHistoryRequest{ - StartEpoch: uint64(6), - EndEpoch: uint64(d.LatestSTR().Epoch)}) +func TestBadRequestGetSTRHistory(t *testing.T) { + d := NewTestDirectory(t) + d.Update() - if res.Error != protocol.ErrMalformedMessage { - t.Fatal("Expect ErrMalformedMessage for out-of-bounds STR history") + tests := []struct { + name string + startEp uint64 + endEp uint64 + want error + }{ + {"bad end epoch", 4, 2, protocol.ErrMalformedMessage}, + {"out-of-bounds", 6, d.LatestSTR().Epoch, protocol.ErrMalformedMessage}, + } + for _, tt := range tests { + res := d.GetSTRHistory(&protocol.STRHistoryRequest{ + StartEpoch: tt.startEp, + EndEpoch: tt.endEp, + }) + if res.Error != tt.want { + t.Errorf("Expect ErrMalformedMessage for %s", tt.name) + } } } diff --git a/protocol/directory/testutil.go b/protocol/directory/testutil.go index 527beb5..f110d3e 100644 --- a/protocol/directory/testutil.go +++ b/protocol/directory/testutil.go @@ -3,29 +3,16 @@ package directory import ( "testing" - "github.com/coniks-sys/coniks-go/crypto/sign" - "github.com/coniks-sys/coniks-go/crypto/vrf" + "github.com/coniks-sys/coniks-go/crypto" + "github.com/coniks-sys/coniks-go/merkletree" ) -// TODO: refactor the function signature after resolving #47 - // NewTestDirectory creates a ConiksDirectory used for testing server-side // CONIKS operations. -func NewTestDirectory(t *testing.T, useTBs bool) ( - *ConiksDirectory, sign.PublicKey) { - - // FIXME: NewTestDirectory should use a fixed VRF and Signing keys. - vrfKey, err := vrf.GenerateKey(nil) - if err != nil { - t.Fatal(err) - } - signKey, err := sign.GenerateKey(nil) - if err != nil { - t.Fatal(err) - } - pk, _ := signKey.Public() - // epDeadline merkletree.TimeStamp, vrfKey vrf.PrivateKey, - // signKey sign.PrivateKey, dirSize uint64, useTBs bool - d := New(1, vrfKey, signKey, 10, useTBs) - return d, pk +func NewTestDirectory(t *testing.T) *ConiksDirectory { + vrfKey := crypto.StaticVRF(t) + signKey := crypto.StaticSigning(t) + d := New(1, vrfKey, signKey, 10, true) + d.pad = merkletree.StaticPAD(t, d.policies) + return d } diff --git a/protocol/error.go b/protocol/error.go index 2521423..8c9f74d 100644 --- a/protocol/error.go +++ b/protocol/error.go @@ -40,12 +40,12 @@ const ( CheckBrokenPromise ) -// Errors contains codes indicating the client +// errors contains codes indicating the client // should skip the consistency checks. These errors indicate // that either a client request could not be processed due to // a malformed client request, an internal server error or // due to a malformed server response. -var Errors = map[error]bool{ +var errors = map[error]bool{ ErrMalformedMessage: true, ErrDirectory: true, ErrAuditLog: true, diff --git a/protocol/message.go b/protocol/message.go index 9bc46ed..bafc86a 100644 --- a/protocol/message.go +++ b/protocol/message.go @@ -269,9 +269,13 @@ func NewSTRHistoryRange(str []*DirSTR) *Response { // Validate returns immediately if the message includes an error code. // Otherwise, it verifies whether the message has proper format. func (msg *Response) Validate() error { - if Errors[msg.Error] { + if errors[msg.Error] { return msg.Error } + + if msg.DirectoryResponse == nil { + return ErrMalformedMessage + } switch df := msg.DirectoryResponse.(type) { case *DirectoryProof: if len(df.STR) == 0 || len(df.AP) == 0 { diff --git a/protocol/tests/client_auditlog_test.go b/protocol/tests/client_auditlog_test.go new file mode 100644 index 0000000..ca8701d --- /dev/null +++ b/protocol/tests/client_auditlog_test.go @@ -0,0 +1 @@ +package tests diff --git a/protocol/tests/directory_auditlog_test.go b/protocol/tests/directory_auditlog_test.go new file mode 100644 index 0000000..ca8701d --- /dev/null +++ b/protocol/tests/directory_auditlog_test.go @@ -0,0 +1 @@ +package tests diff --git a/protocol/tests/directory_client_test.go b/protocol/tests/directory_client_test.go new file mode 100644 index 0000000..ca8701d --- /dev/null +++ b/protocol/tests/directory_client_test.go @@ -0,0 +1 @@ +package tests