diff --git a/client/coniksclient/internal/cmd/run.go b/client/coniksclient/internal/cmd/run.go index 23e816d..2ce429b 100644 --- a/client/coniksclient/internal/cmd/run.go +++ b/client/coniksclient/internal/cmd/run.go @@ -10,6 +10,7 @@ import ( "github.com/coniks-sys/coniks-go/client" "github.com/coniks-sys/coniks-go/keyserver/testutil" p "github.com/coniks-sys/coniks-go/protocol" + pclient "github.com/coniks-sys/coniks-go/protocol/client" "github.com/spf13/cobra" "golang.org/x/crypto/ssh/terminal" ) @@ -46,7 +47,7 @@ func init() { func run(cmd *cobra.Command) { isDebugging, _ := strconv.ParseBool(cmd.Flag("debug").Value.String()) conf := loadConfigOrExit(cmd) - cc := p.NewCC(nil, true, conf.SigningPubKey) + cc := pclient.New(nil, true, conf.SigningPubKey) state, err := terminal.MakeRaw(int(os.Stdin.Fd())) if err != nil { @@ -109,7 +110,7 @@ func run(cmd *cobra.Command) { } } -func register(cc *p.ConsistencyChecks, conf *client.Config, name string, key string) string { +func register(cc *pclient.ConsistencyChecks, conf *client.Config, name string, key string) string { req, err := client.CreateRegistrationMsg(name, []byte(key)) if err != nil { return ("Couldn't marshal registration request!") @@ -167,7 +168,7 @@ func register(cc *p.ConsistencyChecks, conf *client.Config, name string, key str return "" } -func keyLookup(cc *p.ConsistencyChecks, conf *client.Config, name string) string { +func keyLookup(cc *pclient.ConsistencyChecks, conf *client.Config, name string) string { req, err := client.CreateKeyLookupMsg(name) if err != nil { return ("Couldn't marshal key lookup request!") diff --git a/client/encoding_test.go b/client/encoding_test.go index e7812ec..d09ee1b 100644 --- a/client/encoding_test.go +++ b/client/encoding_test.go @@ -7,6 +7,7 @@ import ( "github.com/coniks-sys/coniks-go/keyserver" "github.com/coniks-sys/coniks-go/protocol" + "github.com/coniks-sys/coniks-go/protocol/directory" ) func TestUnmarshalErrorResponse(t *testing.T) { @@ -36,7 +37,7 @@ func TestUnmarshalMalformedErrorResponse(t *testing.T) { } func TestUnmarshalSampleMessage(t *testing.T) { - d, _ := protocol.NewTestDirectory(t, true) + d, _ := directory.NewTestDirectory(t, true) res, _ := d.Register(&protocol.RegistrationRequest{ Username: "alice", Key: []byte("key")}) diff --git a/keyserver/server.go b/keyserver/server.go index 86b62ce..ce63e6d 100644 --- a/keyserver/server.go +++ b/keyserver/server.go @@ -16,6 +16,7 @@ import ( "github.com/coniks-sys/coniks-go/crypto/sign" "github.com/coniks-sys/coniks-go/crypto/vrf" "github.com/coniks-sys/coniks-go/protocol" + "github.com/coniks-sys/coniks-go/protocol/directory" "github.com/coniks-sys/coniks-go/utils" ) @@ -84,7 +85,7 @@ type ConiksServer struct { logger *utils.Logger sync.RWMutex - dir *protocol.ConiksDirectory + dir *directory.ConiksDirectory stop chan struct{} waitStop sync.WaitGroup @@ -145,7 +146,7 @@ func NewConiksServer(conf *ServerConfig) *ConiksServer { // create server instance server := new(ConiksServer) server.logger = utils.NewLogger(conf.Logger) - server.dir = protocol.NewDirectory( + server.dir = directory.New( conf.Policies.EpochDeadline, conf.Policies.vrfKey, conf.Policies.signKey, diff --git a/protocol/auditlog.go b/protocol/auditlog/auditlog.go similarity index 84% rename from protocol/auditlog.go rename to protocol/auditlog/auditlog.go index bb78b0e..d6b1461 100644 --- a/protocol/auditlog.go +++ b/protocol/auditlog/auditlog.go @@ -3,17 +3,19 @@ // An audit log is a mirror of many CONIKS key directories' STR history, // allowing CONIKS clients to audit the CONIKS directories. -package protocol +package auditlog import ( "github.com/coniks-sys/coniks-go/crypto" "github.com/coniks-sys/coniks-go/crypto/sign" + p "github.com/coniks-sys/coniks-go/protocol" + "github.com/coniks-sys/coniks-go/protocol/auditor" ) type directoryHistory struct { - *AudState + *auditor.AudState addr string - snapshots map[uint64]*DirSTR + snapshots map[uint64]*p.DirSTR } // A ConiksAuditLog maintains the histories @@ -27,20 +29,22 @@ type directoryHistory struct { type ConiksAuditLog map[[crypto.HashSizeByte]byte]*directoryHistory // caller validates that initSTR is for epoch 0. -func newDirectoryHistory(addr string, signKey sign.PublicKey, initSTR *DirSTR) *directoryHistory { - a := NewAuditor(signKey, initSTR) +func newDirectoryHistory(addr string, + signKey sign.PublicKey, + initSTR *p.DirSTR) *directoryHistory { + a := auditor.New(signKey, initSTR) h := &directoryHistory{ AudState: a, addr: addr, - snapshots: make(map[uint64]*DirSTR), + snapshots: make(map[uint64]*p.DirSTR), } h.updateVerifiedSTR(initSTR) return h } -// updateVerifiedSTR inserts the latest verified STR into a directory history; -// assumes the STRs have been validated by the caller. -func (h *directoryHistory) updateVerifiedSTR(newVerified *DirSTR) { +// updateVerifiedSTR inserts the latest verified STR into a directory +// history; assumes the STRs have been validated by the caller. +func (h *directoryHistory) updateVerifiedSTR(newVerified *p.DirSTR) { h.Update(newVerified) h.snapshots[newVerified.Epoch] = newVerified } @@ -63,7 +67,7 @@ func (h *directoryHistory) insertRange(snaps []*DirSTR) { // finally updates the snapshots if the checks pass. // Audit() is called when an auditor receives new STRs // from a specific directory. -func (h *directoryHistory) Audit(msg *Response) error { +func (h *directoryHistory) Audit(msg *p.Response) error { if err := msg.validate(); err != nil { return err } @@ -86,10 +90,10 @@ func (h *directoryHistory) Audit(msg *Response) error { return nil } -// NewAuditLog constructs a new ConiksAuditLog. It creates an empty +// New constructs a new ConiksAuditLog. It creates an empty // log; the auditor will add an entry for each CONIKS directory // the first time it observes an STR for that directory. -func NewAuditLog() ConiksAuditLog { +func New() ConiksAuditLog { return make(map[[crypto.HashSizeByte]byte]*directoryHistory) } @@ -120,21 +124,21 @@ func (l ConiksAuditLog) get(dirInitHash [crypto.HashSizeByte]byte) (*directoryHi // InitHistory() returns an ErrAuditLog if the auditor attempts to create // a new history for a known directory, and nil otherwise. func (l ConiksAuditLog) InitHistory(addr string, signKey sign.PublicKey, - snaps []*DirSTR) error { + snaps []*p.DirSTR) error { // make sure we're getting an initial STR at the very least if len(snaps) < 1 || snaps[0].Epoch != 0 { // FIXME: This should be a more generic "malformed error" - return ErrMalformedDirectoryMessage + return p.ErrMalformedDirectoryMessage } // compute the hash of the initial STR - dirInitHash := ComputeDirectoryIdentity(snaps[0]) + dirInitHash := auditor.ComputeDirectoryIdentity(snaps[0]) // error if we want to create a new entry for a directory // we already know h, ok := l.get(dirInitHash) if ok { - return ErrAuditLog + return p.ErrAuditLog } // create the new directory history @@ -169,25 +173,25 @@ func (l ConiksAuditLog) InitHistory(addr string, signKey sign.PublicKey, // If the auditor doesn't have any history entries for the requested CONIKS // directory, GetObservedSTRs() returns a // message.NewErrorResponse(ReqUnknownDirectory) tuple. -func (l ConiksAuditLog) GetObservedSTRs(req *AuditingRequest) (*Response, - ErrorCode) { +func (l ConiksAuditLog) GetObservedSTRs(req *p.AuditingRequest) (*p.Response, + p.ErrorCode) { // make sure we have a history for the requested directory in the log h, ok := l.get(req.DirInitSTRHash) if !ok { - return NewErrorResponse(ReqUnknownDirectory), ReqUnknownDirectory + return p.NewErrorResponse(p.ReqUnknownDirectory), p.ReqUnknownDirectory } // make sure the request is well-formed if req.EndEpoch > h.VerifiedSTR().Epoch || req.StartEpoch > req.EndEpoch { - return NewErrorResponse(ErrMalformedClientMessage), - ErrMalformedClientMessage + return p.NewErrorResponse(p.ErrMalformedClientMessage), + p.ErrMalformedClientMessage } - var strs []*DirSTR + var strs []*p.DirSTR for ep := req.StartEpoch; ep <= req.EndEpoch; ep++ { str := h.snapshots[ep] strs = append(strs, str) } - return NewSTRHistoryRange(strs) + return p.NewSTRHistoryRange(strs) } diff --git a/protocol/auditlog_test.go b/protocol/auditlog/auditlog_test.go similarity index 93% rename from protocol/auditlog_test.go rename to protocol/auditlog/auditlog_test.go index 724ff4e..d59d1b9 100644 --- a/protocol/auditlog_test.go +++ b/protocol/auditlog/auditlog_test.go @@ -1,8 +1,11 @@ -package protocol +package auditlog import ( - "github.com/coniks-sys/coniks-go/crypto" "testing" + + "github.com/coniks-sys/coniks-go/crypto" + . "github.com/coniks-sys/coniks-go/protocol" + "github.com/coniks-sys/coniks-go/protocol/auditor" ) func TestInsertEmptyHistory(t *testing.T) { @@ -15,7 +18,7 @@ func TestUpdateHistory(t *testing.T) { d, aud, hist := NewTestAuditLog(t, 0) // update the directory so we can update the audit log - dirInitHash := ComputeDirectoryIdentity(hist[0]) + dirInitHash := auditor.ComputeDirectoryIdentity(hist[0]) d.Update() h, _ := aud.get(dirInitHash) resp, _ := NewSTRHistoryRange([]*DirSTR{d.LatestSTR()}) @@ -68,7 +71,7 @@ func TestAuditLogBadEpochRange(t *testing.T) { } // compute the hash of the initial STR for later lookups - dirInitHash := ComputeDirectoryIdentity(hist[0]) + dirInitHash := auditor.ComputeDirectoryIdentity(hist[0]) h, _ := aud.get(dirInitHash) err1 := h.Audit(resp) @@ -89,7 +92,7 @@ func TestGetLatestObservedSTR(t *testing.T) { d, aud, hist := NewTestAuditLog(t, 0) // compute the hash of the initial STR for later lookups - dirInitHash := ComputeDirectoryIdentity(hist[0]) + dirInitHash := auditor.ComputeDirectoryIdentity(hist[0]) res, err := aud.GetObservedSTRs(&AuditingRequest{ DirInitSTRHash: dirInitHash, @@ -113,7 +116,7 @@ func TestGetObservedSTRInEpoch(t *testing.T) { _, aud, hist := NewTestAuditLog(t, 10) // compute the hash of the initial STR for later lookups - dirInitHash := ComputeDirectoryIdentity(hist[0]) + dirInitHash := auditor.ComputeDirectoryIdentity(hist[0]) res, err := aud.GetObservedSTRs(&AuditingRequest{ DirInitSTRHash: dirInitHash, @@ -141,7 +144,7 @@ func TestGetObservedSTRMultipleEpochs(t *testing.T) { d, aud, hist := NewTestAuditLog(t, 1) // compute the hash of the initial STR for later lookups - dirInitHash := ComputeDirectoryIdentity(hist[0]) + dirInitHash := auditor.ComputeDirectoryIdentity(hist[0]) // first AuditingRequest res, err := aud.GetObservedSTRs(&AuditingRequest{ @@ -222,7 +225,7 @@ func TestGetObservedSTRMalformed(t *testing.T) { _, aud, hist := NewTestAuditLog(t, 10) // compute the hash of the initial STR for later lookups - dirInitHash := ComputeDirectoryIdentity(hist[0]) + dirInitHash := auditor.ComputeDirectoryIdentity(hist[0]) // also test the epoch range _, err := aud.GetObservedSTRs(&AuditingRequest{ diff --git a/protocol/auditlog/testutil.go b/protocol/auditlog/testutil.go new file mode 100644 index 0000000..af1a90f --- /dev/null +++ b/protocol/auditlog/testutil.go @@ -0,0 +1,35 @@ +package auditlog + +import ( + "testing" + + p "github.com/coniks-sys/coniks-go/protocol" + "github.com/coniks-sys/coniks-go/protocol/directory" +) + +// NewTestAuditLog creates a ConiksAuditLog and corresponding +// ConiksDirectory used for testing auditor-side CONIKS operations. +// The new audit log can be initialized with the number of epochs +// indicating the length of the directory history with which to +// initialize the log; if numEpochs > 0, the history contains numEpochs+1 +// STRs as it always includes the STR after the last directory update +func NewTestAuditLog(t *testing.T, numEpochs int) ( + *directory.ConiksDirectory, ConiksAuditLog, []*p.DirSTR) { + d, pk := directory.NewTestDirectory(t, true) + aud := New() + + var hist []*p.DirSTR + for ep := 0; ep < numEpochs; ep++ { + hist = append(hist, d.LatestSTR()) + d.Update() + } + // always include the actual latest STR + hist = append(hist, d.LatestSTR()) + + err := aud.Insert("test-server", pk, hist) + if err != nil { + t.Fatalf("Error inserting a new history with %d STRs", numEpochs+1) + } + + return d, aud, hist +} diff --git a/protocol/auditor.go b/protocol/auditor/auditor.go similarity index 67% rename from protocol/auditor.go rename to protocol/auditor/auditor.go index 92d16ee..d45346e 100644 --- a/protocol/auditor.go +++ b/protocol/auditor/auditor.go @@ -2,32 +2,31 @@ // functionality that clients and auditors need to verify // a server's STR history. -package protocol +package auditor import ( - "fmt" "reflect" - "github.com/coniks-sys/coniks-go/crypto" "github.com/coniks-sys/coniks-go/crypto/sign" + p "github.com/coniks-sys/coniks-go/protocol" ) // Auditor provides a generic interface allowing different // auditor types to implement specific auditing functionality. type Auditor interface { - AuditDirectory([]*DirSTR) error + AuditDirectory([]*p.DirSTR) error } // AudState verifies the hash chain of a specific directory. type AudState struct { signKey sign.PublicKey - verifiedSTR *DirSTR + verifiedSTR *p.DirSTR } var _ Auditor = (*AudState)(nil) -// NewAuditor instantiates a new auditor state from a persistance storage. -func NewAuditor(signKey sign.PublicKey, verified *DirSTR) *AudState { +// New instantiates a new auditor state from a persistance storage. +func New(signKey sign.PublicKey, verified *p.DirSTR) *AudState { a := &AudState{ signKey: signKey, verifiedSTR: verified, @@ -35,24 +34,29 @@ func NewAuditor(signKey sign.PublicKey, verified *DirSTR) *AudState { return a } +// Verify verifies a signature sig on message using the underlying +// public-key of the AudState. +func (a *AudState) Verify(message, sig []byte) bool { + return a.signKey.Verify(message, sig) +} + // VerifiedSTR returns the newly verified STR. -func (a *AudState) VerifiedSTR() *DirSTR { +func (a *AudState) VerifiedSTR() *p.DirSTR { return a.verifiedSTR } // Update updates the auditor's verifiedSTR to newSTR -func (a *AudState) Update(newSTR *DirSTR) { +func (a *AudState) Update(newSTR *p.DirSTR) { a.verifiedSTR = newSTR } // compareWithVerified checks whether the received STR is the same as // the verified STR in the AudState using reflect.DeepEqual(). -func (a *AudState) compareWithVerified(str *DirSTR) error { +func (a *AudState) compareWithVerified(str *p.DirSTR) error { if reflect.DeepEqual(a.verifiedSTR, str) { return nil } - - return CheckBadSTR + return p.CheckBadSTR } // verifySTRConsistency checks the consistency between 2 snapshots. @@ -60,29 +64,29 @@ func (a *AudState) compareWithVerified(str *DirSTR) error { // The signKey param either comes from a client's // pinned signing key in its consistency state, // or an auditor's pinned signing key in its history. -func (a *AudState) verifySTRConsistency(prevSTR, str *DirSTR) error { +func (a *AudState) verifySTRConsistency(prevSTR, str *p.DirSTR) error { // verify STR's signature if !a.signKey.Verify(str.Serialize(), str.Signature) { - return CheckBadSignature + return p.CheckBadSignature } if str.VerifyHashChain(prevSTR) { return nil } // TODO: verify the directory's policies as well. See #115 - return CheckBadSTR + return p.CheckBadSTR } -// checkSTRAgainstVerified checks an STR str against the a.verifiedSTR. -// If str's Epoch is the same as the verified, checkSTRAgainstVerified() +// CheckSTRAgainstVerified checks an STR str against the a.verifiedSTR. +// If str's Epoch is the same as the verified, CheckSTRAgainstVerified() // compares the two STRs directly. If str is one epoch ahead of the -// a.verifiedSTR, checkSTRAgainstVerified() checks the consistency between +// a.verifiedSTR, CheckSTRAgainstVerified() checks the consistency between // the two STRs. -// checkSTRAgainstVerified() returns nil if the check passes, +// CheckSTRAgainstVerified() returns nil if the check passes, // or the appropriate consistency check error if any of the checks fail, // or str's epoch is anything other than the same or one ahead of // a.verifiedSTR. -func (a *AudState) checkSTRAgainstVerified(str *DirSTR) error { +func (a *AudState) CheckSTRAgainstVerified(str *p.DirSTR) error { // FIXME: check whether the STR was issued on time and whatnot. // Maybe it has something to do w/ #81 and client // transitioning between epochs. @@ -103,24 +107,24 @@ func (a *AudState) checkSTRAgainstVerified(str *DirSTR) error { return err } default: - return CheckBadSTR + return p.CheckBadSTR } - return CheckPassed + return nil } -// verifySTRRange checks the consistency of a range +// VerifySTRRange checks the consistency of a range // of a directory's STRs. It begins by verifying the STR consistency between // the given prevSTR and the first STR in the given range, and // then verifies the consistency between each subsequent STR pair. -func (a *AudState) verifySTRRange(prevSTR *DirSTR, strs []*DirSTR) error { +func (a *AudState) VerifySTRRange(prevSTR *p.DirSTR, strs []*p.DirSTR) error { prev := prevSTR for i := 0; i < len(strs); i++ { str := strs[i] if str == nil { // FIXME: if this comes from the auditor, this // should really be an ErrMalformedAuditorMessage - return ErrMalformedDirectoryMessage + return p.ErrMalformedDirectoryMessage } // verify the consistency of each STR in the range @@ -140,36 +144,23 @@ func (a *AudState) verifySTRRange(prevSTR *DirSTR, strs []*DirSTR) error { // range if the message contains more than one STR. // AuditDirectory() returns the appropriate consistency check error // if any of the checks fail, or nil if the checks pass. -func (a *AudState) AuditDirectory(strs []*DirSTR) error { +func (a *AudState) AuditDirectory(strs []*p.DirSTR) error { // validate strs if len(strs) == 0 { - return ErrMalformedDirectoryMessage + return p.ErrMalformedDirectoryMessage } // check STR against the latest verified STR - if err := a.checkSTRAgainstVerified(strs[0]); err != CheckPassed { + if err := a.CheckSTRAgainstVerified(strs[0]); err != nil { return err } // verify the entire range if we have received more than one STR if len(strs) > 1 { - if err := a.verifySTRRange(strs[0], strs[1:]); err != nil { + if err := a.VerifySTRRange(strs[0], strs[1:]); err != nil { return err } } - return CheckPassed -} - -// ComputeDirectoryIdentity returns the hash of -// the directory's initial STR as a byte array. -// It panics if the STR isn't an initial STR (i.e. str.Epoch != 0). -func ComputeDirectoryIdentity(str *DirSTR) [crypto.HashSizeByte]byte { - if str.Epoch != 0 { - panic(fmt.Sprintf("[coniks] Expect epoch 0, got %x", str.Epoch)) - } - - var initSTRHash [crypto.HashSizeByte]byte - copy(initSTRHash[:], crypto.Digest(str.Signature)) - return initSTRHash + return p.CheckPassed } diff --git a/protocol/auditor/common.go b/protocol/auditor/common.go new file mode 100644 index 0000000..59d79e3 --- /dev/null +++ b/protocol/auditor/common.go @@ -0,0 +1,21 @@ +package auditor + +import ( + "fmt" + + "github.com/coniks-sys/coniks-go/crypto" + "github.com/coniks-sys/coniks-go/protocol" +) + +// ComputeDirectoryIdentity returns the hash of +// the directory's initial STR as a byte array. +// It panics if the STR isn't an initial STR (i.e. str.Epoch != 0). +func ComputeDirectoryIdentity(str *protocol.DirSTR) [crypto.HashSizeByte]byte { + if str.Epoch != 0 { + panic(fmt.Sprintf("[coniks] Expect epoch 0, got %x", str.Epoch)) + } + + var initSTRHash [crypto.HashSizeByte]byte + copy(initSTRHash[:], crypto.Digest(str.Signature)) + return initSTRHash +} diff --git a/protocol/auditor_test.go b/protocol/auditor/common_test.go similarity index 95% rename from protocol/auditor_test.go rename to protocol/auditor/common_test.go index a64c6ca..8731550 100644 --- a/protocol/auditor_test.go +++ b/protocol/auditor/common_test.go @@ -1,19 +1,21 @@ -package protocol +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 TestComputeDirectoryIdentity(t *testing.T) { - d, _ := NewTestDirectory(t, true) + d, _ := directory.NewTestDirectory(t, true) // str0 := d.LatestSTR() d.Update() str1 := d.LatestSTR() var unknown [crypto.HashSizeByte]byte type args struct { - str *DirSTR + str *protocol.DirSTR } tests := []struct { name string diff --git a/protocol/consistencychecks.go b/protocol/client/consistencychecks.go similarity index 69% rename from protocol/consistencychecks.go rename to protocol/client/consistencychecks.go index 25ae0bb..76df175 100644 --- a/protocol/consistencychecks.go +++ b/protocol/client/consistencychecks.go @@ -2,15 +2,16 @@ // on data received from a CONIKS directory. // These include data binding proof verification, // and non-equivocation checks. -// TODO: move all STR-verifying functionality to a separate module -package protocol +package client import ( "bytes" "github.com/coniks-sys/coniks-go/crypto/sign" m "github.com/coniks-sys/coniks-go/merkletree" + p "github.com/coniks-sys/coniks-go/protocol" + "github.com/coniks-sys/coniks-go/protocol/auditor" ) // ConsistencyChecks stores the latest consistency check @@ -27,23 +28,23 @@ import ( type ConsistencyChecks struct { // the auditor state stores the latest verified signed tree root // as well as the server's signing key - *AudState + *auditor.AudState Bindings map[string][]byte // extensions settings useTBs bool - TBs map[string]*TemporaryBinding + TBs map[string]*p.TemporaryBinding } -// NewCC creates an instance of ConsistencyChecks using +// New creates an instance of ConsistencyChecks using // a CONIKS directory's pinned STR at epoch 0, or // the consistency state read from persistent storage. -func NewCC(savedSTR *DirSTR, useTBs bool, signKey sign.PublicKey) *ConsistencyChecks { +func New(savedSTR *p.DirSTR, useTBs bool, signKey sign.PublicKey) *ConsistencyChecks { // TODO: see #110 if !useTBs { panic("[coniks] Currently the server is forced to use TBs") } - a := NewAuditor(signKey, savedSTR) + a := auditor.New(signKey, savedSTR) cc := &ConsistencyChecks{ AudState: a, Bindings: make(map[string][]byte), @@ -51,7 +52,7 @@ func NewCC(savedSTR *DirSTR, useTBs bool, signKey sign.PublicKey) *ConsistencyCh TBs: nil, } if useTBs { - cc.TBs = make(map[string]*TemporaryBinding) + cc.TBs = make(map[string]*p.TemporaryBinding) } return cc } @@ -64,17 +65,17 @@ func NewCC(savedSTR *DirSTR, useTBs bool, signKey sign.PublicKey) *ConsistencyCh // the cc.verifiedSTR. // CheckEquivocation() is called when a client receives a response to a // message.AuditingRequest from an auditor. -func (cc *ConsistencyChecks) CheckEquivocation(msg *Response) error { - if err := msg.validate(); err != nil { - return err.(ErrorCode) +func (cc *ConsistencyChecks) CheckEquivocation(msg *p.Response) error { + if err := msg.Validate(); err != nil { + return err } - strs := msg.DirectoryResponse.(*STRHistoryRange) + strs := msg.DirectoryResponse.(*p.STRHistoryRange) // verify the hashchain of the received STRs // if we get more than 1 in our range if len(strs.STR) > 1 { - if err := cc.verifySTRRange(strs.STR[0], strs.STR[1:]); err != nil { + if err := cc.VerifySTRRange(strs.STR[0], strs.STR[1:]); err != nil { return err } } @@ -82,7 +83,7 @@ func (cc *ConsistencyChecks) CheckEquivocation(msg *Response) error { // TODO: if the auditor has returned a more recent STR, // should the client update its savedSTR? Should this // force a new round of monitoring? - return cc.checkSTRAgainstVerified(strs.STR[len(strs.STR)-1]) + return cc.CheckSTRAgainstVerified(strs.STR[len(strs.STR)-1]) } // HandleResponse verifies the directory's response for a request. @@ -98,42 +99,42 @@ func (cc *ConsistencyChecks) CheckEquivocation(msg *Response) error { // Note that the consistency state will be updated regardless of // whether the checks pass / fail, since a response message contains // cryptographic proof of having been issued nonetheless. -func (cc *ConsistencyChecks) HandleResponse(requestType int, msg *Response, - uname string, key []byte) ErrorCode { - if err := msg.validate(); err != nil { - return err.(ErrorCode) +func (cc *ConsistencyChecks) HandleResponse(requestType int, msg *p.Response, + uname string, key []byte) p.ErrorCode { + if err := msg.Validate(); err != nil { + return err.(p.ErrorCode) } switch requestType { - case RegistrationType, KeyLookupType, KeyLookupInEpochType, MonitoringType: - if _, ok := msg.DirectoryResponse.(*DirectoryProof); !ok { - return ErrMalformedDirectoryMessage + case p.RegistrationType, p.KeyLookupType, p.KeyLookupInEpochType, p.MonitoringType: + if _, ok := msg.DirectoryResponse.(*p.DirectoryProof); !ok { + return p.ErrMalformedDirectoryMessage } default: panic("[coniks] Unknown request type") } if err := cc.updateSTR(requestType, msg); err != nil { - return err.(ErrorCode) + return err.(p.ErrorCode) } - if err := cc.checkConsistency(requestType, msg, uname, key); err != CheckPassed { + if err := cc.checkConsistency(requestType, msg, uname, key); err != p.CheckPassed { return err } if err := cc.updateTBs(requestType, msg, uname, key); err != nil { - return err.(ErrorCode) + return err.(p.ErrorCode) } recvKey, _ := msg.GetKey() cc.Bindings[uname] = recvKey - return CheckPassed + return p.CheckPassed } -func (cc *ConsistencyChecks) updateSTR(requestType int, msg *Response) error { - var str *DirSTR +func (cc *ConsistencyChecks) updateSTR(requestType int, msg *p.Response) error { + var str *p.DirSTR switch requestType { - case RegistrationType, KeyLookupType: - str = msg.DirectoryResponse.(*DirectoryProof).STR[0] + case p.RegistrationType, p.KeyLookupType: + str = msg.DirectoryResponse.(*p.DirectoryProof).STR[0] // The initial STR is pinned in the client // so cc.verifiedSTR should never be nil // FIXME: use STR slice from Response msg - if err := cc.AuditDirectory([]*DirSTR{str}); err != CheckPassed { + if err := cc.AuditDirectory([]*p.DirSTR{str}); err != nil { return err } @@ -147,23 +148,23 @@ func (cc *ConsistencyChecks) updateSTR(requestType int, msg *Response) error { return nil } -func (cc *ConsistencyChecks) checkConsistency(requestType int, msg *Response, - uname string, key []byte) ErrorCode { +func (cc *ConsistencyChecks) checkConsistency(requestType int, msg *p.Response, + uname string, key []byte) p.ErrorCode { var err error switch requestType { - case RegistrationType: + case p.RegistrationType: err = cc.verifyRegistration(msg, uname, key) - case KeyLookupType: + case p.KeyLookupType: err = cc.verifyKeyLookup(msg, uname, key) default: panic("[coniks] Unknown request type") } - return err.(ErrorCode) + return err.(p.ErrorCode) } -func (cc *ConsistencyChecks) verifyRegistration(msg *Response, +func (cc *ConsistencyChecks) verifyRegistration(msg *p.Response, uname string, key []byte) error { - df := msg.DirectoryResponse.(*DirectoryProof) + df := msg.DirectoryResponse.(*p.DirectoryProof) // FIXME: should explicitly validate that // len(df.AP) == len(df.STR) == 1 ap := df.AP[0] @@ -171,23 +172,23 @@ func (cc *ConsistencyChecks) verifyRegistration(msg *Response, proofType := ap.ProofType() switch { - case msg.Error == ReqNameExisted && proofType == m.ProofOfInclusion: - case msg.Error == ReqNameExisted && proofType == m.ProofOfAbsence && cc.useTBs: - case msg.Error == ReqSuccess && proofType == m.ProofOfAbsence: + case msg.Error == p.ReqNameExisted && proofType == m.ProofOfInclusion: + case msg.Error == p.ReqNameExisted && proofType == m.ProofOfAbsence && cc.useTBs: + case msg.Error == p.ReqSuccess && proofType == m.ProofOfAbsence: default: - return ErrMalformedDirectoryMessage + return p.ErrMalformedDirectoryMessage } if err := verifyAuthPath(uname, key, ap, str); err != nil { return err } - return CheckPassed + return p.CheckPassed } -func (cc *ConsistencyChecks) verifyKeyLookup(msg *Response, +func (cc *ConsistencyChecks) verifyKeyLookup(msg *p.Response, uname string, key []byte) error { - df := msg.DirectoryResponse.(*DirectoryProof) + df := msg.DirectoryResponse.(*p.DirectoryProof) // FIXME: should explicitly validate that // len(df.AP) == len(df.STR) == 1 ap := df.AP[0] @@ -195,26 +196,26 @@ func (cc *ConsistencyChecks) verifyKeyLookup(msg *Response, proofType := ap.ProofType() switch { - case msg.Error == ReqNameNotFound && proofType == m.ProofOfAbsence: + case msg.Error == p.ReqNameNotFound && proofType == m.ProofOfAbsence: // FIXME: This would be changed when we support key changes - case msg.Error == ReqSuccess && proofType == m.ProofOfInclusion: - case msg.Error == ReqSuccess && proofType == m.ProofOfAbsence && cc.useTBs: + case msg.Error == p.ReqSuccess && proofType == m.ProofOfInclusion: + case msg.Error == p.ReqSuccess && proofType == m.ProofOfAbsence && cc.useTBs: default: - return ErrMalformedDirectoryMessage + return p.ErrMalformedDirectoryMessage } if err := verifyAuthPath(uname, key, ap, str); err != nil { return err } - return CheckPassed + return p.CheckPassed } -func verifyAuthPath(uname string, key []byte, ap *m.AuthenticationPath, str *DirSTR) error { +func verifyAuthPath(uname string, key []byte, ap *m.AuthenticationPath, str *p.DirSTR) error { // verify VRF Index vrfKey := str.Policies.VrfPublicKey if !vrfKey.Verify([]byte(uname), ap.LookupIndex, ap.VrfProof) { - return CheckBadVRFProof + return p.CheckBadVRFProof } if key == nil { @@ -225,13 +226,13 @@ func verifyAuthPath(uname string, key []byte, ap *m.AuthenticationPath, str *Dir switch err := ap.Verify([]byte(uname), key, str.TreeHash); err { case m.ErrBindingsDiffer: - return CheckBindingsDiffer + return p.CheckBindingsDiffer case m.ErrUnverifiableCommitment: - return CheckBadCommitment + return p.CheckBadCommitment case m.ErrIndicesMismatch: - return CheckBadLookupIndex + return p.CheckBadLookupIndex case m.ErrUnequalTreeHashes: - return CheckBadAuthPath + return p.CheckBadAuthPath case nil: return nil default: @@ -239,14 +240,14 @@ func verifyAuthPath(uname string, key []byte, ap *m.AuthenticationPath, str *Dir } } -func (cc *ConsistencyChecks) updateTBs(requestType int, msg *Response, +func (cc *ConsistencyChecks) updateTBs(requestType int, msg *p.Response, uname string, key []byte) error { if !cc.useTBs { return nil } switch requestType { - case RegistrationType: - df := msg.DirectoryResponse.(*DirectoryProof) + case p.RegistrationType: + df := msg.DirectoryResponse.(*p.DirectoryProof) if df.AP[0].ProofType() == m.ProofOfAbsence { if err := cc.verifyReturnedPromise(df, key); err != nil { return err @@ -255,19 +256,19 @@ func (cc *ConsistencyChecks) updateTBs(requestType int, msg *Response, } return nil - case KeyLookupType: - df := msg.DirectoryResponse.(*DirectoryProof) + case p.KeyLookupType: + df := msg.DirectoryResponse.(*p.DirectoryProof) ap := df.AP[0] str := df.STR[0] proofType := ap.ProofType() switch { - case msg.Error == ReqSuccess && proofType == m.ProofOfInclusion: + case msg.Error == p.ReqSuccess && proofType == m.ProofOfInclusion: if err := cc.verifyFulfilledPromise(uname, str, ap); err != nil { return err } delete(cc.TBs, uname) - case msg.Error == ReqSuccess && proofType == m.ProofOfAbsence: + case msg.Error == p.ReqSuccess && proofType == m.ProofOfAbsence: if err := cc.verifyReturnedPromise(df, key); err != nil { return err } @@ -282,13 +283,13 @@ func (cc *ConsistencyChecks) updateTBs(requestType int, msg *Response, // verifyFulfilledPromise verifies issued TBs were inserted // in the directory as promised. -func (cc *ConsistencyChecks) verifyFulfilledPromise(uname string, str *DirSTR, +func (cc *ConsistencyChecks) verifyFulfilledPromise(uname string, str *p.DirSTR, ap *m.AuthenticationPath) error { // FIXME: Which epoch did this lookup happen in? if tb, ok := cc.TBs[uname]; ok { if !bytes.Equal(ap.LookupIndex, tb.Index) || !bytes.Equal(ap.Leaf.Value, tb.Value) { - return CheckBrokenPromise + return p.CheckBrokenPromise } } return nil @@ -304,29 +305,29 @@ func (cc *ConsistencyChecks) verifyFulfilledPromise(uname string, str *DirSTR, // If the request is a key lookup, and // - the request is successful, then the directory should return a promise for the lookup binding. // These above checks should be performed before calling this method. -func (cc *ConsistencyChecks) verifyReturnedPromise(df *DirectoryProof, +func (cc *ConsistencyChecks) verifyReturnedPromise(df *p.DirectoryProof, key []byte) error { ap := df.AP[0] str := df.STR[0] tb := df.TB if tb == nil { - return CheckBadPromise + return p.CheckBadPromise } // verify TB's Signature - if !cc.signKey.Verify(tb.Serialize(str.Signature), tb.Signature) { - return CheckBadSignature + if !cc.Verify(tb.Serialize(str.Signature), tb.Signature) { + return p.CheckBadSignature } if !bytes.Equal(tb.Index, ap.LookupIndex) { - return CheckBadPromise + return p.CheckBadPromise } // key could be nil if we have no information about // the existed binding (TOFU). if key != nil && !bytes.Equal(tb.Value, key) { - return CheckBindingsDiffer + return p.CheckBindingsDiffer } return nil } diff --git a/protocol/consistencychecks_test.go b/protocol/client/consistencychecks_test.go similarity index 87% rename from protocol/consistencychecks_test.go rename to protocol/client/consistencychecks_test.go index 4f5f42b..a664e45 100644 --- a/protocol/consistencychecks_test.go +++ b/protocol/client/consistencychecks_test.go @@ -1,8 +1,11 @@ -package protocol +package client import ( "bytes" "testing" + + . "github.com/coniks-sys/coniks-go/protocol" + dir "github.com/coniks-sys/coniks-go/protocol/directory" ) var ( @@ -11,7 +14,7 @@ var ( key = []byte("key") ) -func registerAndVerify(d *ConiksDirectory, cc *ConsistencyChecks, +func registerAndVerify(d *dir.ConiksDirectory, cc *ConsistencyChecks, name string, key []byte) (error, error) { request := &RegistrationRequest{ Username: name, @@ -21,7 +24,7 @@ func registerAndVerify(d *ConiksDirectory, cc *ConsistencyChecks, return err, cc.HandleResponse(RegistrationType, res, name, key) } -func lookupAndVerify(d *ConiksDirectory, cc *ConsistencyChecks, +func lookupAndVerify(d *dir.ConiksDirectory, cc *ConsistencyChecks, name string, key []byte) (error, error) { request := &KeyLookupRequest{ Username: name, @@ -31,8 +34,8 @@ func lookupAndVerify(d *ConiksDirectory, cc *ConsistencyChecks, } func TestMalformedClientMessage(t *testing.T) { - d, pk := NewTestDirectory(t, true) - cc := NewCC(d.LatestSTR(), true, pk) + d, pk := dir.NewTestDirectory(t, true) + cc := New(d.LatestSTR(), true, pk) request := &RegistrationRequest{ Username: "", // invalid username @@ -40,13 +43,14 @@ func TestMalformedClientMessage(t *testing.T) { } res, _ := d.Register(request) if err := cc.HandleResponse(RegistrationType, res, "", key); err != ErrMalformedClientMessage { - t.Error("Unexpected verification result") + t.Error("Unexpected verification result", + "got", err) } } func TestMalformedDirectoryMessage(t *testing.T) { - d, pk := NewTestDirectory(t, true) - cc := NewCC(d.LatestSTR(), true, pk) + d, pk := dir.NewTestDirectory(t, true) + cc := New(d.LatestSTR(), true, pk) request := &RegistrationRequest{ Username: "alice", @@ -61,9 +65,9 @@ func TestMalformedDirectoryMessage(t *testing.T) { } func TestVerifyRegistrationResponseWithTB(t *testing.T) { - d, pk := NewTestDirectory(t, true) + d, pk := dir.NewTestDirectory(t, true) - cc := NewCC(d.LatestSTR(), true, pk) + cc := New(d.LatestSTR(), true, pk) if e1, e2 := registerAndVerify(d, cc, alice, key); e1 != ReqSuccess || e2 != CheckPassed { t.Error(e1) @@ -105,9 +109,9 @@ func TestVerifyRegistrationResponseWithTB(t *testing.T) { } func TestVerifyFullfilledPromise(t *testing.T) { - d, pk := NewTestDirectory(t, true) + d, pk := dir.NewTestDirectory(t, true) - cc := NewCC(d.LatestSTR(), true, pk) + cc := New(d.LatestSTR(), true, pk) if e1, e2 := registerAndVerify(d, cc, alice, key); e1 != ReqSuccess || e2 != CheckPassed { t.Error(e1) @@ -146,9 +150,9 @@ func TestVerifyFullfilledPromise(t *testing.T) { } func TestVerifyKeyLookupResponseWithTB(t *testing.T) { - d, pk := NewTestDirectory(t, true) + d, pk := dir.NewTestDirectory(t, true) - cc := NewCC(d.LatestSTR(), true, pk) + cc := New(d.LatestSTR(), true, pk) // do lookup first if e1, e2 := lookupAndVerify(d, cc, alice, key); e1 != ReqNameNotFound || e2 != CheckPassed { diff --git a/protocol/directory.go b/protocol/directory/directory.go similarity index 81% rename from protocol/directory.go rename to protocol/directory/directory.go index 34ac607..6509f78 100644 --- a/protocol/directory.go +++ b/protocol/directory/directory.go @@ -6,7 +6,7 @@ // lookups, and monitoring. // It does not yet support key changes. -package protocol +package directory import ( "bytes" @@ -14,6 +14,7 @@ import ( "github.com/coniks-sys/coniks-go/crypto/sign" "github.com/coniks-sys/coniks-go/crypto/vrf" "github.com/coniks-sys/coniks-go/merkletree" + p "github.com/coniks-sys/coniks-go/protocol" ) // A ConiksDirectory maintains the underlying persistent @@ -26,11 +27,11 @@ import ( type ConiksDirectory struct { pad *merkletree.PAD useTBs bool - tbs map[string]*TemporaryBinding - policies *Policies + tbs map[string]*p.TemporaryBinding + policies *p.Policies } -// NewDirectory constructs a new ConiksDirectory given the key server's PAD +// New constructs a new ConiksDirectory given the key server's PAD // policies (i.e. epDeadline, vrfKey). // // signKey is the private key the key server uses to generate signed tree @@ -38,7 +39,7 @@ type ConiksDirectory struct { // dirSize indicates the number of PAD snapshots the server keeps in memory. // useTBs indicates whether the key server returns TBs upon a successful // registration. -func NewDirectory(epDeadline Timestamp, vrfKey vrf.PrivateKey, +func New(epDeadline p.Timestamp, vrfKey vrf.PrivateKey, signKey sign.PrivateKey, dirSize uint64, useTBs bool) *ConiksDirectory { // FIXME: see #110 if !useTBs { @@ -49,7 +50,7 @@ func NewDirectory(epDeadline Timestamp, vrfKey vrf.PrivateKey, if !ok { panic(vrf.ErrGetPubKey) } - d.policies = NewPolicies(epDeadline, vrfPublicKey) + d.policies = p.NewPolicies(epDeadline, vrfPublicKey) pad, err := merkletree.NewPAD(d.policies, signKey, vrfKey, dirSize) if err != nil { panic(err) @@ -57,7 +58,7 @@ func NewDirectory(epDeadline Timestamp, vrfKey vrf.PrivateKey, d.pad = pad d.useTBs = useTBs if useTBs { - d.tbs = make(map[string]*TemporaryBinding) + d.tbs = make(map[string]*p.TemporaryBinding) } return d } @@ -76,27 +77,27 @@ func (d *ConiksDirectory) Update() { // SetPolicies sets this ConiksDirectory's epoch deadline, which will be used // in the next epoch. -func (d *ConiksDirectory) SetPolicies(epDeadline Timestamp) { - d.policies = NewPolicies(epDeadline, d.policies.VrfPublicKey) +func (d *ConiksDirectory) SetPolicies(epDeadline p.Timestamp) { + d.policies = p.NewPolicies(epDeadline, d.policies.VrfPublicKey) } // EpochDeadline returns this ConiksDirectory's latest epoch deadline // as a timestamp. -func (d *ConiksDirectory) EpochDeadline() Timestamp { - return GetPolicies(d.pad.LatestSTR()).EpochDeadline +func (d *ConiksDirectory) EpochDeadline() p.Timestamp { + return p.GetPolicies(d.pad.LatestSTR()).EpochDeadline } // LatestSTR returns this ConiksDirectory's latest STR. -func (d *ConiksDirectory) LatestSTR() *DirSTR { - return NewDirSTR(d.pad.LatestSTR()) +func (d *ConiksDirectory) LatestSTR() *p.DirSTR { + return p.NewDirSTR(d.pad.LatestSTR()) } // NewTB creates a new temporary binding for the given name-to-key mapping. // NewTB() computes the private index for the name, and // digitally signs the (index, key, latest STR signature) tuple. -func (d *ConiksDirectory) NewTB(name string, key []byte) *TemporaryBinding { +func (d *ConiksDirectory) NewTB(name string, key []byte) *p.TemporaryBinding { index := d.pad.Index(name) - return &TemporaryBinding{ + return &p.TemporaryBinding{ Index: index, Value: key, Signature: d.pad.Sign(d.LatestSTR().Signature, index, key), @@ -127,43 +128,43 @@ func (d *ConiksDirectory) NewTB(name string, key []byte) *TemporaryBinding { // In any case, str is the signed tree root for the latest epoch. // If Register() encounters an internal error at any point, it returns // a message.NewErrorResponse(ErrDirectory) tuple. -func (d *ConiksDirectory) Register(req *RegistrationRequest) ( - *Response, ErrorCode) { +func (d *ConiksDirectory) Register(req *p.RegistrationRequest) ( + *p.Response, p.ErrorCode) { // make sure the request is well-formed if len(req.Username) <= 0 || len(req.Key) <= 0 { - return NewErrorResponse(ErrMalformedClientMessage), - ErrMalformedClientMessage + return p.NewErrorResponse(p.ErrMalformedClientMessage), + p.ErrMalformedClientMessage } // check whether the name already exists // in the directory before we register ap, err := d.pad.Lookup(req.Username) if err != nil { - return NewErrorResponse(ErrDirectory), ErrDirectory + return p.NewErrorResponse(p.ErrDirectory), p.ErrDirectory } if bytes.Equal(ap.LookupIndex, ap.Leaf.Index) { - return NewRegistrationProof(ap, d.LatestSTR(), nil, ReqNameExisted) + return p.NewRegistrationProof(ap, d.LatestSTR(), nil, p.ReqNameExisted) } - var tb *TemporaryBinding + var tb *p.TemporaryBinding if d.useTBs { // also check the temporary bindings array // currently the server allows only one registration/key change per epoch if tb = d.tbs[req.Username]; tb != nil { - return NewRegistrationProof(ap, d.LatestSTR(), tb, ReqNameExisted) + return p.NewRegistrationProof(ap, d.LatestSTR(), tb, p.ReqNameExisted) } tb = d.NewTB(req.Username, req.Key) } if err = d.pad.Set(req.Username, req.Key); err != nil { - return NewErrorResponse(ErrDirectory), ErrDirectory + return p.NewErrorResponse(p.ErrDirectory), p.ErrDirectory } if tb != nil { d.tbs[req.Username] = tb } - return NewRegistrationProof(ap, d.LatestSTR(), tb, ReqSuccess) + return p.NewRegistrationProof(ap, d.LatestSTR(), tb, p.ReqSuccess) } // KeyLookup gets the public key for the username indicated in the @@ -189,30 +190,30 @@ func (d *ConiksDirectory) Register(req *RegistrationRequest) ( // In any case, str is the signed tree root for the latest epoch. // If KeyLookup() encounters an internal error at any point, it returns // a message.NewErrorResponse(ErrDirectory) tuple. -func (d *ConiksDirectory) KeyLookup(req *KeyLookupRequest) ( - *Response, ErrorCode) { +func (d *ConiksDirectory) KeyLookup(req *p.KeyLookupRequest) ( + *p.Response, p.ErrorCode) { // make sure the request is well-formed if len(req.Username) <= 0 { - return NewErrorResponse(ErrMalformedClientMessage), - ErrMalformedClientMessage + return p.NewErrorResponse(p.ErrMalformedClientMessage), + p.ErrMalformedClientMessage } ap, err := d.pad.Lookup(req.Username) if err != nil { - return NewErrorResponse(ErrDirectory), ErrDirectory + return p.NewErrorResponse(p.ErrDirectory), p.ErrDirectory } if bytes.Equal(ap.LookupIndex, ap.Leaf.Index) { - return NewKeyLookupProof(ap, d.LatestSTR(), nil, ReqSuccess) + return p.NewKeyLookupProof(ap, d.LatestSTR(), nil, p.ReqSuccess) } // if not found in the tree, do lookup in tb array if d.useTBs { if tb := d.tbs[req.Username]; tb != nil { - return NewKeyLookupProof(ap, d.LatestSTR(), tb, ReqSuccess) + return p.NewKeyLookupProof(ap, d.LatestSTR(), tb, p.ReqSuccess) } } - return NewKeyLookupProof(ap, d.LatestSTR(), nil, ReqNameNotFound) + return p.NewKeyLookupProof(ap, d.LatestSTR(), nil, p.ReqNameNotFound) } // KeyLookupInEpoch gets the public key for the username for a prior @@ -242,33 +243,33 @@ func (d *ConiksDirectory) KeyLookup(req *KeyLookupRequest) ( // the binding is included in a directory snapshot. // If KeyLookupInEpoch() encounters an internal error at any point, // it returns a message.NewErrorResponse(ErrDirectory) tuple. -func (d *ConiksDirectory) KeyLookupInEpoch(req *KeyLookupInEpochRequest) ( - *Response, ErrorCode) { +func (d *ConiksDirectory) KeyLookupInEpoch(req *p.KeyLookupInEpochRequest) ( + *p.Response, p.ErrorCode) { // make sure the request is well-formed if len(req.Username) <= 0 || req.Epoch > d.LatestSTR().Epoch { - return NewErrorResponse(ErrMalformedClientMessage), - ErrMalformedClientMessage + return p.NewErrorResponse(p.ErrMalformedClientMessage), + p.ErrMalformedClientMessage } - var strs []*DirSTR + var strs []*p.DirSTR startEp := req.Epoch endEp := d.LatestSTR().Epoch ap, err := d.pad.LookupInEpoch(req.Username, startEp) if err != nil { - return NewErrorResponse(ErrDirectory), ErrDirectory + return p.NewErrorResponse(p.ErrDirectory), p.ErrDirectory } for ep := startEp; ep <= endEp; ep++ { - str := NewDirSTR(d.pad.GetSTR(ep)) + str := p.NewDirSTR(d.pad.GetSTR(ep)) strs = append(strs, str) } if bytes.Equal(ap.LookupIndex, ap.Leaf.Index) { - return NewKeyLookupInEpochProof(ap, strs, ReqSuccess) + return p.NewKeyLookupInEpochProof(ap, strs, p.ReqSuccess) } - return NewKeyLookupInEpochProof(ap, strs, ReqNameNotFound) + return p.NewKeyLookupInEpochProof(ap, strs, p.ReqNameNotFound) } // Monitor gets the directory proofs for the username for the range of @@ -291,18 +292,18 @@ func (d *ConiksDirectory) KeyLookupInEpoch(req *KeyLookupInEpochRequest) ( // the end of the range will be set to d.LatestSTR().Epoch. // If Monitor() encounters an internal error at any point, // it returns a message.NewErrorResponse(ErrDirectory) tuple. -func (d *ConiksDirectory) Monitor(req *MonitoringRequest) ( - *Response, ErrorCode) { +func (d *ConiksDirectory) Monitor(req *p.MonitoringRequest) ( + *p.Response, p.ErrorCode) { // make sure the request is well-formed if len(req.Username) <= 0 || req.StartEpoch > d.LatestSTR().Epoch || req.StartEpoch > req.EndEpoch { - return NewErrorResponse(ErrMalformedClientMessage), - ErrMalformedClientMessage + return p.NewErrorResponse(p.ErrMalformedClientMessage), + p.ErrMalformedClientMessage } - var strs []*DirSTR + var strs []*p.DirSTR var aps []*merkletree.AuthenticationPath startEp := req.StartEpoch endEp := req.EndEpoch @@ -312,14 +313,14 @@ func (d *ConiksDirectory) Monitor(req *MonitoringRequest) ( for ep := startEp; ep <= endEp; ep++ { ap, err := d.pad.LookupInEpoch(req.Username, ep) if err != nil { - return NewErrorResponse(ErrDirectory), ErrDirectory + return p.NewErrorResponse(p.ErrDirectory), p.ErrDirectory } aps = append(aps, ap) - str := NewDirSTR(d.pad.GetSTR(ep)) + str := p.NewDirSTR(d.pad.GetSTR(ep)) strs = append(strs, str) } - return NewMonitoringProof(aps, strs) + return p.NewMonitoringProof(aps, strs) } // GetSTRHistory gets the directory snapshots for the epoch range diff --git a/protocol/directory_test.go b/protocol/directory/directory_test.go similarity index 99% rename from protocol/directory_test.go rename to protocol/directory/directory_test.go index 7730de9..d1f2801 100644 --- a/protocol/directory_test.go +++ b/protocol/directory/directory_test.go @@ -1,8 +1,10 @@ -package protocol +package directory import ( "bytes" "testing" + + . "github.com/coniks-sys/coniks-go/protocol" ) func TestRegisterWithTB(t *testing.T) { diff --git a/protocol/directory/testutil.go b/protocol/directory/testutil.go new file mode 100644 index 0000000..527beb5 --- /dev/null +++ b/protocol/directory/testutil.go @@ -0,0 +1,31 @@ +package directory + +import ( + "testing" + + "github.com/coniks-sys/coniks-go/crypto/sign" + "github.com/coniks-sys/coniks-go/crypto/vrf" +) + +// 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 +} diff --git a/protocol/message.go b/protocol/message.go index 91b5287..5145776 100644 --- a/protocol/message.go +++ b/protocol/message.go @@ -266,7 +266,7 @@ func NewSTRHistoryRange(str []*DirSTR) (*Response, ErrorCode) { }, ReqSuccess } -func (msg *Response) validate() error { +func (msg *Response) Validate() error { if Errors[msg.Error] { return msg.Error } diff --git a/protocol/str_test.go b/protocol/str_test.go index 00aad1d..596b3dd 100644 --- a/protocol/str_test.go +++ b/protocol/str_test.go @@ -1,14 +1,39 @@ package protocol -import "testing" +import ( + "testing" + + "github.com/coniks-sys/coniks-go/crypto/sign" + "github.com/coniks-sys/coniks-go/crypto/vrf" + "github.com/coniks-sys/coniks-go/merkletree" +) func TestVerifyHashChain(t *testing.T) { var N uint64 = 100 - d, pk := NewTestDirectory(t, true) - savedSTR := d.LatestSTR() + + vrfKey, err := vrf.GenerateKey(nil) + if err != nil { + t.Fatal(err) + } + signKey, err := sign.GenerateKey(nil) + if err != nil { + t.Fatal(err) + } + + vrfPublicKey, _ := vrfKey.Public() + pk, _ := signKey.Public() + + policies := NewPolicies(10, vrfPublicKey) + pad, err := merkletree.NewPAD(policies, signKey, vrfKey, 1) + if err != nil { + panic(err) + } + + savedSTR := pad.LatestSTR() + for i := uint64(1); i < N; i++ { - d.Update() - str := d.LatestSTR() + pad.Update(nil) + str := pad.LatestSTR() if i != str.Epoch { t.Fatal("Epochs aren't increasing.") } diff --git a/protocol/testutil.go b/protocol/testutil.go deleted file mode 100644 index 02c493c..0000000 --- a/protocol/testutil.go +++ /dev/null @@ -1,57 +0,0 @@ -package protocol - -import ( - "testing" - - "github.com/coniks-sys/coniks-go/crypto/sign" - "github.com/coniks-sys/coniks-go/crypto/vrf" -) - -// 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 := NewDirectory(1, vrfKey, signKey, 10, useTBs) - return d, pk -} - -// NewTestAuditLog creates a ConiksAuditLog and corresponding -// ConiksDirectory used for testing auditor-side CONIKS operations. -// The new audit log can be initialized with the number of epochs -// indicating the length of the directory history with which to -// initialize the log; if numEpochs > 0, the history contains numEpochs+1 -// STRs as it always includes the STR after the last directory update -func NewTestAuditLog(t *testing.T, numEpochs int) (*ConiksDirectory, ConiksAuditLog, []*DirSTR) { - d, pk := NewTestDirectory(t, true) - aud := NewAuditLog() - - var hist []*DirSTR - for ep := 0; ep < numEpochs; ep++ { - hist = append(hist, d.LatestSTR()) - d.Update() - } - // always include the actual latest STR - hist = append(hist, d.LatestSTR()) - - err := aud.InitHistory("test-server", pk, hist) - if err != nil { - t.Fatalf("Error initializing a new history with %d STRs", numEpochs+1) - } - - return d, aud, hist -}