From 5a923dbf27f70ccea31f1dc96a8f6faaeca14140 Mon Sep 17 00:00:00 2001 From: Marcela Melara Date: Wed, 14 Dec 2016 15:43:32 -0500 Subject: [PATCH 01/26] Add client-auditor messages --- protocol/message.go | 122 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 2 deletions(-) diff --git a/protocol/message.go b/protocol/message.go index c666568..8e557c6 100644 --- a/protocol/message.go +++ b/protocol/message.go @@ -90,6 +90,60 @@ type MonitoringRequest struct { EndEpoch uint64 } +// An AuditingRequest is a message with a CONIKS key directory's address +// as a string that a CONIKS client sends to a CONIKS auditor to request +// the latest STR the auditor has observed for the given directory. +// If the client needs to request a directory's STR for a prior epoch, it +// must send an AuditingInEpochRequest. +// +// The response to a successful request is an ObservedDirectoryProof. +type AuditingRequest struct { + DirectoryAddr string `json:"directory_addr"` +} + +// An AuditingInEpochRequest is a message with a key directory's address +// as a string and an epoch as a uint64 that a CONIKS client sends to +// a CONIKS auditor to retrieve the STR it observed for the directory in +// the given epoch. The client sends this request type when it needs to +// audit a directory's STR for a prior epoch (i.e. as part of a +// key lookup in epoch check or a monitoring check). The client can send an +// AuditingRequest if it needs to audit a directory's STR for its latest +// epoch. +// +// The response to a successful request is an ObservedDirectoryProofs with +// a list of STRs covering the epoch range [Epoch, d.LatestSTR().Epoch]. +type AuditingInEpochRequest struct { + DirectoryAddr string `json:"directory_addr"` + Epoch uint64 `json:"epoch"` +} + +// An AuditingRequest is a message with a CONIKS key directory's address +// as a string that a CONIKS client sends to a CONIKS auditor to request +// the latest STR the auditor has observed for the given directory. +// If the client needs to request a directory's STR for a prior epoch, it +// must send an AuditingInEpochRequest. +// +// The response to a successful request is an ObservedDirectoryProof. +type AuditingRequest struct { + DirectoryAddr string `json:"directory_addr"` +} + +// An AuditingInEpochRequest is a message with a key directory's address +// as a string and an epoch as a uint64 that a CONIKS client sends to +// a CONIKS auditor to retrieve the STR it observed for the directory in +// the given epoch. The client sends this request type when it needs to +// audit a directory's STR for a prior epoch (i.e. as part of a +// key lookup in epoch check or a monitoring check). The client can send an +// AuditingRequest if it needs to audit a directory's STR for its latest +// epoch. +// +// The response to a successful request is an ObservedDirectoryProofs with +// a list of STRs covering the epoch range [Epoch, d.LatestSTR().Epoch]. +type AuditingInEpochRequest struct { + DirectoryAddr string `json:"directory_addr"` + Epoch uint64 `json:"epoch"` +} + // A Response message indicates the result of a CONIKS client request // with an appropriate error code, and defines the set of cryptographic // proofs a CONIKS directory must return as part of its response. @@ -99,7 +153,7 @@ type Response struct { } // A DirectoryResponse is a message that includes cryptographic proofs -// about the key directory that a CONIKS key directory returns +// about the key directory that a CONIKS key directory or auditor returns // to a CONIKS client. type DirectoryResponse interface{} @@ -124,8 +178,36 @@ type DirectoryProofs struct { STR []*DirSTR } +// An ObservedSTR response includes a single signed tree root +// STR. A CONIKS auditor returns this DirectoryResponse type upon an +// AuditingRequest. +type ObservedSTR struct { + STR *m.SignedTreeRoot +} + +// An ObservedSTRs response includes a list of signed tree roots +// STR. A CONIKS auditor returns this DirectoryResponse type upon an +// AudutingRequest. +type ObservedSTRs struct { + STR []*m.SignedTreeRoot +} + +// An ObservedSTR response includes a single signed tree root +// STR. A CONIKS auditor returns this DirectoryResponse type upon an +// AuditingRequest. +type ObservedSTR struct { + STR *m.SignedTreeRoot +} + +// An ObservedSTRs response includes a list of signed tree roots +// STR. A CONIKS auditor returns this DirectoryResponse type upon an +// AudutingRequest. +type ObservedSTRs struct { + STR []*m.SignedTreeRoot +} + // NewErrorResponse creates a new response message indicating the error -// that occurred while a CONIKS directory was +// that occurred while a CONIKS directory or a CONIKS auditor was // processing a client request. func NewErrorResponse(e ErrorCode) *Response { return &Response{Error: e} @@ -133,6 +215,8 @@ func NewErrorResponse(e ErrorCode) *Response { var _ DirectoryResponse = (*DirectoryProof)(nil) var _ DirectoryResponse = (*DirectoryProofs)(nil) +var _ DirectoryResponse = (*ObservedSTR)(nil) +var _ DirectoryResponse = (*ObservedSTRs)(nil) // NewRegistrationProof creates the response message a CONIKS directory // sends to a client upon a RegistrationRequest, @@ -216,6 +300,40 @@ func NewMonitoringProof(ap []*m.AuthenticationPath, }, ReqSuccess } +// NewObservedSTR creates the response message a CONIKS auditor +// sends to a client upon an AuditingRequest, +// and returns a Response containing an ObservedSTR struct. +// auditlog.Audit() passes the signed tree root for the auditor's latest +// observed epoch str. +// +// See auditlog.Audit() for details on the contents of the created +// ObservedSTR. +func NewObservedSTR(str *m.SignedTreeRoot) (*Response, ErrorCode) { + return &Response{ + Error: ReqSuccess, + DirectoryResponse: &ObservedSTR{ + STR: str, + }, + }, ReqSuccess +} + +// NewObservedSTRs creates the response message a CONIKS auditor +// sends to a client upon an AuditingInEpochRequest, +// and returns a Response containing an ObservedSTRs struct. +// auditlog.AuditInEpoch() passes a list of signed tree roots +// that the auditor observed for the requested range of epochs str. +// +// See auditlog.AuditInEpoch() for details on the contents of the created +// ObservedSTRs. +func NewObservedSTRs(str []*m.SignedTreeRoot) (*Response, ErrorCode) { + return &Response{ + Error: ReqSuccess, + DirectoryResponse: &ObservedSTRs{ + STR: str, + }, + }, ReqSuccess +} + func (msg *Response) validate() error { if Errors[msg.Error] { return msg.Error From d9ed76dc517b2617277c5ae9c31295f756a87ced Mon Sep 17 00:00:00 2001 From: Marcela Date: Wed, 21 Dec 2016 17:07:50 -0500 Subject: [PATCH 02/26] Create audit log structure, query API finished --- protocol/auditlog.go | 183 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 protocol/auditlog.go diff --git a/protocol/auditlog.go b/protocol/auditlog.go new file mode 100644 index 0000000..9521cb3 --- /dev/null +++ b/protocol/auditlog.go @@ -0,0 +1,183 @@ +// This module implements a CONIKS audit log that a CONIKS auditor +// maintains. +// An audit log is a mirror of many CONIKS key directories' STR history, +// allowing CONIKS clients to audit the CONIKS directories. + +package protocol + +import ( + "github.com/coniks-sys/coniks-go/crypto/sign" + m "github.com/coniks-sys/coniks-go/merkletree" +) + +type directoryHistory struct { + signKey sign.PublicKey + snapshots map[uint64]*m.SignedTreeRoot + latestSTR *m.SignedTreeRoot +} + +// A ConiksAuditLog maintains the histories +// of all CONIKS directories known to a CONIKS auditor. +// Each history includes the directory's public signing key +// enabling the auditor to verify the corresponding signed +// tree roots. +type ConiksAuditLog struct { + histories map[string]*directoryHistory +} + +func newDirectoryHistory(signKey sign.PublicKey, str *m.SignedTreeRoot) *directoryHistory { + h := new(directoryHistory) + h.signKey = signKey + h.snapshots = make(map[uint64]*m.SignedTreeRoot) + h.latestSTR = str + return h +} + +// NewAuditLog 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 { + l := new(ConiksAuditLog) + l.histories = make(map[string]*directoryHistory) + return l +} + +// IsKnownDirectory checks to see if an entry for the directory +// address addr exists in the audit log l. IsKnownDirectory() does not +// validate the entries themselves. It returns true if an entry exists, +// and false otherwise. +func (l *ConiksAuditLog) IsKnownDirectory(addr string) bool { + h := l.histories[addr] + if h != nil { + return true + } + return false +} + +// FIXME: pass Request message as param +// masomel: will probably want to write a more generic function +// for "catching up" on a history in case an auditor misses epochs +func (l *ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, + oldSTRs map[uint64]*m.SignedTreeRoot, latestSTR *m.SignedTreeRoot) error { + + // panic if we want to create a new entry for an addr we already know + if l.IsKnownDirectory(addr) { + panic("[protocol] Trying to add an audit log entry for an existing address") + } + + // create the new directory history + h := newDirectoryHistory(signKey, latestSTR) + + startEp := uint64(0) + endEp := latestSTR.Epoch + + // add each old STR into the history + for ep := startEp; ep < endEp; ep++ { + if str := oldSTRs[ep]; str != nil { + h.snapshots[ep] = str + } + return ErrMalformedDirectoryMessage + } + + // FIXME: verify the consistency of each new STR + return nil +} + +// Update verifies the consistency of a newly observed STR newSTR for +// the directory addr, and inserts the newSTR into addr's directory history +// if the checks (i.e. STR signature and hash chain verifications) pass. +// Update() returns nil if the checks pass, and the appropriate consistency +// check error otherwise. Update() assumes that Insert() has been called for +// addr prior to its first call and thereby expects that an entry for addr +// exists in the audit log l. +// FIXME: pass Request message as param +func (l *ConiksAuditLog) Update(addr string, newSTR *m.SignedTreeRoot) error { + + // panic if we want to update an entry for which we don't have + if !l.IsKnownDirectory(addr) { + panic("[protocol] Trying to update audit log entry for non-existent address") + } + + h := l.histories[addr] + + if err := h.verifySTRConsistency(newSTR); err != nil { + return err + } + + // update the latest STR + h.snapshots[h.latestSTR.Epoch] = h.latestSTR + h.latestSTR = newSTR + return nil +} + +// verifySTRConsistency checks the consistency between 2 snapshots. +// It uses the pinned signing key in the directory history +// to verify the STR's signature and verifies +// the hash chain using the latestSTR stored in the history. +// TODO: dedup this: write generic verifySTRConsistency +func (h *directoryHistory) verifySTRConsistency(str *m.SignedTreeRoot) error { + // verify STR's signature + if !h.signKey.Verify(str.Serialize(), str.Signature) { + return CheckBadSignature + } + if str.VerifyHashChain(h.latestSTR) { + return nil + } + + // TODO: verify the directory's policies as well. See #115 + return CheckBadSTR +} + +// TODO add doc +func (l *ConiksAuditLog) Query(req *AuditingRequest) (*Response, ErrorCode) { + + // make sure the request is well-formed + if len(req.DirectoryAddr) <= 0 { + return NewErrorResponse(ErrMalformedClientMessage), + ErrMalformedClientMessage + } + + if h := l.histories[req.DirectoryAddr]; h != nil { + return NewObservedSTR(h.latestSTR) + } + + // FIXME: return ErrUnknownDirectory + return nil, ErrDirectory +} + +// TODO: add doc +func (l *ConiksAuditLog) QueryInEpoch(req *AuditingInEpochRequest) (*Response, + ErrorCode) { + + // make sure the request is well-formed + if len(req.DirectoryAddr) <= 0 { + return NewErrorResponse(ErrMalformedClientMessage), + ErrMalformedClientMessage + } + + if h := l.histories[req.DirectoryAddr]; h != nil { + + // also make sure the epoch is well-formed + if req.Epoch > h.latestSTR.Epoch { + return NewErrorResponse(ErrMalformedClientMessage), + ErrMalformedClientMessage + } + + var strs []*m.SignedTreeRoot + startEp := req.Epoch + endEp := h.latestSTR.Epoch + + for ep := startEp; ep < endEp; ep++ { + str := h.snapshots[ep] + strs = append(strs, str) + } + + // don't forget to append the latest STR + strs = append(strs, h.latestSTR) + + return NewObservedSTRs(strs) + } + + // FIXME: return ErrUnknownDirectory + return nil, ErrDirectory +} From 146e91a1e1b94309e63ec98ecb348a387bbbae6c Mon Sep 17 00:00:00 2001 From: Marcela Melara Date: Thu, 16 Feb 2017 15:06:23 -0500 Subject: [PATCH 03/26] Add/Update docs to include auditor, add ReqUnknownDirectory auditor error --- protocol/auditlog.go | 47 ++++++++++++++++++++++++++++++++++++-------- protocol/error.go | 5 ++++- protocol/message.go | 29 ++++++++++++++------------- 3 files changed, 58 insertions(+), 23 deletions(-) diff --git a/protocol/auditlog.go b/protocol/auditlog.go index 9521cb3..3f50141 100644 --- a/protocol/auditlog.go +++ b/protocol/auditlog.go @@ -128,8 +128,23 @@ func (h *directoryHistory) verifySTRConsistency(str *m.SignedTreeRoot) error { return CheckBadSTR } -// TODO add doc -func (l *ConiksAuditLog) Query(req *AuditingRequest) (*Response, ErrorCode) { +// GetObservedSTR gets the observed STR for the CONIKS directory address indicated +// in the AuditingRequest req received from a CONIKS client from the auditor's latest +// directory history entry, and returns a tuple of the form +// (response, error). +// The response (which also includes the error code) is supposed to +// be sent back to the client. The returned error is used by the auditor +// for logging purposes. +// +// A request without a directory address is considered +// malformed, and causes GetObservedSTR() to return a +// message.NewErrorResponse(ErrMalformedClientMessage) tuple. +// GetObservedSTR() returns a message.NewObservedSTR(str) tuple. +// str is the signed tree root the auditor has observed for the latest epoch. +// If the auditor doesn't have any history entries for the requested CONIKS +// directory, GetObservedSTR() returns a +// message.NewErrorResponse(ReqUnknownDirectory) tuple. +func (l *ConiksAuditLog) GetObservedSTR(req *AuditingRequest) (*Response, ErrorCode) { // make sure the request is well-formed if len(req.DirectoryAddr) <= 0 { @@ -141,12 +156,29 @@ func (l *ConiksAuditLog) Query(req *AuditingRequest) (*Response, ErrorCode) { return NewObservedSTR(h.latestSTR) } - // FIXME: return ErrUnknownDirectory - return nil, ErrDirectory + return NewErrorResponse(ReqUnknownDirectory), ReqUnknownDirectory } -// TODO: add doc -func (l *ConiksAuditLog) QueryInEpoch(req *AuditingInEpochRequest) (*Response, +// GetObservedSTRInEpoch gets the observed STR for the CONIKS directory address +// for a prior directory history entry indicated in the +// AuditingInEpochRequest req received from a CONIKS client, +// and returns a tuple of the form (response, error). +// The response (which also includes the error code) is supposed to +// be sent back to the client. The returned error is used by the auditor +// for logging purposes. +// +// A request without a directory address or with an epoch greater than the latest +// observed epoch of this directory is considered malformed, and causes +// GetObservedSTRInEpoch() to return a +// message.NewErrorResponse(ErrMalformedClientMessage) tuple. +// GetObservedSTRInEpoch() returns a message.NewObservedSTRs(strs) tuple. +// strs is a list of STRs for the epoch range [ep, +// l.histories[req.DirectoryAddr].latestSTR.Epoch], where ep is the past epoch +// for which the client has requested the observed STR. +// If the auditor doesn't have any history entries for the requested CONIKS +// directory, GetObservedSTR() returns a +// message.NewErrorResponse(ReqUnknownDirectory) tuple. +func (l *ConiksAuditLog) GetObservedSTRInEpoch(req *AuditingInEpochRequest) (*Response, ErrorCode) { // make sure the request is well-formed @@ -178,6 +210,5 @@ func (l *ConiksAuditLog) QueryInEpoch(req *AuditingInEpochRequest) (*Response, return NewObservedSTRs(strs) } - // FIXME: return ErrUnknownDirectory - return nil, ErrDirectory + return NewErrorResponse(ReqUnknownDirectory), ReqUnknownDirectory } diff --git a/protocol/error.go b/protocol/error.go index 866d508..86c2bf4 100644 --- a/protocol/error.go +++ b/protocol/error.go @@ -8,7 +8,8 @@ package protocol // An ErrorCode implements the built-in error interface type. type ErrorCode int -// These codes indicate the status of a client-server message exchange. +// These codes indicate the status of a client-server or client-auditor message +// exchange. // Codes prefixed by "Req" indicate different client request results. // Codes prefixed by "Err" indicate an internal server error or a malformed // message. @@ -16,6 +17,8 @@ const ( ReqSuccess ErrorCode = iota + 100 ReqNameExisted ReqNameNotFound + // auditor->client: no observed history for the requested directory + ReqUnknownDirectory ErrDirectory ErrMalformedClientMessage diff --git a/protocol/message.go b/protocol/message.go index 8e557c6..f0f560e 100644 --- a/protocol/message.go +++ b/protocol/message.go @@ -118,26 +118,27 @@ type AuditingInEpochRequest struct { } // An AuditingRequest is a message with a CONIKS key directory's address -// as a string that a CONIKS client sends to a CONIKS auditor to request -// the latest STR the auditor has observed for the given directory. -// If the client needs to request a directory's STR for a prior epoch, it +// as a string that a CONIKS client sends to a CONIKS auditor, or a CONIKS auditor +// sends to a CONIKS directory, to request the given directory's latest STR. +// If the client/auditor needs to request a directory's STR for a prior epoch, it // must send an AuditingInEpochRequest. // -// The response to a successful request is an ObservedDirectoryProof. +// The response to a successful request is an ObservedSTR. type AuditingRequest struct { DirectoryAddr string `json:"directory_addr"` } // An AuditingInEpochRequest is a message with a key directory's address // as a string and an epoch as a uint64 that a CONIKS client sends to -// a CONIKS auditor to retrieve the STR it observed for the directory in -// the given epoch. The client sends this request type when it needs to +// a CONIKS auditor, or a CONIKS auditor sends to a CONIKS directory, +// to retrieve the STR for the directory in +// the given epoch. The client/auditor sends this request type when it needs to // audit a directory's STR for a prior epoch (i.e. as part of a -// key lookup in epoch check or a monitoring check). The client can send an -// AuditingRequest if it needs to audit a directory's STR for its latest -// epoch. +// key lookup in epoch check, a monitoring check, or an auditor update). +// The client/auditor can send an AuditingRequest if it needs to audit a +// directory's STR for its latest epoch. // -// The response to a successful request is an ObservedDirectoryProofs with +// The response to a successful request is an ObservedSTRs with // a list of STRs covering the epoch range [Epoch, d.LatestSTR().Epoch]. type AuditingInEpochRequest struct { DirectoryAddr string `json:"directory_addr"` @@ -301,10 +302,10 @@ func NewMonitoringProof(ap []*m.AuthenticationPath, } // NewObservedSTR creates the response message a CONIKS auditor -// sends to a client upon an AuditingRequest, -// and returns a Response containing an ObservedSTR struct. -// auditlog.Audit() passes the signed tree root for the auditor's latest -// observed epoch str. +// sends to a client, or a CONIKS directory sends to an auditor, +// upon an AuditingRequest, and returns a Response containing an ObservedSTR struct. +// auditlog.GetObservedSTR(), or directory.GetLatestSTR(), passes the signed +// tree root for the directory's latest str. // // See auditlog.Audit() for details on the contents of the created // ObservedSTR. From 90e2517a580b48a920be49f21c291e5b0d602bd4 Mon Sep 17 00:00:00 2001 From: Marcela Melara Date: Thu, 16 Feb 2017 15:20:16 -0500 Subject: [PATCH 04/26] Use single generic verifySTRConsistency to be used by client and auditor --- protocol/auditlog.go | 20 +------------------- protocol/consistencychecks.go | 15 +++++++++------ 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/protocol/auditlog.go b/protocol/auditlog.go index 3f50141..373a7f4 100644 --- a/protocol/auditlog.go +++ b/protocol/auditlog.go @@ -100,7 +100,7 @@ func (l *ConiksAuditLog) Update(addr string, newSTR *m.SignedTreeRoot) error { h := l.histories[addr] - if err := h.verifySTRConsistency(newSTR); err != nil { + if err := verifySTRConsistency(h.signKey, h.latestSTR, newSTR); err != nil { return err } @@ -110,24 +110,6 @@ func (l *ConiksAuditLog) Update(addr string, newSTR *m.SignedTreeRoot) error { return nil } -// verifySTRConsistency checks the consistency between 2 snapshots. -// It uses the pinned signing key in the directory history -// to verify the STR's signature and verifies -// the hash chain using the latestSTR stored in the history. -// TODO: dedup this: write generic verifySTRConsistency -func (h *directoryHistory) verifySTRConsistency(str *m.SignedTreeRoot) error { - // verify STR's signature - if !h.signKey.Verify(str.Serialize(), str.Signature) { - return CheckBadSignature - } - if str.VerifyHashChain(h.latestSTR) { - return nil - } - - // TODO: verify the directory's policies as well. See #115 - return CheckBadSTR -} - // GetObservedSTR gets the observed STR for the CONIKS directory address indicated // in the AuditingRequest req received from a CONIKS client from the auditor's latest // directory history entry, and returns a tuple of the form diff --git a/protocol/consistencychecks.go b/protocol/consistencychecks.go index 856b706..dd8c98b 100644 --- a/protocol/consistencychecks.go +++ b/protocol/consistencychecks.go @@ -117,7 +117,7 @@ func (cc *ConsistencyChecks) updateSTR(requestType int, msg *Response) error { return nil } // Otherwise, expect that we've entered a new epoch - if err := cc.verifySTRConsistency(cc.SavedSTR, str); err != nil { + if err := verifySTRConsistency(cc.signKey, cc.SavedSTR, str); err != nil { return err } @@ -140,12 +140,15 @@ func (cc *ConsistencyChecks) verifySTR(str *DirSTR) error { } // verifySTRConsistency checks the consistency between 2 snapshots. -// It uses the pinned signing key in cc -// to verify the STR's signature and should not verify -// the hash chain using the STR stored in cc. -func (cc *ConsistencyChecks) verifySTRConsistency(savedSTR, str *DirSTR) error { +// It uses the signing key signKey to verify the STR's signature. +// The signKey param either comes from a client's +// pinned signing key in cc, or an auditor's pinned signing key +// in its history. +// In the case of a client-side consistency check, verifySTRConsistency() +// should not verify the hash chain using the STR stored in cc. +func verifySTRConsistency(signKey sign.PublicKey, savedSTR, str *m.SignedTreeRoot) error { // verify STR's signature - if !cc.signKey.Verify(str.Serialize(), str.Signature) { + if !signKey.Verify(str.Serialize(), str.Signature) { return CheckBadSignature } if str.VerifyHashChain(savedSTR) { From e8178c17bd7f866b98fe2ecdbf075a51e228d02b Mon Sep 17 00:00:00 2001 From: Marcela M Date: Tue, 7 Mar 2017 19:10:08 -0500 Subject: [PATCH 05/26] Add tests for audit log, debug audit log --- protocol/auditlog.go | 21 ++-- protocol/auditlog_test.go | 220 ++++++++++++++++++++++++++++++++++++++ protocol/error.go | 5 +- 3 files changed, 236 insertions(+), 10 deletions(-) create mode 100644 protocol/auditlog_test.go diff --git a/protocol/auditlog.go b/protocol/auditlog.go index 373a7f4..116d8e7 100644 --- a/protocol/auditlog.go +++ b/protocol/auditlog.go @@ -44,7 +44,7 @@ func NewAuditLog() *ConiksAuditLog { // IsKnownDirectory checks to see if an entry for the directory // address addr exists in the audit log l. IsKnownDirectory() does not -// validate the entries themselves. It returns true if an entry exists, +// validate the entries themselves. It returns true if an entry exists, // and false otherwise. func (l *ConiksAuditLog) IsKnownDirectory(addr string) bool { h := l.histories[addr] @@ -54,15 +54,15 @@ func (l *ConiksAuditLog) IsKnownDirectory(addr string) bool { return false } -// FIXME: pass Request message as param +// FIXME: pass Response message as param // masomel: will probably want to write a more generic function // for "catching up" on a history in case an auditor misses epochs func (l *ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, oldSTRs map[uint64]*m.SignedTreeRoot, latestSTR *m.SignedTreeRoot) error { - // panic if we want to create a new entry for an addr we already know + // error if we want to create a new entry for an addr we already know if l.IsKnownDirectory(addr) { - panic("[protocol] Trying to add an audit log entry for an existing address") + return ErrAuditLog } // create the new directory history @@ -73,12 +73,15 @@ func (l *ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, // add each old STR into the history for ep := startEp; ep < endEp; ep++ { - if str := oldSTRs[ep]; str != nil { - h.snapshots[ep] = str + str := oldSTRs[ep] + if str == nil { + return ErrMalformedDirectoryMessage } - return ErrMalformedDirectoryMessage + h.snapshots[ep] = str } + l.histories[addr] = h + // FIXME: verify the consistency of each new STR return nil } @@ -90,12 +93,12 @@ func (l *ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, // check error otherwise. Update() assumes that Insert() has been called for // addr prior to its first call and thereby expects that an entry for addr // exists in the audit log l. -// FIXME: pass Request message as param +// FIXME: pass Response message as param func (l *ConiksAuditLog) Update(addr string, newSTR *m.SignedTreeRoot) error { // panic if we want to update an entry for which we don't have if !l.IsKnownDirectory(addr) { - panic("[protocol] Trying to update audit log entry for non-existent address") + return ErrAuditLog } h := l.histories[addr] diff --git a/protocol/auditlog_test.go b/protocol/auditlog_test.go new file mode 100644 index 0000000..de489ef --- /dev/null +++ b/protocol/auditlog_test.go @@ -0,0 +1,220 @@ +package protocol + +import ( + m "github.com/coniks-sys/coniks-go/merkletree" + "testing" +) + +func TestInsertEmptyHistory(t *testing.T) { + // let's just create basic test directory and an empty audit log + d, pk := NewTestDirectory(t, true) + aud := NewAuditLog() + + err := aud.Insert("test-server", pk, nil, d.LatestSTR()) + if err != nil { + t.Fatal("Error inserting new server history") + } +} + +func TestUpdateHistory(t *testing.T) { + // let's just create basic test directory and an empty audit log + d, pk := NewTestDirectory(t, true) + aud := NewAuditLog() + + err := aud.Insert("test-server", pk, nil, d.LatestSTR()) + if err != nil { + t.Fatal("Error inserting new server history") + } + + // update the directory so we can update the audit log + d.Update() + err = aud.Update("test-server", d.LatestSTR()) + + if err != nil { + t.Fatal("Error updating the server history") + } +} + +func TestInsertPriorHistory(t *testing.T) { + // let's just create basic test directory and an empty audit log + d, pk := NewTestDirectory(t, true) + aud := NewAuditLog() + + // create 10 epochs + priorSTRs := make(map[uint64]*m.SignedTreeRoot) + for i := 0; i < 10; i++ { + priorSTRs[d.LatestSTR().Epoch] = d.LatestSTR() + d.Update() + } + + // now insert + err := aud.Insert("test-server", pk, priorSTRs, d.LatestSTR()) + if err != nil { + t.Fatal("Error inserting new server history with prior STRs") + } +} + +func TestInsertExistingHistory(t *testing.T) { + // let's just create basic test directory and an empty audit log + d, pk := NewTestDirectory(t, true) + aud := NewAuditLog() + err := aud.Insert("test-server", pk, nil, d.LatestSTR()) + if err != nil { + t.Fatal("Error inserting new server history") + } + + // let's make sure that we can't re-insert a new server history into our log + err = aud.Insert("test-server", pk, nil, d.LatestSTR()) + if err != ErrAuditLog { + t.Fatal("Expected an ErrAuditLog when inserting an existing server history") + } +} + +func TestUpdateUnknownHistory(t *testing.T) { + // let's just create basic test directory and an empty audit log + d, pk := NewTestDirectory(t, true) + aud := NewAuditLog() + err := aud.Insert("test-server", pk, nil, d.LatestSTR()) + if err != nil { + t.Fatal("Error inserting new server history") + } + + // let's make sure that we can't re-insert a new server history into our log + err = aud.Update("unknown", d.LatestSTR()) + if err != ErrAuditLog { + t.Fatal("Expected an ErrAuditLog when updating an unknown server history") + } +} + +func TestGetObservedSTR(t *testing.T) { + // let's just create basic test directory and an empty audit log + d, pk := NewTestDirectory(t, true) + aud := NewAuditLog() + err := aud.Insert("test-server", pk, nil, d.LatestSTR()) + if err != nil { + t.Fatal("Error inserting new server history") + } + + res, err := aud.GetObservedSTR(&AuditingRequest{ + DirectoryAddr: "test-server"}) + obs := res.DirectoryResponse.(*ObservedSTR) + if err != ReqSuccess { + t.Fatal("Unable to get latest observed STR") + } + if obs.STR == nil { + t.Fatal("Expect returned STR to be not nil") + } + if obs.STR.Epoch != d.LatestSTR().Epoch { + t.Fatal("Unexpected epoch for returned STR") + } +} + +func TestGetObservedSTRInEpoch(t *testing.T) { + // let's just create basic test directory and an empty audit log + d, pk := NewTestDirectory(t, true) + aud := NewAuditLog() + + // create 10 epochs + priorSTRs := make(map[uint64]*m.SignedTreeRoot) + for i := 0; i < 10; i++ { + priorSTRs[d.LatestSTR().Epoch] = d.LatestSTR() + d.Update() + } + + // now insert into the log + err := aud.Insert("test-server", pk, priorSTRs, d.LatestSTR()) + if err != nil { + t.Fatal("Error inserting new server history with prior STRs") + } + + res, err := aud.GetObservedSTRInEpoch(&AuditingInEpochRequest{ + DirectoryAddr: "test-server", + Epoch: uint64(6)}) + obs := res.DirectoryResponse.(*ObservedSTRs) + if err != ReqSuccess { + t.Fatal("Unable to get latest range of STRs") + } + if obs.STR == nil { + t.Fatal("Expect returned STR to be not nil") + } + if len(obs.STR) != 5 { + t.Fatal("Expect 5 returned STRs") + } + if obs.STR[0].Epoch != 6 || obs.STR[4].Epoch != d.LatestSTR().Epoch { + t.Fatal("Unexpected epoch for returned STRs") + } +} + +func TestGetObservedSTRUnknown(t *testing.T) { + // let's just create basic test directory and an empty audit log + d, pk := NewTestDirectory(t, true) + aud := NewAuditLog() + + // create 10 epochs + priorSTRs := make(map[uint64]*m.SignedTreeRoot) + for i := 0; i < 10; i++ { + priorSTRs[d.LatestSTR().Epoch] = d.LatestSTR() + d.Update() + } + + // now insert into the log + err := aud.Insert("test-server", pk, priorSTRs, d.LatestSTR()) + if err != nil { + t.Fatal("Error inserting new server history with prior STRs") + } + + _, err = aud.GetObservedSTR(&AuditingRequest{ + DirectoryAddr: "unknown"}) + if err != ReqUnknownDirectory { + t.Fatal("Expect ReqUnknownDirectory for latest STR") + } + + _, err = aud.GetObservedSTRInEpoch(&AuditingInEpochRequest{ + DirectoryAddr: "unknown", + Epoch: uint64(6)}) + if err != ReqUnknownDirectory { + t.Fatal("Expect ReqUnknownDirectory for older STR") + } + +} + +func TestGetObservedSTRMalformed(t *testing.T) { + // let's just create basic test directory and an empty audit log + d, pk := NewTestDirectory(t, true) + aud := NewAuditLog() + + // create 10 epochs + priorSTRs := make(map[uint64]*m.SignedTreeRoot) + for i := 0; i < 10; i++ { + priorSTRs[d.LatestSTR().Epoch] = d.LatestSTR() + d.Update() + } + + // now insert into the log + err := aud.Insert("test-server", pk, priorSTRs, d.LatestSTR()) + if err != nil { + t.Fatal("Error inserting new server history with prior STRs") + } + + _, err = aud.GetObservedSTR(&AuditingRequest{ + DirectoryAddr: ""}) + if err != ErrMalformedClientMessage { + t.Fatal("Expect ErrMalFormedClientMessage for latest STR") + } + + _, err = aud.GetObservedSTRInEpoch(&AuditingInEpochRequest{ + DirectoryAddr: "", + Epoch: uint64(6)}) + if err != ErrMalformedClientMessage { + t.Fatal("Expect ErrMalformedClientMessage for older STR") + } + + // also test the epoch range + _, err = aud.GetObservedSTRInEpoch(&AuditingInEpochRequest{ + DirectoryAddr: "", + Epoch: uint64(20)}) + if err != ErrMalformedClientMessage { + t.Fatal("Expect ErrMalformedClientMessage for older STR") + } + +} diff --git a/protocol/error.go b/protocol/error.go index 86c2bf4..97016b9 100644 --- a/protocol/error.go +++ b/protocol/error.go @@ -11,7 +11,7 @@ type ErrorCode int // These codes indicate the status of a client-server or client-auditor message // exchange. // Codes prefixed by "Req" indicate different client request results. -// Codes prefixed by "Err" indicate an internal server error or a malformed +// Codes prefixed by "Err" indicate an internal server/auditor error or a malformed // message. const ( ReqSuccess ErrorCode = iota + 100 @@ -21,6 +21,7 @@ const ( ReqUnknownDirectory ErrDirectory + ErrAuditLog ErrMalformedClientMessage ErrMalformedDirectoryMessage ) @@ -49,6 +50,7 @@ const ( var Errors = map[ErrorCode]bool{ ErrMalformedClientMessage: true, ErrDirectory: true, + ErrAuditLog: true, ErrMalformedDirectoryMessage: true, } @@ -60,6 +62,7 @@ var ( ErrMalformedClientMessage: "[coniks] Malformed client message", ErrDirectory: "[coniks] Directory error", + ErrAuditLog: "[coniks] Audit log error", ErrMalformedDirectoryMessage: "[coniks] Malformed directory message", CheckPassed: "[coniks] Consistency checks passed", From badbafcc60b6609eb6b604440c283b3a6eb80d38 Mon Sep 17 00:00:00 2001 From: Marcela M Date: Tue, 7 Mar 2017 19:19:54 -0500 Subject: [PATCH 06/26] Add assertions to validate auditor messages on client --- protocol/auditlog_test.go | 2 +- protocol/error.go | 3 +++ protocol/message.go | 10 ++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/protocol/auditlog_test.go b/protocol/auditlog_test.go index de489ef..ca45ca7 100644 --- a/protocol/auditlog_test.go +++ b/protocol/auditlog_test.go @@ -134,7 +134,7 @@ func TestGetObservedSTRInEpoch(t *testing.T) { if err != ReqSuccess { t.Fatal("Unable to get latest range of STRs") } - if obs.STR == nil { + if obs.STR == nil || len(obs.STR) < 1 { t.Fatal("Expect returned STR to be not nil") } if len(obs.STR) != 5 { diff --git a/protocol/error.go b/protocol/error.go index 97016b9..4e55a25 100644 --- a/protocol/error.go +++ b/protocol/error.go @@ -24,6 +24,7 @@ const ( ErrAuditLog ErrMalformedClientMessage ErrMalformedDirectoryMessage + ErrMalformedAuditorMessage ) // These codes indicate the result @@ -52,6 +53,7 @@ var Errors = map[ErrorCode]bool{ ErrDirectory: true, ErrAuditLog: true, ErrMalformedDirectoryMessage: true, + ErrMalformedAuditorMessage: true, } var ( @@ -64,6 +66,7 @@ var ( ErrDirectory: "[coniks] Directory error", ErrAuditLog: "[coniks] Audit log error", ErrMalformedDirectoryMessage: "[coniks] Malformed directory message", + ErrMalformedAuditorMessage: "[coniks] Malformed auditor message", CheckPassed: "[coniks] Consistency checks passed", CheckBadSignature: "[coniks] Directory's signature on STR or TB is invalid", diff --git a/protocol/message.go b/protocol/message.go index f0f560e..744fa7b 100644 --- a/protocol/message.go +++ b/protocol/message.go @@ -348,6 +348,16 @@ func (msg *Response) validate() error { case *DirectoryProofs: // TODO: also do above assertions here return nil + case *ObservedSTR: + if df.STR == nil { + return ErrMalformedAuditorMessage + } + return nil + case *ObservedSTRs: + if df.STR == nil || len(df.STR) < 1 { + return ErrMalformedAuditorMessage + } + return nil default: panic("[coniks] Malformed response") } From 3bd8653379978fe6571b6481737ee928df8631ed Mon Sep 17 00:00:00 2001 From: Marcela M Date: Tue, 7 Mar 2017 20:31:16 -0500 Subject: [PATCH 07/26] Add generic STR response handler --- protocol/consistencychecks.go | 55 ++++++++++++++++++++++++++++++++--- protocol/error.go | 2 +- protocol/message.go | 4 ++- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/protocol/consistencychecks.go b/protocol/consistencychecks.go index dd8c98b..97efa1c 100644 --- a/protocol/consistencychecks.go +++ b/protocol/consistencychecks.go @@ -100,6 +100,50 @@ func (cc *ConsistencyChecks) HandleResponse(requestType int, msg *Response, return CheckPassed } +// handleDirectorySTRs is supposed to be used by CONIKS clients to +// handle auditor responses, and by CONIKS auditors to handle directory responses. +func HandleDirectorySTRs(requestType int, msg *Response, signKey sign.PublicKey, + savedSTR *m.SignedTreeRoot, e error, isClient bool) error { + var str *m.SignedTreeRoot + if err := msg.validate(); err != nil { + return e + } + + switch requestType { + case AuditType: + if _, ok := msg.DirectoryResponse.(*ObservedSTR); !ok { + return e + } + str = msg.DirectoryResponse.(*ObservedSTR).STR + // TODO: compare the STR with the saved one on the client + // if the auditor has returned a more recent STR, should the + // client update its savedSTR? Should this force a new round of + // monitoring? + case AuditInEpochType: + // this is the default request type for an auditor + // since the auditor conservatively assumes it may + // have missed epochs + + // FIXME + //if _, ok := msg.DirectoryResponse.(*ObservedSTRs); !ok { + // return e + //} + //str = msg.DirectoryResponse.(*ObservedSTRs).STR + default: + panic("[coniks] Unknown auditing request type") + } + // we assume the requestType is AuditInEpochType if we're here + + // verify the timeliness of the STR if we're the auditor + // check the consistency of the newly received STRs + // FIXME: use `XXInEpoch` version of verifySTRConsistency + if err := verifySTRConsistency(signKey, savedSTR, str); err != nil { + return err + } + + return nil +} + func (cc *ConsistencyChecks) updateSTR(requestType int, msg *Response) error { var str *DirSTR switch requestType { @@ -110,9 +154,6 @@ func (cc *ConsistencyChecks) updateSTR(requestType int, msg *Response) error { cc.SavedSTR = str return nil } - // FIXME: check whether the STR was issued on time and whatnot. - // Maybe it has something to do w/ #81 and client transitioning between epochs. - // Try to verify w/ what's been saved if err := cc.verifySTR(str); err == nil { return nil } @@ -132,7 +173,13 @@ func (cc *ConsistencyChecks) updateSTR(requestType int, msg *Response) error { // verifySTR checks whether the received STR is the same with // the SavedSTR using reflect.DeepEqual(). -func (cc *ConsistencyChecks) verifySTR(str *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. +// Try to verify w/ what's been saved +// FIXME: make this generic so the auditor can also verify the timeliness of the +// STR etc. Might make sense to separate the comparison, which is only done on the client, +// from the rest. +func (cc *ConsistencyChecks) verifySTR(str *m.SignedTreeRoot) error { if reflect.DeepEqual(cc.SavedSTR, str) { return nil } diff --git a/protocol/error.go b/protocol/error.go index 4e55a25..be16002 100644 --- a/protocol/error.go +++ b/protocol/error.go @@ -66,7 +66,7 @@ var ( ErrDirectory: "[coniks] Directory error", ErrAuditLog: "[coniks] Audit log error", ErrMalformedDirectoryMessage: "[coniks] Malformed directory message", - ErrMalformedAuditorMessage: "[coniks] Malformed auditor message", + ErrMalformedAuditorMessage: "[coniks] Malformed auditor message", CheckPassed: "[coniks] Consistency checks passed", CheckBadSignature: "[coniks] Directory's signature on STR or TB is invalid", diff --git a/protocol/message.go b/protocol/message.go index 744fa7b..d5c26c5 100644 --- a/protocol/message.go +++ b/protocol/message.go @@ -12,6 +12,8 @@ const ( KeyLookupType KeyLookupInEpochType MonitoringType + AuditType + AuditInEpochType ) // A Request message defines the data a CONIKS client must send to a CONIKS @@ -202,7 +204,7 @@ type ObservedSTR struct { // An ObservedSTRs response includes a list of signed tree roots // STR. A CONIKS auditor returns this DirectoryResponse type upon an -// AudutingRequest. +// AuditingInEpochRequest. type ObservedSTRs struct { STR []*m.SignedTreeRoot } From c2d107ff03c7a93caac52df7df970ae49cadb49f Mon Sep 17 00:00:00 2001 From: Marcela M Date: Fri, 10 Mar 2017 14:59:27 -0500 Subject: [PATCH 08/26] # This is a combination of 2 commits. # The first commit's message is: Add TODO to move all generic STR auditing code to a separate module # The 2nd commit message will be skipped: # Use single generic verifySTRConsistency to be used by client and auditor --- protocol/consistencychecks.go | 1 + protocol/message.go | 31 ++++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/protocol/consistencychecks.go b/protocol/consistencychecks.go index 97efa1c..c04bc8a 100644 --- a/protocol/consistencychecks.go +++ b/protocol/consistencychecks.go @@ -2,6 +2,7 @@ // 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 diff --git a/protocol/message.go b/protocol/message.go index d5c26c5..82b918c 100644 --- a/protocol/message.go +++ b/protocol/message.go @@ -147,6 +147,34 @@ type AuditingInEpochRequest struct { Epoch uint64 `json:"epoch"` } +// An AuditingRequest is a message with a CONIKS key directory's address +// as a string that a CONIKS client sends to a CONIKS auditor, or a CONIKS auditor +// sends to a CONIKS directory, to request the given directory's latest STR. +// If the client/auditor needs to request a directory's STR for a prior epoch, it +// must send an AuditingInEpochRequest. +// +// The response to a successful request is an ObservedSTR. +type AuditingRequest struct { + DirectoryAddr string `json:"directory_addr"` +} + +// An AuditingInEpochRequest is a message with a key directory's address +// as a string and an epoch as a uint64 that a CONIKS client sends to +// a CONIKS auditor, or a CONIKS auditor sends to a CONIKS directory, +// to retrieve the STR for the directory in +// the given epoch. The client/auditor sends this request type when it needs to +// audit a directory's STR for a prior epoch (i.e. as part of a +// key lookup in epoch check, a monitoring check, or an auditor update). +// The client/auditor can send an AuditingRequest if it needs to audit a +// directory's STR for its latest epoch. +// +// The response to a successful request is an ObservedSTRs with +// a list of STRs covering the epoch range [Epoch, d.LatestSTR().Epoch]. +type AuditingInEpochRequest struct { + DirectoryAddr string `json:"directory_addr"` + Epoch uint64 `json:"epoch"` +} + // A Response message indicates the result of a CONIKS client request // with an appropriate error code, and defines the set of cryptographic // proofs a CONIKS directory must return as part of its response. @@ -308,9 +336,6 @@ func NewMonitoringProof(ap []*m.AuthenticationPath, // upon an AuditingRequest, and returns a Response containing an ObservedSTR struct. // auditlog.GetObservedSTR(), or directory.GetLatestSTR(), passes the signed // tree root for the directory's latest str. -// -// See auditlog.Audit() for details on the contents of the created -// ObservedSTR. func NewObservedSTR(str *m.SignedTreeRoot) (*Response, ErrorCode) { return &Response{ Error: ReqSuccess, From 13d3eb2e1ddcf93c042ebbd60372f8a4f34da68e Mon Sep 17 00:00:00 2001 From: Marcela Melara Date: Sun, 12 Mar 2017 18:00:08 -0400 Subject: [PATCH 09/26] Fix documentation --- protocol/auditlog.go | 32 ++++++++++++++++++++++---------- protocol/auditlog_test.go | 12 ++++++++---- protocol/consistencychecks.go | 5 +++-- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/protocol/auditlog.go b/protocol/auditlog.go index 116d8e7..a2a505a 100644 --- a/protocol/auditlog.go +++ b/protocol/auditlog.go @@ -54,6 +54,17 @@ func (l *ConiksAuditLog) IsKnownDirectory(addr string) bool { return false } +// Insert creates a new directory history for the key directory addr +// and inserts it into the audit log l. +// The directory history is initialized with the key directory's +// signing key signKey, a list of STRs representing the +// directory's prior history oldSTRs, and the directory's latest STR +// latestSTR. +// Insert() returns an ErrAuditLog if the auditor attempts to create +// a new history for a known directory, an ErrMalformedDirectoryMessage +// if oldSTRs is malformed, and nil otherwise. +// Insert() only creates the initial entry in the log for addr. Use Update() +// to insert newly observed STRs for addr in subsequent epochs. // FIXME: pass Response message as param // masomel: will probably want to write a more generic function // for "catching up" on a history in case an auditor misses epochs @@ -96,7 +107,7 @@ func (l *ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, // FIXME: pass Response message as param func (l *ConiksAuditLog) Update(addr string, newSTR *m.SignedTreeRoot) error { - // panic if we want to update an entry for which we don't have + // error if we want to update the entry for an addr we don't know if !l.IsKnownDirectory(addr) { return ErrAuditLog } @@ -113,8 +124,9 @@ func (l *ConiksAuditLog) Update(addr string, newSTR *m.SignedTreeRoot) error { return nil } -// GetObservedSTR gets the observed STR for the CONIKS directory address indicated -// in the AuditingRequest req received from a CONIKS client from the auditor's latest +// GetObservedSTR gets the observed STR for the CONIKS directory address +// indicated in the AuditingRequest req received from a CONIKS client from +// the auditor's latest // directory history entry, and returns a tuple of the form // (response, error). // The response (which also includes the error code) is supposed to @@ -144,22 +156,22 @@ func (l *ConiksAuditLog) GetObservedSTR(req *AuditingRequest) (*Response, ErrorC return NewErrorResponse(ReqUnknownDirectory), ReqUnknownDirectory } -// GetObservedSTRInEpoch gets the observed STR for the CONIKS directory address -// for a prior directory history entry indicated in the +// GetObservedSTRInEpoch gets the observed STR for the CONIKS directory +// address for a prior directory history entry indicated in the // AuditingInEpochRequest req received from a CONIKS client, // and returns a tuple of the form (response, error). // The response (which also includes the error code) is supposed to // be sent back to the client. The returned error is used by the auditor // for logging purposes. // -// A request without a directory address or with an epoch greater than the latest -// observed epoch of this directory is considered malformed, and causes -// GetObservedSTRInEpoch() to return a +// A request without a directory address or with an epoch greater than +// the latest observed epoch of this directory is considered malformed, +// and causes GetObservedSTRInEpoch() to return a // message.NewErrorResponse(ErrMalformedClientMessage) tuple. // GetObservedSTRInEpoch() returns a message.NewObservedSTRs(strs) tuple. // strs is a list of STRs for the epoch range [ep, -// l.histories[req.DirectoryAddr].latestSTR.Epoch], where ep is the past epoch -// for which the client has requested the observed STR. +// l.histories[req.DirectoryAddr].latestSTR.Epoch], where ep is the past +// epoch for which the client has requested the observed STR. // If the auditor doesn't have any history entries for the requested CONIKS // directory, GetObservedSTR() returns a // message.NewErrorResponse(ReqUnknownDirectory) tuple. diff --git a/protocol/auditlog_test.go b/protocol/auditlog_test.go index ca45ca7..b57f543 100644 --- a/protocol/auditlog_test.go +++ b/protocol/auditlog_test.go @@ -63,7 +63,8 @@ func TestInsertExistingHistory(t *testing.T) { t.Fatal("Error inserting new server history") } - // let's make sure that we can't re-insert a new server history into our log + // let's make sure that we can't re-insert a new server + // history into our log err = aud.Insert("test-server", pk, nil, d.LatestSTR()) if err != ErrAuditLog { t.Fatal("Expected an ErrAuditLog when inserting an existing server history") @@ -79,7 +80,8 @@ func TestUpdateUnknownHistory(t *testing.T) { t.Fatal("Error inserting new server history") } - // let's make sure that we can't re-insert a new server history into our log + // let's make sure that we can't re-insert a new server + // history into our log err = aud.Update("unknown", d.LatestSTR()) if err != ErrAuditLog { t.Fatal("Expected an ErrAuditLog when updating an unknown server history") @@ -97,10 +99,11 @@ func TestGetObservedSTR(t *testing.T) { res, err := aud.GetObservedSTR(&AuditingRequest{ DirectoryAddr: "test-server"}) - obs := res.DirectoryResponse.(*ObservedSTR) if err != ReqSuccess { t.Fatal("Unable to get latest observed STR") } + + obs := res.DirectoryResponse.(*ObservedSTR) if obs.STR == nil { t.Fatal("Expect returned STR to be not nil") } @@ -130,10 +133,11 @@ func TestGetObservedSTRInEpoch(t *testing.T) { res, err := aud.GetObservedSTRInEpoch(&AuditingInEpochRequest{ DirectoryAddr: "test-server", Epoch: uint64(6)}) - obs := res.DirectoryResponse.(*ObservedSTRs) if err != ReqSuccess { t.Fatal("Unable to get latest range of STRs") } + + obs := res.DirectoryResponse.(*ObservedSTRs) if obs.STR == nil || len(obs.STR) < 1 { t.Fatal("Expect returned STR to be not nil") } diff --git a/protocol/consistencychecks.go b/protocol/consistencychecks.go index c04bc8a..a587488 100644 --- a/protocol/consistencychecks.go +++ b/protocol/consistencychecks.go @@ -101,8 +101,9 @@ func (cc *ConsistencyChecks) HandleResponse(requestType int, msg *Response, return CheckPassed } -// handleDirectorySTRs is supposed to be used by CONIKS clients to -// handle auditor responses, and by CONIKS auditors to handle directory responses. +// HandleDirectorySTRs is supposed to be used by CONIKS clients to +// handle auditor responses, and by CONIKS auditors to handle directory +// responses. func HandleDirectorySTRs(requestType int, msg *Response, signKey sign.PublicKey, savedSTR *m.SignedTreeRoot, e error, isClient bool) error { var str *m.SignedTreeRoot From 0d0d31267c7a04ebf14dcf7036374ca6204a2050 Mon Sep 17 00:00:00 2001 From: Marcela Melara Date: Sun, 12 Mar 2017 18:27:33 -0400 Subject: [PATCH 10/26] Use DirSTR instead of merkletree.SignedTreeRoot in auditlog --- protocol/auditlog.go | 15 +++++++-------- protocol/auditlog_test.go | 9 ++++----- protocol/consistencychecks.go | 8 ++++---- protocol/message.go | 20 +++----------------- 4 files changed, 18 insertions(+), 34 deletions(-) diff --git a/protocol/auditlog.go b/protocol/auditlog.go index a2a505a..037f7c9 100644 --- a/protocol/auditlog.go +++ b/protocol/auditlog.go @@ -7,13 +7,12 @@ package protocol import ( "github.com/coniks-sys/coniks-go/crypto/sign" - m "github.com/coniks-sys/coniks-go/merkletree" ) type directoryHistory struct { signKey sign.PublicKey - snapshots map[uint64]*m.SignedTreeRoot - latestSTR *m.SignedTreeRoot + snapshots map[uint64]*DirSTR + latestSTR *DirSTR } // A ConiksAuditLog maintains the histories @@ -25,10 +24,10 @@ type ConiksAuditLog struct { histories map[string]*directoryHistory } -func newDirectoryHistory(signKey sign.PublicKey, str *m.SignedTreeRoot) *directoryHistory { +func newDirectoryHistory(signKey sign.PublicKey, str *DirSTR) *directoryHistory { h := new(directoryHistory) h.signKey = signKey - h.snapshots = make(map[uint64]*m.SignedTreeRoot) + h.snapshots = make(map[uint64]*DirSTR) h.latestSTR = str return h } @@ -69,7 +68,7 @@ func (l *ConiksAuditLog) IsKnownDirectory(addr string) bool { // masomel: will probably want to write a more generic function // for "catching up" on a history in case an auditor misses epochs func (l *ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, - oldSTRs map[uint64]*m.SignedTreeRoot, latestSTR *m.SignedTreeRoot) error { + oldSTRs map[uint64]*DirSTR, latestSTR *DirSTR) error { // error if we want to create a new entry for an addr we already know if l.IsKnownDirectory(addr) { @@ -105,7 +104,7 @@ func (l *ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, // addr prior to its first call and thereby expects that an entry for addr // exists in the audit log l. // FIXME: pass Response message as param -func (l *ConiksAuditLog) Update(addr string, newSTR *m.SignedTreeRoot) error { +func (l *ConiksAuditLog) Update(addr string, newSTR *DirSTR) error { // error if we want to update the entry for an addr we don't know if !l.IsKnownDirectory(addr) { @@ -192,7 +191,7 @@ func (l *ConiksAuditLog) GetObservedSTRInEpoch(req *AuditingInEpochRequest) (*Re ErrMalformedClientMessage } - var strs []*m.SignedTreeRoot + var strs []*DirSTR startEp := req.Epoch endEp := h.latestSTR.Epoch diff --git a/protocol/auditlog_test.go b/protocol/auditlog_test.go index b57f543..7783532 100644 --- a/protocol/auditlog_test.go +++ b/protocol/auditlog_test.go @@ -1,7 +1,6 @@ package protocol import ( - m "github.com/coniks-sys/coniks-go/merkletree" "testing" ) @@ -41,7 +40,7 @@ func TestInsertPriorHistory(t *testing.T) { aud := NewAuditLog() // create 10 epochs - priorSTRs := make(map[uint64]*m.SignedTreeRoot) + priorSTRs := make(map[uint64]*DirSTR) for i := 0; i < 10; i++ { priorSTRs[d.LatestSTR().Epoch] = d.LatestSTR() d.Update() @@ -118,7 +117,7 @@ func TestGetObservedSTRInEpoch(t *testing.T) { aud := NewAuditLog() // create 10 epochs - priorSTRs := make(map[uint64]*m.SignedTreeRoot) + priorSTRs := make(map[uint64]*DirSTR) for i := 0; i < 10; i++ { priorSTRs[d.LatestSTR().Epoch] = d.LatestSTR() d.Update() @@ -155,7 +154,7 @@ func TestGetObservedSTRUnknown(t *testing.T) { aud := NewAuditLog() // create 10 epochs - priorSTRs := make(map[uint64]*m.SignedTreeRoot) + priorSTRs := make(map[uint64]*DirSTR) for i := 0; i < 10; i++ { priorSTRs[d.LatestSTR().Epoch] = d.LatestSTR() d.Update() @@ -188,7 +187,7 @@ func TestGetObservedSTRMalformed(t *testing.T) { aud := NewAuditLog() // create 10 epochs - priorSTRs := make(map[uint64]*m.SignedTreeRoot) + priorSTRs := make(map[uint64]*DirSTR) for i := 0; i < 10; i++ { priorSTRs[d.LatestSTR().Epoch] = d.LatestSTR() d.Update() diff --git a/protocol/consistencychecks.go b/protocol/consistencychecks.go index a587488..9521a3f 100644 --- a/protocol/consistencychecks.go +++ b/protocol/consistencychecks.go @@ -105,8 +105,8 @@ func (cc *ConsistencyChecks) HandleResponse(requestType int, msg *Response, // handle auditor responses, and by CONIKS auditors to handle directory // responses. func HandleDirectorySTRs(requestType int, msg *Response, signKey sign.PublicKey, - savedSTR *m.SignedTreeRoot, e error, isClient bool) error { - var str *m.SignedTreeRoot + savedSTR *DirSTR, e error, isClient bool) error { + var str *DirSTR if err := msg.validate(); err != nil { return e } @@ -181,7 +181,7 @@ func (cc *ConsistencyChecks) updateSTR(requestType int, msg *Response) error { // FIXME: make this generic so the auditor can also verify the timeliness of the // STR etc. Might make sense to separate the comparison, which is only done on the client, // from the rest. -func (cc *ConsistencyChecks) verifySTR(str *m.SignedTreeRoot) error { +func (cc *ConsistencyChecks) verifySTR(str *DirSTR) error { if reflect.DeepEqual(cc.SavedSTR, str) { return nil } @@ -195,7 +195,7 @@ func (cc *ConsistencyChecks) verifySTR(str *m.SignedTreeRoot) error { // in its history. // In the case of a client-side consistency check, verifySTRConsistency() // should not verify the hash chain using the STR stored in cc. -func verifySTRConsistency(signKey sign.PublicKey, savedSTR, str *m.SignedTreeRoot) error { +func verifySTRConsistency(signKey sign.PublicKey, savedSTR, str *DirSTR) error { // verify STR's signature if !signKey.Verify(str.Serialize(), str.Signature) { return CheckBadSignature diff --git a/protocol/message.go b/protocol/message.go index 82b918c..684b1a3 100644 --- a/protocol/message.go +++ b/protocol/message.go @@ -213,28 +213,14 @@ type DirectoryProofs struct { // STR. A CONIKS auditor returns this DirectoryResponse type upon an // AuditingRequest. type ObservedSTR struct { - STR *m.SignedTreeRoot + STR *DirSTR } // An ObservedSTRs response includes a list of signed tree roots // STR. A CONIKS auditor returns this DirectoryResponse type upon an // AudutingRequest. type ObservedSTRs struct { - STR []*m.SignedTreeRoot -} - -// An ObservedSTR response includes a single signed tree root -// STR. A CONIKS auditor returns this DirectoryResponse type upon an -// AuditingRequest. -type ObservedSTR struct { - STR *m.SignedTreeRoot -} - -// An ObservedSTRs response includes a list of signed tree roots -// STR. A CONIKS auditor returns this DirectoryResponse type upon an -// AuditingInEpochRequest. -type ObservedSTRs struct { - STR []*m.SignedTreeRoot + STR []*DirSTR } // NewErrorResponse creates a new response message indicating the error @@ -353,7 +339,7 @@ func NewObservedSTR(str *m.SignedTreeRoot) (*Response, ErrorCode) { // // See auditlog.AuditInEpoch() for details on the contents of the created // ObservedSTRs. -func NewObservedSTRs(str []*m.SignedTreeRoot) (*Response, ErrorCode) { +func NewObservedSTRs(str []*DirSTR) (*Response, ErrorCode) { return &Response{ Error: ReqSuccess, DirectoryResponse: &ObservedSTRs{ From 8b1eeebb35f8d78ff140c2795a50f8f7c02c2a25 Mon Sep 17 00:00:00 2001 From: Marcela M Date: Tue, 4 Apr 2017 17:43:13 -0400 Subject: [PATCH 11/26] Remove all references to auditor-directory communication, make auditor response message generic --- protocol/auditlog.go | 53 +++++------------------- protocol/auditlog_test.go | 38 ++++++++++-------- protocol/consistencychecks.go | 49 +--------------------- protocol/message.go | 76 ++++++++--------------------------- 4 files changed, 49 insertions(+), 167 deletions(-) diff --git a/protocol/auditlog.go b/protocol/auditlog.go index 037f7c9..762e054 100644 --- a/protocol/auditlog.go +++ b/protocol/auditlog.go @@ -123,41 +123,9 @@ func (l *ConiksAuditLog) Update(addr string, newSTR *DirSTR) error { return nil } -// GetObservedSTR gets the observed STR for the CONIKS directory address -// indicated in the AuditingRequest req received from a CONIKS client from -// the auditor's latest -// directory history entry, and returns a tuple of the form -// (response, error). -// The response (which also includes the error code) is supposed to -// be sent back to the client. The returned error is used by the auditor -// for logging purposes. -// -// A request without a directory address is considered -// malformed, and causes GetObservedSTR() to return a -// message.NewErrorResponse(ErrMalformedClientMessage) tuple. -// GetObservedSTR() returns a message.NewObservedSTR(str) tuple. -// str is the signed tree root the auditor has observed for the latest epoch. -// If the auditor doesn't have any history entries for the requested CONIKS -// directory, GetObservedSTR() returns a -// message.NewErrorResponse(ReqUnknownDirectory) tuple. -func (l *ConiksAuditLog) GetObservedSTR(req *AuditingRequest) (*Response, ErrorCode) { - - // make sure the request is well-formed - if len(req.DirectoryAddr) <= 0 { - return NewErrorResponse(ErrMalformedClientMessage), - ErrMalformedClientMessage - } - - if h := l.histories[req.DirectoryAddr]; h != nil { - return NewObservedSTR(h.latestSTR) - } - - return NewErrorResponse(ReqUnknownDirectory), ReqUnknownDirectory -} - -// GetObservedSTRInEpoch gets the observed STR for the CONIKS directory -// address for a prior directory history entry indicated in the -// AuditingInEpochRequest req received from a CONIKS client, +// GetObservedSTRs gets the observed STR for the CONIKS directory +// address for a directory history entry indicated in the +// AuditingRequest req received from a CONIKS client, // and returns a tuple of the form (response, error). // The response (which also includes the error code) is supposed to // be sent back to the client. The returned error is used by the auditor @@ -165,16 +133,17 @@ func (l *ConiksAuditLog) GetObservedSTR(req *AuditingRequest) (*Response, ErrorC // // A request without a directory address or with an epoch greater than // the latest observed epoch of this directory is considered malformed, -// and causes GetObservedSTRInEpoch() to return a +// and causes GetObservedSTRs() to return a // message.NewErrorResponse(ErrMalformedClientMessage) tuple. -// GetObservedSTRInEpoch() returns a message.NewObservedSTRs(strs) tuple. +// GetObservedSTRs() returns a message.NewSTRList(strs) tuple. // strs is a list of STRs for the epoch range [ep, -// l.histories[req.DirectoryAddr].latestSTR.Epoch], where ep is the past -// epoch for which the client has requested the observed STR. +// l.histories[req.DirectoryAddr].latestSTR.Epoch], where ep is the epoch for +// which the client has requested the observed STR; i.e. if ep == the latest epoch, +// the list returned is of length 1. // If the auditor doesn't have any history entries for the requested CONIKS -// directory, GetObservedSTR() returns a +// directory, GetObservedSTRs() returns a // message.NewErrorResponse(ReqUnknownDirectory) tuple. -func (l *ConiksAuditLog) GetObservedSTRInEpoch(req *AuditingInEpochRequest) (*Response, +func (l *ConiksAuditLog) GetObservedSTRs(req *AuditingRequest) (*Response, ErrorCode) { // make sure the request is well-formed @@ -203,7 +172,7 @@ func (l *ConiksAuditLog) GetObservedSTRInEpoch(req *AuditingInEpochRequest) (*Re // don't forget to append the latest STR strs = append(strs, h.latestSTR) - return NewObservedSTRs(strs) + return NewSTRList(strs) } return NewErrorResponse(ReqUnknownDirectory), ReqUnknownDirectory diff --git a/protocol/auditlog_test.go b/protocol/auditlog_test.go index 7783532..896e081 100644 --- a/protocol/auditlog_test.go +++ b/protocol/auditlog_test.go @@ -87,7 +87,7 @@ func TestUpdateUnknownHistory(t *testing.T) { } } -func TestGetObservedSTR(t *testing.T) { +func TestGetLatestObservedSTR(t *testing.T) { // let's just create basic test directory and an empty audit log d, pk := NewTestDirectory(t, true) aud := NewAuditLog() @@ -96,17 +96,18 @@ func TestGetObservedSTR(t *testing.T) { t.Fatal("Error inserting new server history") } - res, err := aud.GetObservedSTR(&AuditingRequest{ - DirectoryAddr: "test-server"}) + res, err := aud.GetObservedSTRs(&AuditingRequest{ + DirectoryAddr: "test-server", + Epoch: uint64(d.LatestSTR().Epoch)}) if err != ReqSuccess { t.Fatal("Unable to get latest observed STR") } - obs := res.DirectoryResponse.(*ObservedSTR) - if obs.STR == nil { + obs := res.DirectoryResponse.(*STRList) + if len(obs.STR) != 1 { t.Fatal("Expect returned STR to be not nil") } - if obs.STR.Epoch != d.LatestSTR().Epoch { + if obs.STR[0].Epoch != d.LatestSTR().Epoch { t.Fatal("Unexpected epoch for returned STR") } } @@ -129,15 +130,16 @@ func TestGetObservedSTRInEpoch(t *testing.T) { t.Fatal("Error inserting new server history with prior STRs") } - res, err := aud.GetObservedSTRInEpoch(&AuditingInEpochRequest{ + res, err := aud.GetObservedSTRs(&AuditingRequest{ DirectoryAddr: "test-server", - Epoch: uint64(6)}) + Epoch: uint64(6)}) + if err != ReqSuccess { t.Fatal("Unable to get latest range of STRs") } - obs := res.DirectoryResponse.(*ObservedSTRs) - if obs.STR == nil || len(obs.STR) < 1 { + obs := res.DirectoryResponse.(*STRList) + if len(obs.STR) == 0 { t.Fatal("Expect returned STR to be not nil") } if len(obs.STR) != 5 { @@ -166,13 +168,14 @@ func TestGetObservedSTRUnknown(t *testing.T) { t.Fatal("Error inserting new server history with prior STRs") } - _, err = aud.GetObservedSTR(&AuditingRequest{ - DirectoryAddr: "unknown"}) + _, err = aud.GetObservedSTRs(&AuditingRequest{ + DirectoryAddr: "unknown", + Epoch: uint64(d.LatestSTR().Epoch)}) if err != ReqUnknownDirectory { t.Fatal("Expect ReqUnknownDirectory for latest STR") } - _, err = aud.GetObservedSTRInEpoch(&AuditingInEpochRequest{ + _, err = aud.GetObservedSTRs(&AuditingRequest{ DirectoryAddr: "unknown", Epoch: uint64(6)}) if err != ReqUnknownDirectory { @@ -199,13 +202,14 @@ func TestGetObservedSTRMalformed(t *testing.T) { t.Fatal("Error inserting new server history with prior STRs") } - _, err = aud.GetObservedSTR(&AuditingRequest{ - DirectoryAddr: ""}) + _, err = aud.GetObservedSTRs(&AuditingRequest{ + DirectoryAddr: "", + Epoch: uint64(d.LatestSTR().Epoch)}) if err != ErrMalformedClientMessage { t.Fatal("Expect ErrMalFormedClientMessage for latest STR") } - _, err = aud.GetObservedSTRInEpoch(&AuditingInEpochRequest{ + _, err = aud.GetObservedSTRs(&AuditingRequest{ DirectoryAddr: "", Epoch: uint64(6)}) if err != ErrMalformedClientMessage { @@ -213,7 +217,7 @@ func TestGetObservedSTRMalformed(t *testing.T) { } // also test the epoch range - _, err = aud.GetObservedSTRInEpoch(&AuditingInEpochRequest{ + _, err = aud.GetObservedSTRs(&AuditingRequest{ DirectoryAddr: "", Epoch: uint64(20)}) if err != ErrMalformedClientMessage { diff --git a/protocol/consistencychecks.go b/protocol/consistencychecks.go index 9521a3f..87d6141 100644 --- a/protocol/consistencychecks.go +++ b/protocol/consistencychecks.go @@ -101,51 +101,6 @@ func (cc *ConsistencyChecks) HandleResponse(requestType int, msg *Response, return CheckPassed } -// HandleDirectorySTRs is supposed to be used by CONIKS clients to -// handle auditor responses, and by CONIKS auditors to handle directory -// responses. -func HandleDirectorySTRs(requestType int, msg *Response, signKey sign.PublicKey, - savedSTR *DirSTR, e error, isClient bool) error { - var str *DirSTR - if err := msg.validate(); err != nil { - return e - } - - switch requestType { - case AuditType: - if _, ok := msg.DirectoryResponse.(*ObservedSTR); !ok { - return e - } - str = msg.DirectoryResponse.(*ObservedSTR).STR - // TODO: compare the STR with the saved one on the client - // if the auditor has returned a more recent STR, should the - // client update its savedSTR? Should this force a new round of - // monitoring? - case AuditInEpochType: - // this is the default request type for an auditor - // since the auditor conservatively assumes it may - // have missed epochs - - // FIXME - //if _, ok := msg.DirectoryResponse.(*ObservedSTRs); !ok { - // return e - //} - //str = msg.DirectoryResponse.(*ObservedSTRs).STR - default: - panic("[coniks] Unknown auditing request type") - } - // we assume the requestType is AuditInEpochType if we're here - - // verify the timeliness of the STR if we're the auditor - // check the consistency of the newly received STRs - // FIXME: use `XXInEpoch` version of verifySTRConsistency - if err := verifySTRConsistency(signKey, savedSTR, str); err != nil { - return err - } - - return nil -} - func (cc *ConsistencyChecks) updateSTR(requestType int, msg *Response) error { var str *DirSTR switch requestType { @@ -191,10 +146,8 @@ func (cc *ConsistencyChecks) verifySTR(str *DirSTR) error { // verifySTRConsistency checks the consistency between 2 snapshots. // It uses the signing key signKey to verify the STR's signature. // The signKey param either comes from a client's -// pinned signing key in cc, or an auditor's pinned signing key +// pinned signing key, or an auditor's pinned signing key // in its history. -// In the case of a client-side consistency check, verifySTRConsistency() -// should not verify the hash chain using the STR stored in cc. func verifySTRConsistency(signKey sign.PublicKey, savedSTR, str *DirSTR) error { // verify STR's signature if !signKey.Verify(str.Serialize(), str.Signature) { diff --git a/protocol/message.go b/protocol/message.go index 684b1a3..2905cf8 100644 --- a/protocol/message.go +++ b/protocol/message.go @@ -13,7 +13,6 @@ const ( KeyLookupInEpochType MonitoringType AuditType - AuditInEpochType ) // A Request message defines the data a CONIKS client must send to a CONIKS @@ -148,29 +147,13 @@ type AuditingInEpochRequest struct { } // An AuditingRequest is a message with a CONIKS key directory's address -// as a string that a CONIKS client sends to a CONIKS auditor, or a CONIKS auditor -// sends to a CONIKS directory, to request the given directory's latest STR. -// If the client/auditor needs to request a directory's STR for a prior epoch, it -// must send an AuditingInEpochRequest. -// -// The response to a successful request is an ObservedSTR. -type AuditingRequest struct { - DirectoryAddr string `json:"directory_addr"` -} - -// An AuditingInEpochRequest is a message with a key directory's address // as a string and an epoch as a uint64 that a CONIKS client sends to -// a CONIKS auditor, or a CONIKS auditor sends to a CONIKS directory, -// to retrieve the STR for the directory in -// the given epoch. The client/auditor sends this request type when it needs to -// audit a directory's STR for a prior epoch (i.e. as part of a -// key lookup in epoch check, a monitoring check, or an auditor update). -// The client/auditor can send an AuditingRequest if it needs to audit a -// directory's STR for its latest epoch. +// a CONIKS auditor to request the given directory's STR at the given +// epoch. // // The response to a successful request is an ObservedSTRs with // a list of STRs covering the epoch range [Epoch, d.LatestSTR().Epoch]. -type AuditingInEpochRequest struct { +type AuditingRequest struct { DirectoryAddr string `json:"directory_addr"` Epoch uint64 `json:"epoch"` } @@ -209,17 +192,10 @@ type DirectoryProofs struct { STR []*DirSTR } -// An ObservedSTR response includes a single signed tree root -// STR. A CONIKS auditor returns this DirectoryResponse type upon an -// AuditingRequest. -type ObservedSTR struct { - STR *DirSTR -} - -// An ObservedSTRs response includes a list of signed tree roots +// An STRList response includes a list of signed tree roots // STR. A CONIKS auditor returns this DirectoryResponse type upon an // AudutingRequest. -type ObservedSTRs struct { +type STRList struct { STR []*DirSTR } @@ -232,8 +208,7 @@ func NewErrorResponse(e ErrorCode) *Response { var _ DirectoryResponse = (*DirectoryProof)(nil) var _ DirectoryResponse = (*DirectoryProofs)(nil) -var _ DirectoryResponse = (*ObservedSTR)(nil) -var _ DirectoryResponse = (*ObservedSTRs)(nil) +var _ DirectoryResponse = (*STRList)(nil) // NewRegistrationProof creates the response message a CONIKS directory // sends to a client upon a RegistrationRequest, @@ -317,32 +292,18 @@ func NewMonitoringProof(ap []*m.AuthenticationPath, }, ReqSuccess } -// NewObservedSTR creates the response message a CONIKS auditor -// sends to a client, or a CONIKS directory sends to an auditor, -// upon an AuditingRequest, and returns a Response containing an ObservedSTR struct. -// auditlog.GetObservedSTR(), or directory.GetLatestSTR(), passes the signed -// tree root for the directory's latest str. -func NewObservedSTR(str *m.SignedTreeRoot) (*Response, ErrorCode) { - return &Response{ - Error: ReqSuccess, - DirectoryResponse: &ObservedSTR{ - STR: str, - }, - }, ReqSuccess -} - -// NewObservedSTRs creates the response message a CONIKS auditor -// sends to a client upon an AuditingInEpochRequest, -// and returns a Response containing an ObservedSTRs struct. -// auditlog.AuditInEpoch() passes a list of signed tree roots +// NewSTRList creates the response message a CONIKS auditor +// sends to a client upon an AuditingRequest, +// and returns a Response containing an STRList struct. +// auditlog.GetObservedSTRs() passes a list of one or more signed tree roots // that the auditor observed for the requested range of epochs str. // -// See auditlog.AuditInEpoch() for details on the contents of the created -// ObservedSTRs. -func NewObservedSTRs(str []*DirSTR) (*Response, ErrorCode) { +// See auditlog.GetObservedSTRs() for details on the contents of the created +// STRList. +func NewSTRList(str []*DirSTR) (*Response, ErrorCode) { return &Response{ Error: ReqSuccess, - DirectoryResponse: &ObservedSTRs{ + DirectoryResponse: &STRList{ STR: str, }, }, ReqSuccess @@ -361,13 +322,8 @@ func (msg *Response) validate() error { case *DirectoryProofs: // TODO: also do above assertions here return nil - case *ObservedSTR: - if df.STR == nil { - return ErrMalformedAuditorMessage - } - return nil - case *ObservedSTRs: - if df.STR == nil || len(df.STR) < 1 { + case *STRList: + if len(df.STR) == 0 { return ErrMalformedAuditorMessage } return nil From 3872e329fdddd6f44e4bf0f95b5880bafcc75e1a Mon Sep 17 00:00:00 2001 From: Marcela M Date: Wed, 5 Apr 2017 16:02:48 -0400 Subject: [PATCH 12/26] STRList -> STRHistoryRange --- protocol/auditlog.go | 4 +- protocol/auditlog_test.go | 12 +++--- protocol/message.go | 85 ++++++++------------------------------- protocol/str.go | 2 +- 4 files changed, 26 insertions(+), 77 deletions(-) diff --git a/protocol/auditlog.go b/protocol/auditlog.go index 762e054..63cb3d8 100644 --- a/protocol/auditlog.go +++ b/protocol/auditlog.go @@ -135,7 +135,7 @@ func (l *ConiksAuditLog) Update(addr string, newSTR *DirSTR) error { // the latest observed epoch of this directory is considered malformed, // and causes GetObservedSTRs() to return a // message.NewErrorResponse(ErrMalformedClientMessage) tuple. -// GetObservedSTRs() returns a message.NewSTRList(strs) tuple. +// GetObservedSTRs() returns a message.NewSTRHistoryRange(strs) tuple. // strs is a list of STRs for the epoch range [ep, // l.histories[req.DirectoryAddr].latestSTR.Epoch], where ep is the epoch for // which the client has requested the observed STR; i.e. if ep == the latest epoch, @@ -172,7 +172,7 @@ func (l *ConiksAuditLog) GetObservedSTRs(req *AuditingRequest) (*Response, // don't forget to append the latest STR strs = append(strs, h.latestSTR) - return NewSTRList(strs) + return NewSTRHistoryRange(strs) } return NewErrorResponse(ReqUnknownDirectory), ReqUnknownDirectory diff --git a/protocol/auditlog_test.go b/protocol/auditlog_test.go index 896e081..7bd9439 100644 --- a/protocol/auditlog_test.go +++ b/protocol/auditlog_test.go @@ -98,12 +98,12 @@ func TestGetLatestObservedSTR(t *testing.T) { res, err := aud.GetObservedSTRs(&AuditingRequest{ DirectoryAddr: "test-server", - Epoch: uint64(d.LatestSTR().Epoch)}) + Epoch: uint64(d.LatestSTR().Epoch)}) if err != ReqSuccess { t.Fatal("Unable to get latest observed STR") } - obs := res.DirectoryResponse.(*STRList) + obs := res.DirectoryResponse.(*STRHistoryRange) if len(obs.STR) != 1 { t.Fatal("Expect returned STR to be not nil") } @@ -132,13 +132,13 @@ func TestGetObservedSTRInEpoch(t *testing.T) { res, err := aud.GetObservedSTRs(&AuditingRequest{ DirectoryAddr: "test-server", - Epoch: uint64(6)}) + Epoch: uint64(6)}) if err != ReqSuccess { t.Fatal("Unable to get latest range of STRs") } - obs := res.DirectoryResponse.(*STRList) + obs := res.DirectoryResponse.(*STRHistoryRange) if len(obs.STR) == 0 { t.Fatal("Expect returned STR to be not nil") } @@ -170,7 +170,7 @@ func TestGetObservedSTRUnknown(t *testing.T) { _, err = aud.GetObservedSTRs(&AuditingRequest{ DirectoryAddr: "unknown", - Epoch: uint64(d.LatestSTR().Epoch)}) + Epoch: uint64(d.LatestSTR().Epoch)}) if err != ReqUnknownDirectory { t.Fatal("Expect ReqUnknownDirectory for latest STR") } @@ -204,7 +204,7 @@ func TestGetObservedSTRMalformed(t *testing.T) { _, err = aud.GetObservedSTRs(&AuditingRequest{ DirectoryAddr: "", - Epoch: uint64(d.LatestSTR().Epoch)}) + Epoch: uint64(d.LatestSTR().Epoch)}) if err != ErrMalformedClientMessage { t.Fatal("Expect ErrMalFormedClientMessage for latest STR") } diff --git a/protocol/message.go b/protocol/message.go index 2905cf8..e2217da 100644 --- a/protocol/message.go +++ b/protocol/message.go @@ -91,71 +91,16 @@ type MonitoringRequest struct { EndEpoch uint64 } -// An AuditingRequest is a message with a CONIKS key directory's address -// as a string that a CONIKS client sends to a CONIKS auditor to request -// the latest STR the auditor has observed for the given directory. -// If the client needs to request a directory's STR for a prior epoch, it -// must send an AuditingInEpochRequest. -// -// The response to a successful request is an ObservedDirectoryProof. -type AuditingRequest struct { - DirectoryAddr string `json:"directory_addr"` -} - -// An AuditingInEpochRequest is a message with a key directory's address -// as a string and an epoch as a uint64 that a CONIKS client sends to -// a CONIKS auditor to retrieve the STR it observed for the directory in -// the given epoch. The client sends this request type when it needs to -// audit a directory's STR for a prior epoch (i.e. as part of a -// key lookup in epoch check or a monitoring check). The client can send an -// AuditingRequest if it needs to audit a directory's STR for its latest -// epoch. -// -// The response to a successful request is an ObservedDirectoryProofs with -// a list of STRs covering the epoch range [Epoch, d.LatestSTR().Epoch]. -type AuditingInEpochRequest struct { - DirectoryAddr string `json:"directory_addr"` - Epoch uint64 `json:"epoch"` -} - -// An AuditingRequest is a message with a CONIKS key directory's address -// as a string that a CONIKS client sends to a CONIKS auditor, or a CONIKS auditor -// sends to a CONIKS directory, to request the given directory's latest STR. -// If the client/auditor needs to request a directory's STR for a prior epoch, it -// must send an AuditingInEpochRequest. -// -// The response to a successful request is an ObservedSTR. -type AuditingRequest struct { - DirectoryAddr string `json:"directory_addr"` -} - -// An AuditingInEpochRequest is a message with a key directory's address -// as a string and an epoch as a uint64 that a CONIKS client sends to -// a CONIKS auditor, or a CONIKS auditor sends to a CONIKS directory, -// to retrieve the STR for the directory in -// the given epoch. The client/auditor sends this request type when it needs to -// audit a directory's STR for a prior epoch (i.e. as part of a -// key lookup in epoch check, a monitoring check, or an auditor update). -// The client/auditor can send an AuditingRequest if it needs to audit a -// directory's STR for its latest epoch. -// -// The response to a successful request is an ObservedSTRs with -// a list of STRs covering the epoch range [Epoch, d.LatestSTR().Epoch]. -type AuditingInEpochRequest struct { - DirectoryAddr string `json:"directory_addr"` - Epoch uint64 `json:"epoch"` -} - // An AuditingRequest is a message with a CONIKS key directory's address // as a string and an epoch as a uint64 that a CONIKS client sends to // a CONIKS auditor to request the given directory's STR at the given // epoch. // -// The response to a successful request is an ObservedSTRs with +// The response to a successful request is an STRHistoryRange with // a list of STRs covering the epoch range [Epoch, d.LatestSTR().Epoch]. type AuditingRequest struct { - DirectoryAddr string `json:"directory_addr"` - Epoch uint64 `json:"epoch"` + DirectoryAddr string + Epoch uint64 } // A Response message indicates the result of a CONIKS client request @@ -192,10 +137,12 @@ type DirectoryProofs struct { STR []*DirSTR } -// An STRList response includes a list of signed tree roots -// STR. A CONIKS auditor returns this DirectoryResponse type upon an +// An STRHistoryRange response includes a list of signed tree roots +// STR representing a range of the STR hash chain. If the range only +// covers the latest epoch, the list only contains a single STR. +// A CONIKS auditor returns this DirectoryResponse type upon an // AudutingRequest. -type STRList struct { +type STRHistoryRange struct { STR []*DirSTR } @@ -208,7 +155,7 @@ func NewErrorResponse(e ErrorCode) *Response { var _ DirectoryResponse = (*DirectoryProof)(nil) var _ DirectoryResponse = (*DirectoryProofs)(nil) -var _ DirectoryResponse = (*STRList)(nil) +var _ DirectoryResponse = (*STRHistoryRange)(nil) // NewRegistrationProof creates the response message a CONIKS directory // sends to a client upon a RegistrationRequest, @@ -292,18 +239,18 @@ func NewMonitoringProof(ap []*m.AuthenticationPath, }, ReqSuccess } -// NewSTRList creates the response message a CONIKS auditor +// NewSTRHistoryRange creates the response message a CONIKS auditor // sends to a client upon an AuditingRequest, -// and returns a Response containing an STRList struct. +// and returns a Response containing an STRHistoryRange struct. // auditlog.GetObservedSTRs() passes a list of one or more signed tree roots // that the auditor observed for the requested range of epochs str. // // See auditlog.GetObservedSTRs() for details on the contents of the created -// STRList. -func NewSTRList(str []*DirSTR) (*Response, ErrorCode) { +// STRHistoryRange. +func NewSTRHistoryRange(str []*DirSTR) (*Response, ErrorCode) { return &Response{ Error: ReqSuccess, - DirectoryResponse: &STRList{ + DirectoryResponse: &STRHistoryRange{ STR: str, }, }, ReqSuccess @@ -322,7 +269,9 @@ func (msg *Response) validate() error { case *DirectoryProofs: // TODO: also do above assertions here return nil - case *STRList: + case *STRHistoryRange: + // treat the STRHistoryRange as an auditor response + // bc validate is only called by a client if len(df.STR) == 0 { return ErrMalformedAuditorMessage } diff --git a/protocol/str.go b/protocol/str.go index db92f96..826f173 100644 --- a/protocol/str.go +++ b/protocol/str.go @@ -19,7 +19,7 @@ func NewDirSTR(str *merkletree.SignedTreeRoot) *DirSTR { // Serialize overrides merkletree.SignedTreeRoot.Serialize func (str *DirSTR) Serialize() []byte { - return append(str.SerializeInternal(), str.Policies.Serialize()...) + return append(str.SignedTreeRoot.SerializeInternal(), str.Policies.Serialize()...) } // VerifyHashChain wraps merkletree.SignedTreeRoot.VerifyHashChain From 1f609a8ac903d5b9f649c1fca15fd89c68bee366 Mon Sep 17 00:00:00 2001 From: Marcela Date: Thu, 1 Jun 2017 16:19:18 -0700 Subject: [PATCH 13/26] Fail sooner in GetObservedSTRs --- protocol/auditlog.go | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/protocol/auditlog.go b/protocol/auditlog.go index 63cb3d8..03a2aea 100644 --- a/protocol/auditlog.go +++ b/protocol/auditlog.go @@ -152,28 +152,29 @@ func (l *ConiksAuditLog) GetObservedSTRs(req *AuditingRequest) (*Response, ErrMalformedClientMessage } - if h := l.histories[req.DirectoryAddr]; h != nil { + h := l.histories[req.DirectoryAddr] - // also make sure the epoch is well-formed - if req.Epoch > h.latestSTR.Epoch { - return NewErrorResponse(ErrMalformedClientMessage), - ErrMalformedClientMessage - } - - var strs []*DirSTR - startEp := req.Epoch - endEp := h.latestSTR.Epoch + if h == nil { + return NewErrorResponse(ReqUnknownDirectory), ReqUnknownDirectory + } - for ep := startEp; ep < endEp; ep++ { - str := h.snapshots[ep] - strs = append(strs, str) - } + // also make sure the epoch is well-formed + if req.Epoch > h.latestSTR.Epoch { + return NewErrorResponse(ErrMalformedClientMessage), + ErrMalformedClientMessage + } - // don't forget to append the latest STR - strs = append(strs, h.latestSTR) + var strs []*DirSTR + startEp := req.Epoch + endEp := h.latestSTR.Epoch - return NewSTRHistoryRange(strs) + for ep := startEp; ep < endEp; ep++ { + str := h.snapshots[ep] + strs = append(strs, str) } - return NewErrorResponse(ReqUnknownDirectory), ReqUnknownDirectory + // don't forget to append the latest STR + strs = append(strs, h.latestSTR) + + return NewSTRHistoryRange(strs) } From 477cddf16df3514685971b4884e0c7d9d12cfa5e Mon Sep 17 00:00:00 2001 From: Marcela Date: Fri, 2 Jun 2017 18:04:21 -0700 Subject: [PATCH 14/26] Revert changes to protocol/str.go --- protocol/str.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/str.go b/protocol/str.go index 826f173..db92f96 100644 --- a/protocol/str.go +++ b/protocol/str.go @@ -19,7 +19,7 @@ func NewDirSTR(str *merkletree.SignedTreeRoot) *DirSTR { // Serialize overrides merkletree.SignedTreeRoot.Serialize func (str *DirSTR) Serialize() []byte { - return append(str.SignedTreeRoot.SerializeInternal(), str.Policies.Serialize()...) + return append(str.SerializeInternal(), str.Policies.Serialize()...) } // VerifyHashChain wraps merkletree.SignedTreeRoot.VerifyHashChain From c6d106c3458f1886402fe1aae16238a589cc435a Mon Sep 17 00:00:00 2001 From: Marcela M Date: Mon, 26 Jun 2017 14:59:22 -0400 Subject: [PATCH 15/26] Always request epoch range in AuditingRequest, fix Insert() bug --- protocol/auditlog.go | 51 ++++++++++++++++++++++----------------- protocol/auditlog_test.go | 46 +++++++++++++++++++++++++---------- protocol/message.go | 12 +++++---- 3 files changed, 69 insertions(+), 40 deletions(-) diff --git a/protocol/auditlog.go b/protocol/auditlog.go index 03a2aea..5bafbab 100644 --- a/protocol/auditlog.go +++ b/protocol/auditlog.go @@ -75,6 +75,12 @@ func (l *ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, return ErrAuditLog } + // make sure we have oldEpochs unless we're inserting right + // at the start of a directory's history + if oldSTRs == nil && latestSTR.Epoch > 0 { + return ErrMalformedDirectoryMessage + } + // create the new directory history h := newDirectoryHistory(signKey, latestSTR) @@ -82,6 +88,9 @@ func (l *ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, endEp := latestSTR.Epoch // add each old STR into the history + // This loop automatically catches if oldSTRs is malformed + // (i.e. oldSTRs starts at epoch 0 and + // len(oldSTRs) != latestSTR.Epoch-1) for ep := startEp; ep < endEp; ep++ { str := oldSTRs[ep] if str == nil { @@ -90,6 +99,9 @@ func (l *ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, h.snapshots[ep] = str } + // don't forget to add the latest STR + h.snapshots[endEp] = latestSTR + l.histories[addr] = h // FIXME: verify the consistency of each new STR @@ -123,23 +135,21 @@ func (l *ConiksAuditLog) Update(addr string, newSTR *DirSTR) error { return nil } -// GetObservedSTRs gets the observed STR for the CONIKS directory -// address for a directory history entry indicated in the -// AuditingRequest req received from a CONIKS client, -// and returns a tuple of the form (response, error). -// The response (which also includes the error code) is supposed to -// be sent back to the client. The returned error is used by the auditor +// GetObservedSTRs gets a range of observed STRs for the CONIKS directory +// address indicated in the AuditingRequest req received from a +// CONIKS client, and returns a tuple of the form (response, error). +// The response (which also includes the error code) is sent back to +// the client. The returned error is used by the auditor // for logging purposes. // -// A request without a directory address or with an epoch greater than -// the latest observed epoch of this directory is considered malformed, -// and causes GetObservedSTRs() to return a +// A request without a directory address, with a StartEpoch or EndEpoch +// greater than the latest observed epoch of this directory, or with +// at StartEpoch > EndEpoch is considered +// malformed and causes GetObservedSTRs() to return a // message.NewErrorResponse(ErrMalformedClientMessage) tuple. // GetObservedSTRs() returns a message.NewSTRHistoryRange(strs) tuple. -// strs is a list of STRs for the epoch range [ep, -// l.histories[req.DirectoryAddr].latestSTR.Epoch], where ep is the epoch for -// which the client has requested the observed STR; i.e. if ep == the latest epoch, -// the list returned is of length 1. +// strs is a list of STRs for the epoch range [StartEpoch, EndEpoch]; +// if StartEpoch == EndEpoch, the list returned is of length 1. // If the auditor doesn't have any history entries for the requested CONIKS // directory, GetObservedSTRs() returns a // message.NewErrorResponse(ReqUnknownDirectory) tuple. @@ -147,7 +157,7 @@ func (l *ConiksAuditLog) GetObservedSTRs(req *AuditingRequest) (*Response, ErrorCode) { // make sure the request is well-formed - if len(req.DirectoryAddr) <= 0 { + if len(req.DirectoryAddr) <= 0 || req.StartEpoch > req.EndEpoch { return NewErrorResponse(ErrMalformedClientMessage), ErrMalformedClientMessage } @@ -158,23 +168,20 @@ func (l *ConiksAuditLog) GetObservedSTRs(req *AuditingRequest) (*Response, return NewErrorResponse(ReqUnknownDirectory), ReqUnknownDirectory } - // also make sure the epoch is well-formed - if req.Epoch > h.latestSTR.Epoch { + // also make sure the epoch range is well-formed + if req.StartEpoch > h.latestSTR.Epoch || req.EndEpoch > h.latestSTR.Epoch { return NewErrorResponse(ErrMalformedClientMessage), ErrMalformedClientMessage } var strs []*DirSTR - startEp := req.Epoch - endEp := h.latestSTR.Epoch - - for ep := startEp; ep < endEp; ep++ { + for ep := req.StartEpoch; ep < req.EndEpoch; ep++ { str := h.snapshots[ep] strs = append(strs, str) } - // don't forget to append the latest STR - strs = append(strs, h.latestSTR) + // don't forget to append the STR for EndEpoch + strs = append(strs, h.snapshots[req.EndEpoch]) return NewSTRHistoryRange(strs) } diff --git a/protocol/auditlog_test.go b/protocol/auditlog_test.go index 7bd9439..f24f0c3 100644 --- a/protocol/auditlog_test.go +++ b/protocol/auditlog_test.go @@ -98,7 +98,8 @@ func TestGetLatestObservedSTR(t *testing.T) { res, err := aud.GetObservedSTRs(&AuditingRequest{ DirectoryAddr: "test-server", - Epoch: uint64(d.LatestSTR().Epoch)}) + StartEpoch: uint64(d.LatestSTR().Epoch), + EndEpoch: uint64(d.LatestSTR().Epoch)}) if err != ReqSuccess { t.Fatal("Unable to get latest observed STR") } @@ -132,7 +133,8 @@ func TestGetObservedSTRInEpoch(t *testing.T) { res, err := aud.GetObservedSTRs(&AuditingRequest{ DirectoryAddr: "test-server", - Epoch: uint64(6)}) + StartEpoch: uint64(6), + EndEpoch: uint64(8)}) if err != ReqSuccess { t.Fatal("Unable to get latest range of STRs") @@ -142,10 +144,10 @@ func TestGetObservedSTRInEpoch(t *testing.T) { if len(obs.STR) == 0 { t.Fatal("Expect returned STR to be not nil") } - if len(obs.STR) != 5 { - t.Fatal("Expect 5 returned STRs") + if len(obs.STR) != 3 { + t.Fatal("Expect 3 returned STRs") } - if obs.STR[0].Epoch != 6 || obs.STR[4].Epoch != d.LatestSTR().Epoch { + if obs.STR[0].Epoch != 6 || obs.STR[2].Epoch != 8 { t.Fatal("Unexpected epoch for returned STRs") } } @@ -170,14 +172,16 @@ func TestGetObservedSTRUnknown(t *testing.T) { _, err = aud.GetObservedSTRs(&AuditingRequest{ DirectoryAddr: "unknown", - Epoch: uint64(d.LatestSTR().Epoch)}) + StartEpoch: uint64(0), + EndEpoch: uint64(d.LatestSTR().Epoch)}) if err != ReqUnknownDirectory { t.Fatal("Expect ReqUnknownDirectory for latest STR") } _, err = aud.GetObservedSTRs(&AuditingRequest{ DirectoryAddr: "unknown", - Epoch: uint64(6)}) + StartEpoch: uint64(6), + EndEpoch: uint64(8)}) if err != ReqUnknownDirectory { t.Fatal("Expect ReqUnknownDirectory for older STR") } @@ -204,24 +208,40 @@ func TestGetObservedSTRMalformed(t *testing.T) { _, err = aud.GetObservedSTRs(&AuditingRequest{ DirectoryAddr: "", - Epoch: uint64(d.LatestSTR().Epoch)}) + StartEpoch: uint64(0), + EndEpoch: uint64(d.LatestSTR().Epoch)}) if err != ErrMalformedClientMessage { t.Fatal("Expect ErrMalFormedClientMessage for latest STR") } _, err = aud.GetObservedSTRs(&AuditingRequest{ DirectoryAddr: "", - Epoch: uint64(6)}) + StartEpoch: uint64(4), + EndEpoch: uint64(6)}) if err != ErrMalformedClientMessage { t.Fatal("Expect ErrMalformedClientMessage for older STR") } // also test the epoch range _, err = aud.GetObservedSTRs(&AuditingRequest{ - DirectoryAddr: "", - Epoch: uint64(20)}) + DirectoryAddr: "test-server", + StartEpoch: uint64(6), + EndEpoch: uint64(4)}) if err != ErrMalformedClientMessage { - t.Fatal("Expect ErrMalformedClientMessage for older STR") + t.Fatal("Expect ErrMalformedClientMessage for bad end epoch") + } + _, err = aud.GetObservedSTRs(&AuditingRequest{ + DirectoryAddr: "test-server", + StartEpoch: uint64(11), + EndEpoch: uint64(11)}) + if err != ErrMalformedClientMessage { + t.Fatal("Expect ErrMalformedClientMessage for bad start epoch") + } + _, err = aud.GetObservedSTRs(&AuditingRequest{ + DirectoryAddr: "test-server", + StartEpoch: uint64(6), + EndEpoch: uint64(11)}) + if err != ErrMalformedClientMessage { + t.Fatal("Expect ErrMalformedClientMessage for out-of-bounds epoch range") } - } diff --git a/protocol/message.go b/protocol/message.go index e2217da..1b5310f 100644 --- a/protocol/message.go +++ b/protocol/message.go @@ -92,15 +92,17 @@ type MonitoringRequest struct { } // An AuditingRequest is a message with a CONIKS key directory's address -// as a string and an epoch as a uint64 that a CONIKS client sends to -// a CONIKS auditor to request the given directory's STR at the given -// epoch. +// as a string, and a StartEpoch and an EndEpoch as uint64's that a CONIKS +// client sends to a CONIKS auditor to request the given directory's +// STRs for the given epoch range. To obtain a single STR, the client +// must set StartEpoch = EndEpoch in the request. // // The response to a successful request is an STRHistoryRange with -// a list of STRs covering the epoch range [Epoch, d.LatestSTR().Epoch]. +// a list of STRs covering the epoch range [StartEpoch, EndEpoch]. type AuditingRequest struct { DirectoryAddr string - Epoch uint64 + StartEpoch uint64 + EndEpoch uint64 } // A Response message indicates the result of a CONIKS client request From 9843f4aae6e81f1aef044bacbdc9d27cdc269a56 Mon Sep 17 00:00:00 2001 From: Marcela M Date: Mon, 3 Jul 2017 15:56:12 -0400 Subject: [PATCH 16/26] Index audit log by hash of directory's initial STR --- protocol/auditlog.go | 84 ++++++++++++++++++++++++--------------- protocol/auditlog_test.go | 76 +++++++++++++++-------------------- protocol/message.go | 11 +++-- 3 files changed, 92 insertions(+), 79 deletions(-) diff --git a/protocol/auditlog.go b/protocol/auditlog.go index 5bafbab..d1d8ba1 100644 --- a/protocol/auditlog.go +++ b/protocol/auditlog.go @@ -6,26 +6,44 @@ package protocol import ( + "github.com/coniks-sys/coniks-go/crypto" "github.com/coniks-sys/coniks-go/crypto/sign" ) type directoryHistory struct { + dirName string signKey sign.PublicKey snapshots map[uint64]*DirSTR latestSTR *DirSTR } // A ConiksAuditLog maintains the histories -// of all CONIKS directories known to a CONIKS auditor. -// Each history includes the directory's public signing key -// enabling the auditor to verify the corresponding signed -// tree roots. +// of all CONIKS directories known to a CONIKS auditor, +// indexing the histories by the hash of a directory's initial +// STR. +// Each history includes the directory's domain name as a string, its +// public signing key enabling the auditor to verify the corresponding +// signed tree roots, and a list with all observed snapshots in +// chronological order. type ConiksAuditLog struct { - histories map[string]*directoryHistory + histories map[[crypto.HashSizeByte]byte]*directoryHistory } -func newDirectoryHistory(signKey sign.PublicKey, str *DirSTR) *directoryHistory { +// computeInitSTRHash is a wrapper for the digest function; +// returns nil if the STR isn't an initial STR (i.e. str.Epoch != 0) +func computeInitSTRHash(initSTR *DirSTR) [crypto.HashSizeByte]byte { + var initSTRHash [crypto.HashSizeByte]byte + + if initSTR.Epoch == 0 { + // ugh HACK: need to call copy to convert slice into the array + copy(initSTRHash[:], crypto.Digest(initSTR.Serialize())) + } + return initSTRHash +} + +func newDirectoryHistory(dirName string, signKey sign.PublicKey, str *DirSTR) *directoryHistory { h := new(directoryHistory) + h.dirName = dirName h.signKey = signKey h.snapshots = make(map[uint64]*DirSTR) h.latestSTR = str @@ -37,16 +55,17 @@ func newDirectoryHistory(signKey sign.PublicKey, str *DirSTR) *directoryHistory // the first time it observes an STR for that directory. func NewAuditLog() *ConiksAuditLog { l := new(ConiksAuditLog) - l.histories = make(map[string]*directoryHistory) + l.histories = make(map[[crypto.HashSizeByte]byte]*directoryHistory) return l } // IsKnownDirectory checks to see if an entry for the directory -// address addr exists in the audit log l. IsKnownDirectory() does not +// (indexed by the hash of its initial STR dirInitHash) exists +// in the audit log l. IsKnownDirectory() does not // validate the entries themselves. It returns true if an entry exists, // and false otherwise. -func (l *ConiksAuditLog) IsKnownDirectory(addr string) bool { - h := l.histories[addr] +func (l *ConiksAuditLog) IsKnownDirectory(dirInitHash [crypto.HashSizeByte]byte) bool { + h := l.histories[dirInitHash] if h != nil { return true } @@ -70,19 +89,26 @@ func (l *ConiksAuditLog) IsKnownDirectory(addr string) bool { func (l *ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, oldSTRs map[uint64]*DirSTR, latestSTR *DirSTR) error { - // error if we want to create a new entry for an addr we already know - if l.IsKnownDirectory(addr) { - return ErrAuditLog - } - // make sure we have oldEpochs unless we're inserting right // at the start of a directory's history if oldSTRs == nil && latestSTR.Epoch > 0 { return ErrMalformedDirectoryMessage } + // compute the hash of the initial STR + dirInitHash := computeInitSTRHash(latestSTR) + if oldSTRs != nil { + dirInitHash = computeInitSTRHash(oldSTRs[0]) + } + + // error if we want to create a new entry for a directory + // we already know + if l.IsKnownDirectory(dirInitHash) { + return ErrAuditLog + } + // create the new directory history - h := newDirectoryHistory(signKey, latestSTR) + h := newDirectoryHistory(addr, signKey, latestSTR) startEp := uint64(0) endEp := latestSTR.Epoch @@ -101,8 +127,7 @@ func (l *ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, // don't forget to add the latest STR h.snapshots[endEp] = latestSTR - - l.histories[addr] = h + l.histories[dirInitHash] = h // FIXME: verify the consistency of each new STR return nil @@ -116,14 +141,14 @@ func (l *ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, // addr prior to its first call and thereby expects that an entry for addr // exists in the audit log l. // FIXME: pass Response message as param -func (l *ConiksAuditLog) Update(addr string, newSTR *DirSTR) error { +func (l *ConiksAuditLog) Update(dirInitHash [crypto.HashSizeByte]byte, newSTR *DirSTR) error { // error if we want to update the entry for an addr we don't know - if !l.IsKnownDirectory(addr) { + if !l.IsKnownDirectory(dirInitHash) { return ErrAuditLog } - h := l.histories[addr] + h := l.histories[dirInitHash] if err := verifySTRConsistency(h.signKey, h.latestSTR, newSTR); err != nil { return err @@ -156,20 +181,15 @@ func (l *ConiksAuditLog) Update(addr string, newSTR *DirSTR) error { func (l *ConiksAuditLog) GetObservedSTRs(req *AuditingRequest) (*Response, ErrorCode) { - // make sure the request is well-formed - if len(req.DirectoryAddr) <= 0 || req.StartEpoch > req.EndEpoch { - return NewErrorResponse(ErrMalformedClientMessage), - ErrMalformedClientMessage - } - - h := l.histories[req.DirectoryAddr] - - if h == nil { + // make sure we have a history for the requested directory in the log + if !l.IsKnownDirectory(req.DirInitSTRHash) { return NewErrorResponse(ReqUnknownDirectory), ReqUnknownDirectory } - // also make sure the epoch range is well-formed - if req.StartEpoch > h.latestSTR.Epoch || req.EndEpoch > h.latestSTR.Epoch { + h := l.histories[req.DirInitSTRHash] + + // make sure the request is well-formed + if req.EndEpoch > h.latestSTR.Epoch || req.StartEpoch > req.EndEpoch { return NewErrorResponse(ErrMalformedClientMessage), ErrMalformedClientMessage } diff --git a/protocol/auditlog_test.go b/protocol/auditlog_test.go index f24f0c3..4b3eb13 100644 --- a/protocol/auditlog_test.go +++ b/protocol/auditlog_test.go @@ -1,6 +1,7 @@ package protocol import ( + "github.com/coniks-sys/coniks-go/crypto" "testing" ) @@ -26,8 +27,9 @@ func TestUpdateHistory(t *testing.T) { } // update the directory so we can update the audit log + dirInitHash := computeInitSTRHash(d.LatestSTR()) d.Update() - err = aud.Update("test-server", d.LatestSTR()) + err = aud.Update(dirInitHash, d.LatestSTR()) if err != nil { t.Fatal("Error updating the server history") @@ -81,7 +83,8 @@ func TestUpdateUnknownHistory(t *testing.T) { // let's make sure that we can't re-insert a new server // history into our log - err = aud.Update("unknown", d.LatestSTR()) + var unknown [crypto.HashSizeByte]byte + err = aud.Update(unknown, d.LatestSTR()) if err != ErrAuditLog { t.Fatal("Expected an ErrAuditLog when updating an unknown server history") } @@ -96,10 +99,13 @@ func TestGetLatestObservedSTR(t *testing.T) { t.Fatal("Error inserting new server history") } + // compute the hash of the initial STR for later lookups + dirInitHash := computeInitSTRHash(d.LatestSTR()) + res, err := aud.GetObservedSTRs(&AuditingRequest{ - DirectoryAddr: "test-server", - StartEpoch: uint64(d.LatestSTR().Epoch), - EndEpoch: uint64(d.LatestSTR().Epoch)}) + DirInitSTRHash: dirInitHash, + StartEpoch: uint64(d.LatestSTR().Epoch), + EndEpoch: uint64(d.LatestSTR().Epoch)}) if err != ReqSuccess { t.Fatal("Unable to get latest observed STR") } @@ -125,6 +131,9 @@ func TestGetObservedSTRInEpoch(t *testing.T) { d.Update() } + // compute the hash of the initial STR for later lookups + dirInitHash := computeInitSTRHash(priorSTRs[0]) + // now insert into the log err := aud.Insert("test-server", pk, priorSTRs, d.LatestSTR()) if err != nil { @@ -132,9 +141,9 @@ func TestGetObservedSTRInEpoch(t *testing.T) { } res, err := aud.GetObservedSTRs(&AuditingRequest{ - DirectoryAddr: "test-server", - StartEpoch: uint64(6), - EndEpoch: uint64(8)}) + DirInitSTRHash: dirInitHash, + StartEpoch: uint64(6), + EndEpoch: uint64(8)}) if err != ReqSuccess { t.Fatal("Unable to get latest range of STRs") @@ -170,18 +179,19 @@ func TestGetObservedSTRUnknown(t *testing.T) { t.Fatal("Error inserting new server history with prior STRs") } + var unknown [crypto.HashSizeByte]byte _, err = aud.GetObservedSTRs(&AuditingRequest{ - DirectoryAddr: "unknown", - StartEpoch: uint64(0), - EndEpoch: uint64(d.LatestSTR().Epoch)}) + DirInitSTRHash: unknown, + StartEpoch: uint64(d.LatestSTR().Epoch), + EndEpoch: uint64(d.LatestSTR().Epoch)}) if err != ReqUnknownDirectory { t.Fatal("Expect ReqUnknownDirectory for latest STR") } _, err = aud.GetObservedSTRs(&AuditingRequest{ - DirectoryAddr: "unknown", - StartEpoch: uint64(6), - EndEpoch: uint64(8)}) + DirInitSTRHash: unknown, + StartEpoch: uint64(6), + EndEpoch: uint64(8)}) if err != ReqUnknownDirectory { t.Fatal("Expect ReqUnknownDirectory for older STR") } @@ -200,47 +210,27 @@ func TestGetObservedSTRMalformed(t *testing.T) { d.Update() } + // compute the hash of the initial STR for later lookups + dirInitHash := computeInitSTRHash(priorSTRs[0]) + // now insert into the log err := aud.Insert("test-server", pk, priorSTRs, d.LatestSTR()) if err != nil { t.Fatal("Error inserting new server history with prior STRs") } - _, err = aud.GetObservedSTRs(&AuditingRequest{ - DirectoryAddr: "", - StartEpoch: uint64(0), - EndEpoch: uint64(d.LatestSTR().Epoch)}) - if err != ErrMalformedClientMessage { - t.Fatal("Expect ErrMalFormedClientMessage for latest STR") - } - - _, err = aud.GetObservedSTRs(&AuditingRequest{ - DirectoryAddr: "", - StartEpoch: uint64(4), - EndEpoch: uint64(6)}) - if err != ErrMalformedClientMessage { - t.Fatal("Expect ErrMalformedClientMessage for older STR") - } - // also test the epoch range _, err = aud.GetObservedSTRs(&AuditingRequest{ - DirectoryAddr: "test-server", - StartEpoch: uint64(6), - EndEpoch: uint64(4)}) + DirInitSTRHash: dirInitHash, + StartEpoch: uint64(6), + EndEpoch: uint64(4)}) if err != ErrMalformedClientMessage { t.Fatal("Expect ErrMalformedClientMessage for bad end epoch") } _, err = aud.GetObservedSTRs(&AuditingRequest{ - DirectoryAddr: "test-server", - StartEpoch: uint64(11), - EndEpoch: uint64(11)}) - if err != ErrMalformedClientMessage { - t.Fatal("Expect ErrMalformedClientMessage for bad start epoch") - } - _, err = aud.GetObservedSTRs(&AuditingRequest{ - DirectoryAddr: "test-server", - StartEpoch: uint64(6), - EndEpoch: uint64(11)}) + DirInitSTRHash: dirInitHash, + StartEpoch: uint64(6), + EndEpoch: uint64(11)}) if err != ErrMalformedClientMessage { t.Fatal("Expect ErrMalformedClientMessage for out-of-bounds epoch range") } diff --git a/protocol/message.go b/protocol/message.go index 1b5310f..bd3d58c 100644 --- a/protocol/message.go +++ b/protocol/message.go @@ -4,7 +4,10 @@ package protocol -import m "github.com/coniks-sys/coniks-go/merkletree" +import ( + "github.com/coniks-sys/coniks-go/crypto" + m "github.com/coniks-sys/coniks-go/merkletree" +) // The types of requests CONIKS clients send during the CONIKS protocols. const ( @@ -100,9 +103,9 @@ type MonitoringRequest struct { // The response to a successful request is an STRHistoryRange with // a list of STRs covering the epoch range [StartEpoch, EndEpoch]. type AuditingRequest struct { - DirectoryAddr string - StartEpoch uint64 - EndEpoch uint64 + DirInitSTRHash [crypto.HashSizeByte]byte + StartEpoch uint64 + EndEpoch uint64 } // A Response message indicates the result of a CONIKS client request From 9f212b16c142cfda6a6151b71323860443c6d441 Mon Sep 17 00:00:00 2001 From: Marcela M Date: Mon, 3 Jul 2017 19:07:39 -0400 Subject: [PATCH 17/26] Insert latest STR into snapshot map right away --- protocol/auditlog.go | 86 +++++++++--------- protocol/auditlog_test.go | 185 +++++++++++++++----------------------- protocol/testutil.go | 26 ++++++ 3 files changed, 142 insertions(+), 155 deletions(-) diff --git a/protocol/auditlog.go b/protocol/auditlog.go index d1d8ba1..8c8b3c7 100644 --- a/protocol/auditlog.go +++ b/protocol/auditlog.go @@ -25,9 +25,7 @@ type directoryHistory struct { // public signing key enabling the auditor to verify the corresponding // signed tree roots, and a list with all observed snapshots in // chronological order. -type ConiksAuditLog struct { - histories map[[crypto.HashSizeByte]byte]*directoryHistory -} +type ConiksAuditLog map[[crypto.HashSizeByte]byte]*directoryHistory // computeInitSTRHash is a wrapper for the digest function; // returns nil if the STR isn't an initial STR (i.e. str.Epoch != 0) @@ -35,27 +33,27 @@ func computeInitSTRHash(initSTR *DirSTR) [crypto.HashSizeByte]byte { var initSTRHash [crypto.HashSizeByte]byte if initSTR.Epoch == 0 { - // ugh HACK: need to call copy to convert slice into the array + // ugh HACK: need to call copy to convert slice + // into the array copy(initSTRHash[:], crypto.Digest(initSTR.Serialize())) } return initSTRHash } -func newDirectoryHistory(dirName string, signKey sign.PublicKey, str *DirSTR) *directoryHistory { +func newDirectoryHistory(dirName string, signKey sign.PublicKey) *directoryHistory { h := new(directoryHistory) h.dirName = dirName h.signKey = signKey h.snapshots = make(map[uint64]*DirSTR) - h.latestSTR = str + h.latestSTR = nil return h } // NewAuditLog 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 { - l := new(ConiksAuditLog) - l.histories = make(map[[crypto.HashSizeByte]byte]*directoryHistory) +func NewAuditLog() ConiksAuditLog { + l := make(map[[crypto.HashSizeByte]byte]*directoryHistory) return l } @@ -64,20 +62,26 @@ func NewAuditLog() *ConiksAuditLog { // in the audit log l. IsKnownDirectory() does not // validate the entries themselves. It returns true if an entry exists, // and false otherwise. -func (l *ConiksAuditLog) IsKnownDirectory(dirInitHash [crypto.HashSizeByte]byte) bool { - h := l.histories[dirInitHash] +func (l ConiksAuditLog) IsKnownDirectory(dirInitHash [crypto.HashSizeByte]byte) bool { + h := l[dirInitHash] if h != nil { return true } return false } +// updateLatestSTR inserts a new STR into a directory history; +// assumes the STR has been validated by the caller +func (h *directoryHistory) updateLatestSTR(newLatest *DirSTR) { + h.snapshots[newLatest.Epoch] = newLatest + h.latestSTR = newLatest +} + // Insert creates a new directory history for the key directory addr // and inserts it into the audit log l. // The directory history is initialized with the key directory's -// signing key signKey, a list of STRs representing the -// directory's prior history oldSTRs, and the directory's latest STR -// latestSTR. +// signing key signKey, and a list of STRs representing the +// directory's STR history so far (as a map of epochs to STRs). // Insert() returns an ErrAuditLog if the auditor attempts to create // a new history for a known directory, an ErrMalformedDirectoryMessage // if oldSTRs is malformed, and nil otherwise. @@ -86,20 +90,16 @@ func (l *ConiksAuditLog) IsKnownDirectory(dirInitHash [crypto.HashSizeByte]byte) // FIXME: pass Response message as param // masomel: will probably want to write a more generic function // for "catching up" on a history in case an auditor misses epochs -func (l *ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, - oldSTRs map[uint64]*DirSTR, latestSTR *DirSTR) error { +func (l ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, + hist map[uint64]*DirSTR) error { - // make sure we have oldEpochs unless we're inserting right - // at the start of a directory's history - if oldSTRs == nil && latestSTR.Epoch > 0 { + // make sure we're getting an initial STR at the very least + if len(hist) < 1 && hist[0].Epoch != 0 { return ErrMalformedDirectoryMessage } // compute the hash of the initial STR - dirInitHash := computeInitSTRHash(latestSTR) - if oldSTRs != nil { - dirInitHash = computeInitSTRHash(oldSTRs[0]) - } + dirInitHash := computeInitSTRHash(hist[0]) // error if we want to create a new entry for a directory // we already know @@ -108,28 +108,30 @@ func (l *ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, } // create the new directory history - h := newDirectoryHistory(addr, signKey, latestSTR) + h := newDirectoryHistory(addr, signKey) startEp := uint64(0) - endEp := latestSTR.Epoch + endEp := uint64(len(hist)) - // add each old STR into the history - // This loop automatically catches if oldSTRs is malformed - // (i.e. oldSTRs starts at epoch 0 and - // len(oldSTRs) != latestSTR.Epoch-1) + // add each STR into the history + // This loop automatically catches if hist is malformed + // (i.e. hist is missing and epoch) + // FIXME: verify the consistency of each new STR before inserting + // into the audit log for ep := startEp; ep < endEp; ep++ { - str := oldSTRs[ep] + str := hist[ep] if str == nil { return ErrMalformedDirectoryMessage } h.snapshots[ep] = str } - // don't forget to add the latest STR - h.snapshots[endEp] = latestSTR - l.histories[dirInitHash] = h + // Make sure to update the latestSTR + // in this particular call, the latestSTR has already been + // inserted into the snapshots map in the loop above + h.updateLatestSTR(hist[endEp-1]) + l[dirInitHash] = h - // FIXME: verify the consistency of each new STR return nil } @@ -141,22 +143,21 @@ func (l *ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, // addr prior to its first call and thereby expects that an entry for addr // exists in the audit log l. // FIXME: pass Response message as param -func (l *ConiksAuditLog) Update(dirInitHash [crypto.HashSizeByte]byte, newSTR *DirSTR) error { +func (l ConiksAuditLog) Update(dirInitHash [crypto.HashSizeByte]byte, newSTR *DirSTR) error { // error if we want to update the entry for an addr we don't know if !l.IsKnownDirectory(dirInitHash) { return ErrAuditLog } - h := l.histories[dirInitHash] + h := l[dirInitHash] if err := verifySTRConsistency(h.signKey, h.latestSTR, newSTR); err != nil { return err } // update the latest STR - h.snapshots[h.latestSTR.Epoch] = h.latestSTR - h.latestSTR = newSTR + h.updateLatestSTR(newSTR) return nil } @@ -178,7 +179,7 @@ func (l *ConiksAuditLog) Update(dirInitHash [crypto.HashSizeByte]byte, newSTR *D // 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, +func (l ConiksAuditLog) GetObservedSTRs(req *AuditingRequest) (*Response, ErrorCode) { // make sure we have a history for the requested directory in the log @@ -186,7 +187,7 @@ func (l *ConiksAuditLog) GetObservedSTRs(req *AuditingRequest) (*Response, return NewErrorResponse(ReqUnknownDirectory), ReqUnknownDirectory } - h := l.histories[req.DirInitSTRHash] + h := l[req.DirInitSTRHash] // make sure the request is well-formed if req.EndEpoch > h.latestSTR.Epoch || req.StartEpoch > req.EndEpoch { @@ -195,13 +196,10 @@ func (l *ConiksAuditLog) GetObservedSTRs(req *AuditingRequest) (*Response, } var strs []*DirSTR - for ep := req.StartEpoch; ep < req.EndEpoch; ep++ { + for ep := req.StartEpoch; ep <= req.EndEpoch; ep++ { str := h.snapshots[ep] strs = append(strs, str) } - // don't forget to append the STR for EndEpoch - strs = append(strs, h.snapshots[req.EndEpoch]) - return NewSTRHistoryRange(strs) } diff --git a/protocol/auditlog_test.go b/protocol/auditlog_test.go index 4b3eb13..a59774b 100644 --- a/protocol/auditlog_test.go +++ b/protocol/auditlog_test.go @@ -6,30 +6,18 @@ import ( ) func TestInsertEmptyHistory(t *testing.T) { - // let's just create basic test directory and an empty audit log - d, pk := NewTestDirectory(t, true) - aud := NewAuditLog() - - err := aud.Insert("test-server", pk, nil, d.LatestSTR()) - if err != nil { - t.Fatal("Error inserting new server history") - } + // create basic test directory and audit log with 1 STR + _, _, _ = NewTestAuditLog(t, 0) } func TestUpdateHistory(t *testing.T) { - // let's just create basic test directory and an empty audit log - d, pk := NewTestDirectory(t, true) - aud := NewAuditLog() - - err := aud.Insert("test-server", pk, nil, d.LatestSTR()) - if err != nil { - t.Fatal("Error inserting new server history") - } + // create basic test directory and audit log with 1 STR + d, aud, hist := NewTestAuditLog(t, 0) // update the directory so we can update the audit log - dirInitHash := computeInitSTRHash(d.LatestSTR()) + dirInitHash := computeInitSTRHash(hist[0]) d.Update() - err = aud.Update(dirInitHash, d.LatestSTR()) + err := aud.Update(dirInitHash, d.LatestSTR()) if err != nil { t.Fatal("Error updating the server history") @@ -37,70 +25,59 @@ func TestUpdateHistory(t *testing.T) { } func TestInsertPriorHistory(t *testing.T) { - // let's just create basic test directory and an empty audit log - d, pk := NewTestDirectory(t, true) - aud := NewAuditLog() - - // create 10 epochs - priorSTRs := make(map[uint64]*DirSTR) - for i := 0; i < 10; i++ { - priorSTRs[d.LatestSTR().Epoch] = d.LatestSTR() - d.Update() - } - - // now insert - err := aud.Insert("test-server", pk, priorSTRs, d.LatestSTR()) - if err != nil { - t.Fatal("Error inserting new server history with prior STRs") - } + // create basic test directory and audit log with 11 STRs + _, _, _ = NewTestAuditLog(t, 10) } func TestInsertExistingHistory(t *testing.T) { - // let's just create basic test directory and an empty audit log - d, pk := NewTestDirectory(t, true) - aud := NewAuditLog() - err := aud.Insert("test-server", pk, nil, d.LatestSTR()) - if err != nil { - t.Fatal("Error inserting new server history") - } + // create basic test directory and audit log with 1 STR + _, aud, hist := NewTestAuditLog(t, 0) // let's make sure that we can't re-insert a new server // history into our log - err = aud.Insert("test-server", pk, nil, d.LatestSTR()) + err := aud.Insert("test-server", nil, hist) if err != ErrAuditLog { t.Fatal("Expected an ErrAuditLog when inserting an existing server history") } } func TestUpdateUnknownHistory(t *testing.T) { - // let's just create basic test directory and an empty audit log - d, pk := NewTestDirectory(t, true) - aud := NewAuditLog() - err := aud.Insert("test-server", pk, nil, d.LatestSTR()) - if err != nil { - t.Fatal("Error inserting new server history") - } + // create basic test directory and audit log with 1 STR + d, aud, _ := NewTestAuditLog(t, 0) - // let's make sure that we can't re-insert a new server - // history into our log + // let's make sure that we can't update a history for an unknown + // directory in our log var unknown [crypto.HashSizeByte]byte - err = aud.Update(unknown, d.LatestSTR()) + err := aud.Update(unknown, d.LatestSTR()) if err != ErrAuditLog { t.Fatal("Expected an ErrAuditLog when updating an unknown server history") } } -func TestGetLatestObservedSTR(t *testing.T) { - // let's just create basic test directory and an empty audit log - d, pk := NewTestDirectory(t, true) - aud := NewAuditLog() - err := aud.Insert("test-server", pk, nil, d.LatestSTR()) - if err != nil { - t.Fatal("Error inserting new server history") +func TestUpdateBadNewSTR(t *testing.T) { + // create basic test directory and audit log with 11 STRs + d, aud, hist := NewTestAuditLog(t, 10) + + // compute the hash of the initial STR for later lookups + dirInitHash := computeInitSTRHash(hist[0]) + + // update the directory a few more times and then try + // to update + d.Update() + d.Update() + + err := aud.Update(dirInitHash, d.LatestSTR()) + if err != CheckBadSTR { + t.Fatal("Expected a CheckBadSTR when attempting update a server history with a bad STR") } +} + +func TestGetLatestObservedSTR(t *testing.T) { + // create basic test directory and audit log with 1 STR + d, aud, hist := NewTestAuditLog(t, 0) // compute the hash of the initial STR for later lookups - dirInitHash := computeInitSTRHash(d.LatestSTR()) + dirInitHash := computeInitSTRHash(hist[0]) res, err := aud.GetObservedSTRs(&AuditingRequest{ DirInitSTRHash: dirInitHash, @@ -111,34 +88,20 @@ func TestGetLatestObservedSTR(t *testing.T) { } obs := res.DirectoryResponse.(*STRHistoryRange) - if len(obs.STR) != 1 { + if len(obs.STR) == 0 { t.Fatal("Expect returned STR to be not nil") } if obs.STR[0].Epoch != d.LatestSTR().Epoch { - t.Fatal("Unexpected epoch for returned STR") + t.Fatal("Unexpected epoch for returned latest STR") } } func TestGetObservedSTRInEpoch(t *testing.T) { - // let's just create basic test directory and an empty audit log - d, pk := NewTestDirectory(t, true) - aud := NewAuditLog() - - // create 10 epochs - priorSTRs := make(map[uint64]*DirSTR) - for i := 0; i < 10; i++ { - priorSTRs[d.LatestSTR().Epoch] = d.LatestSTR() - d.Update() - } + // create basic test directory and audit log with 11 STRs + _, aud, hist := NewTestAuditLog(t, 10) // compute the hash of the initial STR for later lookups - dirInitHash := computeInitSTRHash(priorSTRs[0]) - - // now insert into the log - err := aud.Insert("test-server", pk, priorSTRs, d.LatestSTR()) - if err != nil { - t.Fatal("Error inserting new server history with prior STRs") - } + dirInitHash := computeInitSTRHash(hist[0]) res, err := aud.GetObservedSTRs(&AuditingRequest{ DirInitSTRHash: dirInitHash, @@ -161,26 +124,40 @@ func TestGetObservedSTRInEpoch(t *testing.T) { } } -func TestGetObservedSTRUnknown(t *testing.T) { - // let's just create basic test directory and an empty audit log - d, pk := NewTestDirectory(t, true) - aud := NewAuditLog() +func TestGetEntireObservedSTRHist(t *testing.T) { + // create basic test directory and audit log with 2 STRs + d, aud, hist := NewTestAuditLog(t, 1) - // create 10 epochs - priorSTRs := make(map[uint64]*DirSTR) - for i := 0; i < 10; i++ { - priorSTRs[d.LatestSTR().Epoch] = d.LatestSTR() - d.Update() + // compute the hash of the initial STR for later lookups + dirInitHash := computeInitSTRHash(hist[0]) + + res, err := aud.GetObservedSTRs(&AuditingRequest{ + DirInitSTRHash: dirInitHash, + StartEpoch: uint64(0), + EndEpoch: d.LatestSTR().Epoch}) + + if err != ReqSuccess { + t.Fatal("Unable to get latest range of STRs") } - // now insert into the log - err := aud.Insert("test-server", pk, priorSTRs, d.LatestSTR()) - if err != nil { - t.Fatal("Error inserting new server history with prior STRs") + obs := res.DirectoryResponse.(*STRHistoryRange) + if len(obs.STR) != 2 { + t.Fatal("Unexpected number of returned STRs") + } + if obs.STR[0].Epoch != 0 { + t.Fatal("Unexpected initial epoch for returned STR range") + } + if obs.STR[1].Epoch != d.LatestSTR().Epoch { + t.Fatal("Unexpected latest STR epoch for returned STR") } +} + +func TestGetObservedSTRUnknown(t *testing.T) { + // create basic test directory and audit log with 11 STRs + d, aud, _ := NewTestAuditLog(t, 10) var unknown [crypto.HashSizeByte]byte - _, err = aud.GetObservedSTRs(&AuditingRequest{ + _, err := aud.GetObservedSTRs(&AuditingRequest{ DirInitSTRHash: unknown, StartEpoch: uint64(d.LatestSTR().Epoch), EndEpoch: uint64(d.LatestSTR().Epoch)}) @@ -199,28 +176,14 @@ func TestGetObservedSTRUnknown(t *testing.T) { } func TestGetObservedSTRMalformed(t *testing.T) { - // let's just create basic test directory and an empty audit log - d, pk := NewTestDirectory(t, true) - aud := NewAuditLog() - - // create 10 epochs - priorSTRs := make(map[uint64]*DirSTR) - for i := 0; i < 10; i++ { - priorSTRs[d.LatestSTR().Epoch] = d.LatestSTR() - d.Update() - } + // create basic test directory and audit log with 11 STRs + _, aud, hist := NewTestAuditLog(t, 10) // compute the hash of the initial STR for later lookups - dirInitHash := computeInitSTRHash(priorSTRs[0]) - - // now insert into the log - err := aud.Insert("test-server", pk, priorSTRs, d.LatestSTR()) - if err != nil { - t.Fatal("Error inserting new server history with prior STRs") - } + dirInitHash := computeInitSTRHash(hist[0]) // also test the epoch range - _, err = aud.GetObservedSTRs(&AuditingRequest{ + _, err := aud.GetObservedSTRs(&AuditingRequest{ DirInitSTRHash: dirInitHash, StartEpoch: uint64(6), EndEpoch: uint64(4)}) diff --git a/protocol/testutil.go b/protocol/testutil.go index 4e464ba..ee2bbb4 100644 --- a/protocol/testutil.go +++ b/protocol/testutil.go @@ -28,3 +28,29 @@ func NewTestDirectory(t *testing.T, 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, map[uint64]*DirSTR) { + d, pk := NewTestDirectory(t, true) + aud := NewAuditLog() + + hist := make(map[uint64]*DirSTR) + for ep := 0; ep < numEpochs; ep++ { + hist[d.LatestSTR().Epoch] = d.LatestSTR() + d.Update() + } + // always include the actual latest STR + hist[d.LatestSTR().Epoch] = d.LatestSTR() + + err := aud.Insert("test-server", pk, hist) + if err != nil { + t.Fatal("Error inserting a new history with %d epochs", numEpochs) + } + + return d, aud, hist +} From fcebf89070432132456ac8b23f9fe09ae5c9d69c Mon Sep 17 00:00:00 2001 From: Marcela Melara Date: Mon, 3 Jul 2017 21:22:10 -0400 Subject: [PATCH 18/26] Fix go vet error --- protocol/testutil.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/testutil.go b/protocol/testutil.go index ee2bbb4..0f41e4f 100644 --- a/protocol/testutil.go +++ b/protocol/testutil.go @@ -49,7 +49,7 @@ func NewTestAuditLog(t *testing.T, numEpochs int) (*ConiksDirectory, ConiksAudit err := aud.Insert("test-server", pk, hist) if err != nil { - t.Fatal("Error inserting a new history with %d epochs", numEpochs) + t.Fatalf("Error inserting a new history with %d STRs", numEpochs+1) } return d, aud, hist From 7e540875d4ce60f00d18a8439baf83becb9fcf03 Mon Sep 17 00:00:00 2001 From: Marcela Melara Date: Mon, 3 Jul 2017 23:02:07 -0400 Subject: [PATCH 19/26] Change audit log index from byte array to string --- protocol/auditlog.go | 77 ++++++++++++++++++++++----------------- protocol/auditlog_test.go | 13 ++----- protocol/message.go | 20 +++++----- 3 files changed, 56 insertions(+), 54 deletions(-) diff --git a/protocol/auditlog.go b/protocol/auditlog.go index 8c8b3c7..fa7c17e 100644 --- a/protocol/auditlog.go +++ b/protocol/auditlog.go @@ -6,6 +6,8 @@ package protocol import ( + "encoding/hex" + "github.com/coniks-sys/coniks-go/crypto" "github.com/coniks-sys/coniks-go/crypto/sign" ) @@ -20,32 +22,36 @@ type directoryHistory struct { // A ConiksAuditLog maintains the histories // of all CONIKS directories known to a CONIKS auditor, // indexing the histories by the hash of a directory's initial -// STR. +// STR (specifically, the hash of the STR's signature as a string). // Each history includes the directory's domain name as a string, its // public signing key enabling the auditor to verify the corresponding -// signed tree roots, and a list with all observed snapshots in -// chronological order. -type ConiksAuditLog map[[crypto.HashSizeByte]byte]*directoryHistory +// signed tree roots, and a map with the snapshots for each observed +// epoch. +type ConiksAuditLog map[string]*directoryHistory // computeInitSTRHash is a wrapper for the digest function; -// returns nil if the STR isn't an initial STR (i.e. str.Epoch != 0) -func computeInitSTRHash(initSTR *DirSTR) [crypto.HashSizeByte]byte { - var initSTRHash [crypto.HashSizeByte]byte - - if initSTR.Epoch == 0 { - // ugh HACK: need to call copy to convert slice - // into the array - copy(initSTRHash[:], crypto.Digest(initSTR.Serialize())) +// returns empty string if the STR isn't an initial STR (i.e. str.Epoch != 0) +func computeInitSTRHash(initSTR *DirSTR) string { + if initSTR.Epoch != 0 { + return "" } - return initSTRHash + return hex.EncodeToString(crypto.Digest(initSTR.Signature)) } -func newDirectoryHistory(dirName string, signKey sign.PublicKey) *directoryHistory { +// updateLatestSTR inserts a new STR into a directory history; +// assumes the STR has been validated by the caller +func (h *directoryHistory) updateLatestSTR(newLatest *DirSTR) { + h.snapshots[newLatest.Epoch] = newLatest + h.latestSTR = newLatest +} + +// caller validates that initSTR is for epoch 0 +func newDirectoryHistory(dirName string, signKey sign.PublicKey, initSTR *DirSTR) *directoryHistory { h := new(directoryHistory) h.dirName = dirName h.signKey = signKey h.snapshots = make(map[uint64]*DirSTR) - h.latestSTR = nil + h.updateLatestSTR(initSTR) return h } @@ -53,7 +59,7 @@ func newDirectoryHistory(dirName string, signKey sign.PublicKey) *directoryHisto // log; the auditor will add an entry for each CONIKS directory // the first time it observes an STR for that directory. func NewAuditLog() ConiksAuditLog { - l := make(map[[crypto.HashSizeByte]byte]*directoryHistory) + l := make(map[string]*directoryHistory) return l } @@ -62,7 +68,7 @@ func NewAuditLog() ConiksAuditLog { // in the audit log l. IsKnownDirectory() does not // validate the entries themselves. It returns true if an entry exists, // and false otherwise. -func (l ConiksAuditLog) IsKnownDirectory(dirInitHash [crypto.HashSizeByte]byte) bool { +func (l ConiksAuditLog) IsKnownDirectory(dirInitHash string) bool { h := l[dirInitHash] if h != nil { return true @@ -70,21 +76,16 @@ func (l ConiksAuditLog) IsKnownDirectory(dirInitHash [crypto.HashSizeByte]byte) return false } -// updateLatestSTR inserts a new STR into a directory history; -// assumes the STR has been validated by the caller -func (h *directoryHistory) updateLatestSTR(newLatest *DirSTR) { - h.snapshots[newLatest.Epoch] = newLatest - h.latestSTR = newLatest -} - -// Insert creates a new directory history for the key directory addr -// and inserts it into the audit log l. +// Insert creates a new directory history for the key directory addr, +// verifies the consistency of the STR history so far, and inserts it +// into the audit log l if the checks pass. // The directory history is initialized with the key directory's // signing key signKey, and a list of STRs representing the // directory's STR history so far (as a map of epochs to STRs). // Insert() returns an ErrAuditLog if the auditor attempts to create // a new history for a known directory, an ErrMalformedDirectoryMessage -// if oldSTRs is malformed, and nil otherwise. +// if oldSTRs is malformed, a CheckBadSignature or CheckBadSTR if there +// is an inconsistency in the history given in hist, and nil otherwise. // Insert() only creates the initial entry in the log for addr. Use Update() // to insert newly observed STRs for addr in subsequent epochs. // FIXME: pass Response message as param @@ -108,21 +109,29 @@ func (l ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, } // create the new directory history - h := newDirectoryHistory(addr, signKey) + h := newDirectoryHistory(addr, signKey, hist[0]) - startEp := uint64(0) + // add each STR into the history + // start at 1 since we've inserted the initial STR above + startEp := uint64(1) endEp := uint64(len(hist)) - // add each STR into the history // This loop automatically catches if hist is malformed - // (i.e. hist is missing and epoch) - // FIXME: verify the consistency of each new STR before inserting - // into the audit log + // (i.e. hist is missing an epoch between 0 and the latest given) for ep := startEp; ep < endEp; ep++ { str := hist[ep] if str == nil { return ErrMalformedDirectoryMessage } + + // verify the consistency of each new STR before inserting + // into the audit log + err := verifySTRConsistency(signKey, h.snapshots[ep-1], str) + + if err != nil { + return err + } + h.snapshots[ep] = str } @@ -143,7 +152,7 @@ func (l ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, // addr prior to its first call and thereby expects that an entry for addr // exists in the audit log l. // FIXME: pass Response message as param -func (l ConiksAuditLog) Update(dirInitHash [crypto.HashSizeByte]byte, newSTR *DirSTR) error { +func (l ConiksAuditLog) Update(dirInitHash string, newSTR *DirSTR) error { // error if we want to update the entry for an addr we don't know if !l.IsKnownDirectory(dirInitHash) { diff --git a/protocol/auditlog_test.go b/protocol/auditlog_test.go index a59774b..ccb58b9 100644 --- a/protocol/auditlog_test.go +++ b/protocol/auditlog_test.go @@ -1,9 +1,6 @@ package protocol -import ( - "github.com/coniks-sys/coniks-go/crypto" - "testing" -) +import "testing" func TestInsertEmptyHistory(t *testing.T) { // create basic test directory and audit log with 1 STR @@ -47,8 +44,7 @@ func TestUpdateUnknownHistory(t *testing.T) { // let's make sure that we can't update a history for an unknown // directory in our log - var unknown [crypto.HashSizeByte]byte - err := aud.Update(unknown, d.LatestSTR()) + err := aud.Update("unknown", d.LatestSTR()) if err != ErrAuditLog { t.Fatal("Expected an ErrAuditLog when updating an unknown server history") } @@ -156,9 +152,8 @@ func TestGetObservedSTRUnknown(t *testing.T) { // create basic test directory and audit log with 11 STRs d, aud, _ := NewTestAuditLog(t, 10) - var unknown [crypto.HashSizeByte]byte _, err := aud.GetObservedSTRs(&AuditingRequest{ - DirInitSTRHash: unknown, + DirInitSTRHash: "unknown", StartEpoch: uint64(d.LatestSTR().Epoch), EndEpoch: uint64(d.LatestSTR().Epoch)}) if err != ReqUnknownDirectory { @@ -166,7 +161,7 @@ func TestGetObservedSTRUnknown(t *testing.T) { } _, err = aud.GetObservedSTRs(&AuditingRequest{ - DirInitSTRHash: unknown, + DirInitSTRHash: "unknown", StartEpoch: uint64(6), EndEpoch: uint64(8)}) if err != ReqUnknownDirectory { diff --git a/protocol/message.go b/protocol/message.go index bd3d58c..20056b6 100644 --- a/protocol/message.go +++ b/protocol/message.go @@ -4,10 +4,7 @@ package protocol -import ( - "github.com/coniks-sys/coniks-go/crypto" - m "github.com/coniks-sys/coniks-go/merkletree" -) +import m "github.com/coniks-sys/coniks-go/merkletree" // The types of requests CONIKS clients send during the CONIKS protocols. const ( @@ -94,16 +91,17 @@ type MonitoringRequest struct { EndEpoch uint64 } -// An AuditingRequest is a message with a CONIKS key directory's address -// as a string, and a StartEpoch and an EndEpoch as uint64's that a CONIKS -// client sends to a CONIKS auditor to request the given directory's -// STRs for the given epoch range. To obtain a single STR, the client -// must set StartEpoch = EndEpoch in the request. +// An AuditingRequest is a message with a CONIKS key directory's initial +// STR hash as a string, and a StartEpoch and an EndEpoch as uint64's +// that a CONIKS client sends to a CONIKS auditor to request the given +// directory's STRs for the given epoch range. To obtain a single STR, +// the client must set StartEpoch = EndEpoch in the request. // // The response to a successful request is an STRHistoryRange with -// a list of STRs covering the epoch range [StartEpoch, EndEpoch]. +// a list of STRs covering the epoch range [StartEpoch, EndEpoch], +// inclusively. type AuditingRequest struct { - DirInitSTRHash [crypto.HashSizeByte]byte + DirInitSTRHash string StartEpoch uint64 EndEpoch uint64 } From 699858a1d88f9c3aa95dde0c34a1dab41daedb3f Mon Sep 17 00:00:00 2001 From: Marcela Melara Date: Mon, 3 Jul 2017 23:19:02 -0400 Subject: [PATCH 20/26] Add test case for getting an STR after an audit log update --- protocol/auditlog_test.go | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/protocol/auditlog_test.go b/protocol/auditlog_test.go index ccb58b9..50f9fa3 100644 --- a/protocol/auditlog_test.go +++ b/protocol/auditlog_test.go @@ -120,13 +120,14 @@ func TestGetObservedSTRInEpoch(t *testing.T) { } } -func TestGetEntireObservedSTRHist(t *testing.T) { +func TestGetObservedSTRMultipleEpochs(t *testing.T) { // create basic test directory and audit log with 2 STRs d, aud, hist := NewTestAuditLog(t, 1) // compute the hash of the initial STR for later lookups dirInitHash := computeInitSTRHash(hist[0]) + // first AuditingRequest res, err := aud.GetObservedSTRs(&AuditingRequest{ DirInitSTRHash: dirInitHash, StartEpoch: uint64(0), @@ -146,6 +147,32 @@ func TestGetEntireObservedSTRHist(t *testing.T) { if obs.STR[1].Epoch != d.LatestSTR().Epoch { t.Fatal("Unexpected latest STR epoch for returned STR") } + + // go to next epoch + d.Update() + err1 := aud.Update(dirInitHash, d.LatestSTR()) + if err1 != nil { + t.Fatal("Error occurred updating audit log after auditing request") + } + + // request the new latest STR + res, err = aud.GetObservedSTRs(&AuditingRequest{ + DirInitSTRHash: dirInitHash, + StartEpoch: d.LatestSTR().Epoch, + EndEpoch: d.LatestSTR().Epoch}) + + if err != ReqSuccess { + t.Fatal("Unable to get new latest STRs") + } + + obs = res.DirectoryResponse.(*STRHistoryRange) + if len(obs.STR) != 1 { + t.Fatal("Unexpected number of new latest STRs") + } + if obs.STR[0].Epoch != d.LatestSTR().Epoch { + t.Fatal("Unexpected new latest STR epoch") + } + } func TestGetObservedSTRUnknown(t *testing.T) { From 92cee27f21ab8299483b4d43712cfbd05c8308a6 Mon Sep 17 00:00:00 2001 From: Vu Quoc Huy Date: Wed, 5 Jul 2017 12:31:23 +0700 Subject: [PATCH 21/26] Refactor common functions --- protocol/auditlog.go | 20 ++++---------------- protocol/auditlog_test.go | 12 ++++++------ protocol/common.go | 18 ++++++++++++++++++ protocol/common_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 22 deletions(-) create mode 100644 protocol/common.go create mode 100644 protocol/common_test.go diff --git a/protocol/auditlog.go b/protocol/auditlog.go index fa7c17e..2f0225e 100644 --- a/protocol/auditlog.go +++ b/protocol/auditlog.go @@ -6,14 +6,11 @@ package protocol import ( - "encoding/hex" - - "github.com/coniks-sys/coniks-go/crypto" "github.com/coniks-sys/coniks-go/crypto/sign" ) type directoryHistory struct { - dirName string + name string signKey sign.PublicKey snapshots map[uint64]*DirSTR latestSTR *DirSTR @@ -29,15 +26,6 @@ type directoryHistory struct { // epoch. type ConiksAuditLog map[string]*directoryHistory -// computeInitSTRHash is a wrapper for the digest function; -// returns empty string if the STR isn't an initial STR (i.e. str.Epoch != 0) -func computeInitSTRHash(initSTR *DirSTR) string { - if initSTR.Epoch != 0 { - return "" - } - return hex.EncodeToString(crypto.Digest(initSTR.Signature)) -} - // updateLatestSTR inserts a new STR into a directory history; // assumes the STR has been validated by the caller func (h *directoryHistory) updateLatestSTR(newLatest *DirSTR) { @@ -46,9 +34,9 @@ func (h *directoryHistory) updateLatestSTR(newLatest *DirSTR) { } // caller validates that initSTR is for epoch 0 -func newDirectoryHistory(dirName string, signKey sign.PublicKey, initSTR *DirSTR) *directoryHistory { +func newDirectoryHistory(name string, signKey sign.PublicKey, initSTR *DirSTR) *directoryHistory { h := new(directoryHistory) - h.dirName = dirName + h.name = name h.signKey = signKey h.snapshots = make(map[uint64]*DirSTR) h.updateLatestSTR(initSTR) @@ -100,7 +88,7 @@ func (l ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, } // compute the hash of the initial STR - dirInitHash := computeInitSTRHash(hist[0]) + dirInitHash := ComputeDirectoryIdentity(hist[0]) // error if we want to create a new entry for a directory // we already know diff --git a/protocol/auditlog_test.go b/protocol/auditlog_test.go index 50f9fa3..b242957 100644 --- a/protocol/auditlog_test.go +++ b/protocol/auditlog_test.go @@ -12,7 +12,7 @@ func TestUpdateHistory(t *testing.T) { d, aud, hist := NewTestAuditLog(t, 0) // update the directory so we can update the audit log - dirInitHash := computeInitSTRHash(hist[0]) + dirInitHash := ComputeDirectoryIdentity(hist[0]) d.Update() err := aud.Update(dirInitHash, d.LatestSTR()) @@ -55,7 +55,7 @@ func TestUpdateBadNewSTR(t *testing.T) { d, aud, hist := NewTestAuditLog(t, 10) // compute the hash of the initial STR for later lookups - dirInitHash := computeInitSTRHash(hist[0]) + dirInitHash := ComputeDirectoryIdentity(hist[0]) // update the directory a few more times and then try // to update @@ -73,7 +73,7 @@ func TestGetLatestObservedSTR(t *testing.T) { d, aud, hist := NewTestAuditLog(t, 0) // compute the hash of the initial STR for later lookups - dirInitHash := computeInitSTRHash(hist[0]) + dirInitHash := ComputeDirectoryIdentity(hist[0]) res, err := aud.GetObservedSTRs(&AuditingRequest{ DirInitSTRHash: dirInitHash, @@ -97,7 +97,7 @@ func TestGetObservedSTRInEpoch(t *testing.T) { _, aud, hist := NewTestAuditLog(t, 10) // compute the hash of the initial STR for later lookups - dirInitHash := computeInitSTRHash(hist[0]) + dirInitHash := ComputeDirectoryIdentity(hist[0]) res, err := aud.GetObservedSTRs(&AuditingRequest{ DirInitSTRHash: dirInitHash, @@ -125,7 +125,7 @@ func TestGetObservedSTRMultipleEpochs(t *testing.T) { d, aud, hist := NewTestAuditLog(t, 1) // compute the hash of the initial STR for later lookups - dirInitHash := computeInitSTRHash(hist[0]) + dirInitHash := ComputeDirectoryIdentity(hist[0]) // first AuditingRequest res, err := aud.GetObservedSTRs(&AuditingRequest{ @@ -202,7 +202,7 @@ func TestGetObservedSTRMalformed(t *testing.T) { _, aud, hist := NewTestAuditLog(t, 10) // compute the hash of the initial STR for later lookups - dirInitHash := computeInitSTRHash(hist[0]) + dirInitHash := ComputeDirectoryIdentity(hist[0]) // also test the epoch range _, err := aud.GetObservedSTRs(&AuditingRequest{ diff --git a/protocol/common.go b/protocol/common.go new file mode 100644 index 0000000..d923cb3 --- /dev/null +++ b/protocol/common.go @@ -0,0 +1,18 @@ +package protocol + +import ( + "encoding/hex" + "fmt" + + "github.com/coniks-sys/coniks-go/crypto" +) + +// ComputeDirectoryIdentity returns the hash of +// the directory's initial STR as a string. +// It panics if the STR isn't an initial STR (i.e. str.Epoch != 0). +func ComputeDirectoryIdentity(str *DirSTR) string { + if str.Epoch != 0 { + panic(fmt.Sprintf("[coniks] Expect epoch 0, got %x", str.Epoch)) + } + return hex.EncodeToString(crypto.Digest(str.Signature)) +} diff --git a/protocol/common_test.go b/protocol/common_test.go new file mode 100644 index 0000000..35d4aae --- /dev/null +++ b/protocol/common_test.go @@ -0,0 +1,39 @@ +package protocol + +import ( + "testing" +) + +func TestComputeDirectoryIdentity(t *testing.T) { + // FIXME: NewTestDirectory should use a fixed VRF and Signing keys. + d, _ := NewTestDirectory(t, true) + // str0 := d.LatestSTR() + d.Update() + str1 := d.LatestSTR() + type args struct { + str *DirSTR + } + tests := []struct { + name string + args args + want string + }{ + // {"normal", args{str0}, ""}, + {"panic", args{str1}, ""}, + } + for _, tt := range tests { + // FIXME: Refactor testing. See #18. + t.Run(tt.name, func(t *testing.T) { + if tt.name == "panic" { + defer func() { + if r := recover(); r == nil { + t.Errorf("The code did not panic") + } + }() + } + if got := ComputeDirectoryIdentity(tt.args.str); got != tt.want { + t.Errorf("ComputeDirectoryIdentity() = %v, want %v", got, tt.want) + } + }) + } +} From 92c6a9832a696367d657cea7311f32e875eaf1a9 Mon Sep 17 00:00:00 2001 From: Marcela Melara Date: Fri, 7 Jul 2017 12:16:26 -0400 Subject: [PATCH 22/26] Use slice for initial history inserted, remove IsKnownDirectory --- protocol/auditlog.go | 82 ++++++++++++++++++++------------------------ protocol/testutil.go | 8 ++--- 2 files changed, 41 insertions(+), 49 deletions(-) diff --git a/protocol/auditlog.go b/protocol/auditlog.go index 2f0225e..2af9992 100644 --- a/protocol/auditlog.go +++ b/protocol/auditlog.go @@ -10,7 +10,7 @@ import ( ) type directoryHistory struct { - name string + dirName string signKey sign.PublicKey snapshots map[uint64]*DirSTR latestSTR *DirSTR @@ -20,7 +20,7 @@ type directoryHistory struct { // of all CONIKS directories known to a CONIKS auditor, // indexing the histories by the hash of a directory's initial // STR (specifically, the hash of the STR's signature as a string). -// Each history includes the directory's domain name as a string, its +// Each history includes the directory's domain dirName as a string, its // public signing key enabling the auditor to verify the corresponding // signed tree roots, and a map with the snapshots for each observed // epoch. @@ -34,9 +34,9 @@ func (h *directoryHistory) updateLatestSTR(newLatest *DirSTR) { } // caller validates that initSTR is for epoch 0 -func newDirectoryHistory(name string, signKey sign.PublicKey, initSTR *DirSTR) *directoryHistory { +func newDirectoryHistory(dirName string, signKey sign.PublicKey, initSTR *DirSTR) *directoryHistory { h := new(directoryHistory) - h.name = name + h.dirName = dirName h.signKey = signKey h.snapshots = make(map[uint64]*DirSTR) h.updateLatestSTR(initSTR) @@ -47,29 +47,28 @@ func newDirectoryHistory(name string, signKey sign.PublicKey, initSTR *DirSTR) * // log; the auditor will add an entry for each CONIKS directory // the first time it observes an STR for that directory. func NewAuditLog() ConiksAuditLog { - l := make(map[string]*directoryHistory) - return l + return make(map[string]*directoryHistory) } -// IsKnownDirectory checks to see if an entry for the directory -// (indexed by the hash of its initial STR dirInitHash) exists -// in the audit log l. IsKnownDirectory() does not -// validate the entries themselves. It returns true if an entry exists, -// and false otherwise. -func (l ConiksAuditLog) IsKnownDirectory(dirInitHash string) bool { - h := l[dirInitHash] - if h != nil { - return true - } - return false +// Set associates the given directoryHistory with the dirInitHash in the +// ConiksAuditLog. +func (l ConiksAuditLog) Set(dirInitHash string, dirHistory *directoryHistory) { + l[dirInitHash] = dirHistory +} + +// Get retrieves the directory history for the given dirInitHash +// from the ConiksAuditLog. +func (l ConiksAuditLog) Get(dirInitHash string) (*directoryHistory, bool) { + h, ok := l[dirInitHash] + return h, ok } // Insert creates a new directory history for the key directory addr, // verifies the consistency of the STR history so far, and inserts it // into the audit log l if the checks pass. // The directory history is initialized with the key directory's -// signing key signKey, and a list of STRs representing the -// directory's STR history so far (as a map of epochs to STRs). +// signing key signKey, and a list of snapshots snaps representing the +// directory's STR history so far, in chronological order. // Insert() returns an ErrAuditLog if the auditor attempts to create // a new history for a known directory, an ErrMalformedDirectoryMessage // if oldSTRs is malformed, a CheckBadSignature or CheckBadSTR if there @@ -80,54 +79,49 @@ func (l ConiksAuditLog) IsKnownDirectory(dirInitHash string) bool { // masomel: will probably want to write a more generic function // for "catching up" on a history in case an auditor misses epochs func (l ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, - hist map[uint64]*DirSTR) error { + snaps []*DirSTR) error { // make sure we're getting an initial STR at the very least - if len(hist) < 1 && hist[0].Epoch != 0 { + if len(snaps) < 1 && snaps[0].Epoch != 0 { return ErrMalformedDirectoryMessage } // compute the hash of the initial STR - dirInitHash := ComputeDirectoryIdentity(hist[0]) + dirInitHash := ComputeDirectoryIdentity(snaps[0]) // error if we want to create a new entry for a directory // we already know - if l.IsKnownDirectory(dirInitHash) { + h, ok := l.Get(dirInitHash) + if ok { return ErrAuditLog } // create the new directory history - h := newDirectoryHistory(addr, signKey, hist[0]) + h = newDirectoryHistory(addr, signKey, snaps[0]) // add each STR into the history // start at 1 since we've inserted the initial STR above - startEp := uint64(1) - endEp := uint64(len(hist)) - - // This loop automatically catches if hist is malformed - // (i.e. hist is missing an epoch between 0 and the latest given) - for ep := startEp; ep < endEp; ep++ { - str := hist[ep] - if str == nil { + // This loop automatically catches if snaps is malformed + // (i.e. snaps is missing an epoch between 0 and the latest given) + for i := 1; i < len(snaps); i++ { + str := snaps[i] + if str == nil || str.Epoch != uint64(i) { return ErrMalformedDirectoryMessage } // verify the consistency of each new STR before inserting // into the audit log - err := verifySTRConsistency(signKey, h.snapshots[ep-1], str) + err := verifySTRConsistency(signKey, h.latestSTR, str) if err != nil { return err } - h.snapshots[ep] = str + h.updateLatestSTR(snaps[i]) } - // Make sure to update the latestSTR - // in this particular call, the latestSTR has already been - // inserted into the snapshots map in the loop above - h.updateLatestSTR(hist[endEp-1]) - l[dirInitHash] = h + // Finally, add the new history to the log + l.Set(dirInitHash, h) return nil } @@ -143,12 +137,11 @@ func (l ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, func (l ConiksAuditLog) Update(dirInitHash string, newSTR *DirSTR) error { // error if we want to update the entry for an addr we don't know - if !l.IsKnownDirectory(dirInitHash) { + h, ok := l.Get(dirInitHash) + if !ok { return ErrAuditLog } - h := l[dirInitHash] - if err := verifySTRConsistency(h.signKey, h.latestSTR, newSTR); err != nil { return err } @@ -180,12 +173,11 @@ func (l ConiksAuditLog) GetObservedSTRs(req *AuditingRequest) (*Response, ErrorCode) { // make sure we have a history for the requested directory in the log - if !l.IsKnownDirectory(req.DirInitSTRHash) { + h, ok := l.Get(req.DirInitSTRHash) + if !ok { return NewErrorResponse(ReqUnknownDirectory), ReqUnknownDirectory } - h := l[req.DirInitSTRHash] - // make sure the request is well-formed if req.EndEpoch > h.latestSTR.Epoch || req.StartEpoch > req.EndEpoch { return NewErrorResponse(ErrMalformedClientMessage), diff --git a/protocol/testutil.go b/protocol/testutil.go index 0f41e4f..983ff76 100644 --- a/protocol/testutil.go +++ b/protocol/testutil.go @@ -35,17 +35,17 @@ func NewTestDirectory(t *testing.T, useTBs bool) ( // 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, map[uint64]*DirSTR) { +func NewTestAuditLog(t *testing.T, numEpochs int) (*ConiksDirectory, ConiksAuditLog, []*DirSTR) { d, pk := NewTestDirectory(t, true) aud := NewAuditLog() - hist := make(map[uint64]*DirSTR) + var hist []*DirSTR for ep := 0; ep < numEpochs; ep++ { - hist[d.LatestSTR().Epoch] = d.LatestSTR() + hist = append(hist, d.LatestSTR()) d.Update() } // always include the actual latest STR - hist[d.LatestSTR().Epoch] = d.LatestSTR() + hist = append(hist, d.LatestSTR()) err := aud.Insert("test-server", pk, hist) if err != nil { From 073aa7029ea181afb02c0981746288d76279efe3 Mon Sep 17 00:00:00 2001 From: Marcela Melara Date: Fri, 7 Jul 2017 12:25:42 -0400 Subject: [PATCH 23/26] dirName --> addr, some documentation fixes --- protocol/auditlog.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/protocol/auditlog.go b/protocol/auditlog.go index 2af9992..4b44bff 100644 --- a/protocol/auditlog.go +++ b/protocol/auditlog.go @@ -10,7 +10,7 @@ import ( ) type directoryHistory struct { - dirName string + addr string signKey sign.PublicKey snapshots map[uint64]*DirSTR latestSTR *DirSTR @@ -20,7 +20,7 @@ type directoryHistory struct { // of all CONIKS directories known to a CONIKS auditor, // indexing the histories by the hash of a directory's initial // STR (specifically, the hash of the STR's signature as a string). -// Each history includes the directory's domain dirName as a string, its +// Each history includes the directory's domain addr as a string, its // public signing key enabling the auditor to verify the corresponding // signed tree roots, and a map with the snapshots for each observed // epoch. @@ -34,9 +34,9 @@ func (h *directoryHistory) updateLatestSTR(newLatest *DirSTR) { } // caller validates that initSTR is for epoch 0 -func newDirectoryHistory(dirName string, signKey sign.PublicKey, initSTR *DirSTR) *directoryHistory { +func newDirectoryHistory(addr string, signKey sign.PublicKey, initSTR *DirSTR) *directoryHistory { h := new(directoryHistory) - h.dirName = dirName + h.addr = addr h.signKey = signKey h.snapshots = make(map[uint64]*DirSTR) h.updateLatestSTR(initSTR) @@ -50,14 +50,16 @@ func NewAuditLog() ConiksAuditLog { return make(map[string]*directoryHistory) } -// Set associates the given directoryHistory with the dirInitHash in the -// ConiksAuditLog. +// Set associates the given directoryHistory with the directory identifier +// (i.e. the hash of the initial STR) dirInitHash in the ConiksAuditLog. func (l ConiksAuditLog) Set(dirInitHash string, dirHistory *directoryHistory) { l[dirInitHash] = dirHistory } -// Get retrieves the directory history for the given dirInitHash -// from the ConiksAuditLog. +// Get retrieves the directory history for the given directory identifier +// dirInitHash from the ConiksAuditLog. +// Get() also returns a boolean indicating whether the requested dirInitHash +// is present in the log. func (l ConiksAuditLog) Get(dirInitHash string) (*directoryHistory, bool) { h, ok := l[dirInitHash] return h, ok From e3cb3432bbf8a98fbcbfabeae932ba71cbd88b8f Mon Sep 17 00:00:00 2001 From: Marcela Melara Date: Fri, 7 Jul 2017 13:00:14 -0400 Subject: [PATCH 24/26] Small fixes --- protocol/auditlog.go | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/protocol/auditlog.go b/protocol/auditlog.go index 4b44bff..c8bf053 100644 --- a/protocol/auditlog.go +++ b/protocol/auditlog.go @@ -50,17 +50,17 @@ func NewAuditLog() ConiksAuditLog { return make(map[string]*directoryHistory) } -// Set associates the given directoryHistory with the directory identifier +// set associates the given directoryHistory with the directory identifier // (i.e. the hash of the initial STR) dirInitHash in the ConiksAuditLog. -func (l ConiksAuditLog) Set(dirInitHash string, dirHistory *directoryHistory) { +func (l ConiksAuditLog) set(dirInitHash string, dirHistory *directoryHistory) { l[dirInitHash] = dirHistory } -// Get retrieves the directory history for the given directory identifier +// get retrieves the directory history for the given directory identifier // dirInitHash from the ConiksAuditLog. // Get() also returns a boolean indicating whether the requested dirInitHash // is present in the log. -func (l ConiksAuditLog) Get(dirInitHash string) (*directoryHistory, bool) { +func (l ConiksAuditLog) get(dirInitHash string) (*directoryHistory, bool) { h, ok := l[dirInitHash] return h, ok } @@ -84,7 +84,7 @@ func (l ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, snaps []*DirSTR) error { // make sure we're getting an initial STR at the very least - if len(snaps) < 1 && snaps[0].Epoch != 0 { + if len(snaps) < 1 || snaps[0].Epoch != 0 { return ErrMalformedDirectoryMessage } @@ -93,7 +93,7 @@ func (l ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, // error if we want to create a new entry for a directory // we already know - h, ok := l.Get(dirInitHash) + h, ok := l.get(dirInitHash) if ok { return ErrAuditLog } @@ -113,9 +113,7 @@ func (l ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, // verify the consistency of each new STR before inserting // into the audit log - err := verifySTRConsistency(signKey, h.latestSTR, str) - - if err != nil { + if err := verifySTRConsistency(signKey, h.latestSTR, str); err != nil { return err } @@ -123,7 +121,7 @@ func (l ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, } // Finally, add the new history to the log - l.Set(dirInitHash, h) + l.set(dirInitHash, h) return nil } @@ -139,7 +137,7 @@ func (l ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, func (l ConiksAuditLog) Update(dirInitHash string, newSTR *DirSTR) error { // error if we want to update the entry for an addr we don't know - h, ok := l.Get(dirInitHash) + h, ok := l.get(dirInitHash) if !ok { return ErrAuditLog } @@ -175,7 +173,7 @@ func (l ConiksAuditLog) GetObservedSTRs(req *AuditingRequest) (*Response, ErrorCode) { // make sure we have a history for the requested directory in the log - h, ok := l.Get(req.DirInitSTRHash) + h, ok := l.get(req.DirInitSTRHash) if !ok { return NewErrorResponse(ReqUnknownDirectory), ReqUnknownDirectory } From e886828ee76ad22bd9c211ba3446bbfe63ebb6ed Mon Sep 17 00:00:00 2001 From: Marcela Melara Date: Fri, 7 Jul 2017 13:32:57 -0400 Subject: [PATCH 25/26] Revert "Change audit log index from byte array to string" This reverts commit 7e540875d4ce60f00d18a8439baf83becb9fcf03. Conflicts: protocol/auditlog.go --- protocol/auditlog.go | 27 ++++++++++++++++----------- protocol/auditlog_test.go | 13 +++++++++---- protocol/message.go | 20 +++++++++++--------- 3 files changed, 36 insertions(+), 24 deletions(-) diff --git a/protocol/auditlog.go b/protocol/auditlog.go index c8bf053..3295be7 100644 --- a/protocol/auditlog.go +++ b/protocol/auditlog.go @@ -22,9 +22,9 @@ type directoryHistory struct { // STR (specifically, the hash of the STR's signature as a string). // Each history includes the directory's domain addr as a string, its // public signing key enabling the auditor to verify the corresponding -// signed tree roots, and a map with the snapshots for each observed -// epoch. -type ConiksAuditLog map[string]*directoryHistory +// signed tree roots, and a list with all observed snapshots in +// chronological order. +type ConiksAuditLog map[[crypto.HashSizeByte]byte]*directoryHistory // updateLatestSTR inserts a new STR into a directory history; // assumes the STR has been validated by the caller @@ -39,7 +39,7 @@ func newDirectoryHistory(addr string, signKey sign.PublicKey, initSTR *DirSTR) * h.addr = addr h.signKey = signKey h.snapshots = make(map[uint64]*DirSTR) - h.updateLatestSTR(initSTR) + h.latestSTR = nil return h } @@ -47,7 +47,7 @@ func newDirectoryHistory(addr string, signKey sign.PublicKey, initSTR *DirSTR) * // log; the auditor will add an entry for each CONIKS directory // the first time it observes an STR for that directory. func NewAuditLog() ConiksAuditLog { - return make(map[string]*directoryHistory) + return make(map[[crypto.HashSizeByte]byte]*directoryHistory) } // set associates the given directoryHistory with the directory identifier @@ -65,16 +65,21 @@ func (l ConiksAuditLog) get(dirInitHash string) (*directoryHistory, bool) { return h, ok } -// Insert creates a new directory history for the key directory addr, -// verifies the consistency of the STR history so far, and inserts it -// into the audit log l if the checks pass. +// updateLatestSTR inserts a new STR into a directory history; +// assumes the STR has been validated by the caller +func (h *directoryHistory) updateLatestSTR(newLatest *DirSTR) { + h.snapshots[newLatest.Epoch] = newLatest + h.latestSTR = newLatest +} + +// Insert creates a new directory history for the key directory addr +// and inserts it into the audit log l. // The directory history is initialized with the key directory's // signing key signKey, and a list of snapshots snaps representing the // directory's STR history so far, in chronological order. // Insert() returns an ErrAuditLog if the auditor attempts to create // a new history for a known directory, an ErrMalformedDirectoryMessage -// if oldSTRs is malformed, a CheckBadSignature or CheckBadSTR if there -// is an inconsistency in the history given in hist, and nil otherwise. +// if oldSTRs is malformed, and nil otherwise. // Insert() only creates the initial entry in the log for addr. Use Update() // to insert newly observed STRs for addr in subsequent epochs. // FIXME: pass Response message as param @@ -134,7 +139,7 @@ func (l ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, // addr prior to its first call and thereby expects that an entry for addr // exists in the audit log l. // FIXME: pass Response message as param -func (l ConiksAuditLog) Update(dirInitHash string, newSTR *DirSTR) error { +func (l ConiksAuditLog) Update(dirInitHash [crypto.HashSizeByte]byte, newSTR *DirSTR) error { // error if we want to update the entry for an addr we don't know h, ok := l.get(dirInitHash) diff --git a/protocol/auditlog_test.go b/protocol/auditlog_test.go index b242957..6695b1d 100644 --- a/protocol/auditlog_test.go +++ b/protocol/auditlog_test.go @@ -1,6 +1,9 @@ package protocol -import "testing" +import ( + "github.com/coniks-sys/coniks-go/crypto" + "testing" +) func TestInsertEmptyHistory(t *testing.T) { // create basic test directory and audit log with 1 STR @@ -44,7 +47,8 @@ func TestUpdateUnknownHistory(t *testing.T) { // let's make sure that we can't update a history for an unknown // directory in our log - err := aud.Update("unknown", d.LatestSTR()) + var unknown [crypto.HashSizeByte]byte + err := aud.Update(unknown, d.LatestSTR()) if err != ErrAuditLog { t.Fatal("Expected an ErrAuditLog when updating an unknown server history") } @@ -179,8 +183,9 @@ func TestGetObservedSTRUnknown(t *testing.T) { // create basic test directory and audit log with 11 STRs d, aud, _ := NewTestAuditLog(t, 10) + var unknown [crypto.HashSizeByte]byte _, err := aud.GetObservedSTRs(&AuditingRequest{ - DirInitSTRHash: "unknown", + DirInitSTRHash: unknown, StartEpoch: uint64(d.LatestSTR().Epoch), EndEpoch: uint64(d.LatestSTR().Epoch)}) if err != ReqUnknownDirectory { @@ -188,7 +193,7 @@ func TestGetObservedSTRUnknown(t *testing.T) { } _, err = aud.GetObservedSTRs(&AuditingRequest{ - DirInitSTRHash: "unknown", + DirInitSTRHash: unknown, StartEpoch: uint64(6), EndEpoch: uint64(8)}) if err != ReqUnknownDirectory { diff --git a/protocol/message.go b/protocol/message.go index 20056b6..bd3d58c 100644 --- a/protocol/message.go +++ b/protocol/message.go @@ -4,7 +4,10 @@ package protocol -import m "github.com/coniks-sys/coniks-go/merkletree" +import ( + "github.com/coniks-sys/coniks-go/crypto" + m "github.com/coniks-sys/coniks-go/merkletree" +) // The types of requests CONIKS clients send during the CONIKS protocols. const ( @@ -91,17 +94,16 @@ type MonitoringRequest struct { EndEpoch uint64 } -// An AuditingRequest is a message with a CONIKS key directory's initial -// STR hash as a string, and a StartEpoch and an EndEpoch as uint64's -// that a CONIKS client sends to a CONIKS auditor to request the given -// directory's STRs for the given epoch range. To obtain a single STR, -// the client must set StartEpoch = EndEpoch in the request. +// An AuditingRequest is a message with a CONIKS key directory's address +// as a string, and a StartEpoch and an EndEpoch as uint64's that a CONIKS +// client sends to a CONIKS auditor to request the given directory's +// STRs for the given epoch range. To obtain a single STR, the client +// must set StartEpoch = EndEpoch in the request. // // The response to a successful request is an STRHistoryRange with -// a list of STRs covering the epoch range [StartEpoch, EndEpoch], -// inclusively. +// a list of STRs covering the epoch range [StartEpoch, EndEpoch]. type AuditingRequest struct { - DirInitSTRHash string + DirInitSTRHash [crypto.HashSizeByte]byte StartEpoch uint64 EndEpoch uint64 } From 3e340b9fc0c59963e31e70760b4349fe4dffc2af Mon Sep 17 00:00:00 2001 From: Marcela Melara Date: Fri, 7 Jul 2017 14:03:09 -0400 Subject: [PATCH 26/26] More fixes for reverting --- protocol/auditlog.go | 18 ++++++------------ protocol/common.go | 8 +++++--- protocol/common_test.go | 8 +++++--- protocol/testutil.go | 1 + 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/protocol/auditlog.go b/protocol/auditlog.go index 3295be7..a412c76 100644 --- a/protocol/auditlog.go +++ b/protocol/auditlog.go @@ -6,6 +6,7 @@ package protocol import ( + "github.com/coniks-sys/coniks-go/crypto" "github.com/coniks-sys/coniks-go/crypto/sign" ) @@ -19,7 +20,7 @@ type directoryHistory struct { // A ConiksAuditLog maintains the histories // of all CONIKS directories known to a CONIKS auditor, // indexing the histories by the hash of a directory's initial -// STR (specifically, the hash of the STR's signature as a string). +// STR (specifically, the hash of the STR's signature). // Each history includes the directory's domain addr as a string, its // public signing key enabling the auditor to verify the corresponding // signed tree roots, and a list with all observed snapshots in @@ -39,7 +40,7 @@ func newDirectoryHistory(addr string, signKey sign.PublicKey, initSTR *DirSTR) * h.addr = addr h.signKey = signKey h.snapshots = make(map[uint64]*DirSTR) - h.latestSTR = nil + h.updateLatestSTR(initSTR) return h } @@ -52,7 +53,7 @@ func NewAuditLog() ConiksAuditLog { // set associates the given directoryHistory with the directory identifier // (i.e. the hash of the initial STR) dirInitHash in the ConiksAuditLog. -func (l ConiksAuditLog) set(dirInitHash string, dirHistory *directoryHistory) { +func (l ConiksAuditLog) set(dirInitHash [crypto.HashSizeByte]byte, dirHistory *directoryHistory) { l[dirInitHash] = dirHistory } @@ -60,18 +61,11 @@ func (l ConiksAuditLog) set(dirInitHash string, dirHistory *directoryHistory) { // dirInitHash from the ConiksAuditLog. // Get() also returns a boolean indicating whether the requested dirInitHash // is present in the log. -func (l ConiksAuditLog) get(dirInitHash string) (*directoryHistory, bool) { +func (l ConiksAuditLog) get(dirInitHash [crypto.HashSizeByte]byte) (*directoryHistory, bool) { h, ok := l[dirInitHash] return h, ok } -// updateLatestSTR inserts a new STR into a directory history; -// assumes the STR has been validated by the caller -func (h *directoryHistory) updateLatestSTR(newLatest *DirSTR) { - h.snapshots[newLatest.Epoch] = newLatest - h.latestSTR = newLatest -} - // Insert creates a new directory history for the key directory addr // and inserts it into the audit log l. // The directory history is initialized with the key directory's @@ -112,7 +106,7 @@ func (l ConiksAuditLog) Insert(addr string, signKey sign.PublicKey, // (i.e. snaps is missing an epoch between 0 and the latest given) for i := 1; i < len(snaps); i++ { str := snaps[i] - if str == nil || str.Epoch != uint64(i) { + if str == nil { return ErrMalformedDirectoryMessage } diff --git a/protocol/common.go b/protocol/common.go index d923cb3..01f277b 100644 --- a/protocol/common.go +++ b/protocol/common.go @@ -1,7 +1,6 @@ package protocol import ( - "encoding/hex" "fmt" "github.com/coniks-sys/coniks-go/crypto" @@ -10,9 +9,12 @@ import ( // ComputeDirectoryIdentity returns the hash of // the directory's initial STR as a string. // It panics if the STR isn't an initial STR (i.e. str.Epoch != 0). -func ComputeDirectoryIdentity(str *DirSTR) string { +func ComputeDirectoryIdentity(str *DirSTR) [crypto.HashSizeByte]byte { if str.Epoch != 0 { panic(fmt.Sprintf("[coniks] Expect epoch 0, got %x", str.Epoch)) } - return hex.EncodeToString(crypto.Digest(str.Signature)) + + var initSTRHash [crypto.HashSizeByte]byte + copy(initSTRHash[:], crypto.Digest(str.Signature)) + return initSTRHash } diff --git a/protocol/common_test.go b/protocol/common_test.go index 35d4aae..8697335 100644 --- a/protocol/common_test.go +++ b/protocol/common_test.go @@ -2,24 +2,26 @@ package protocol import ( "testing" + + "github.com/coniks-sys/coniks-go/crypto" ) func TestComputeDirectoryIdentity(t *testing.T) { - // FIXME: NewTestDirectory should use a fixed VRF and Signing keys. d, _ := NewTestDirectory(t, true) // str0 := d.LatestSTR() d.Update() str1 := d.LatestSTR() + var unknown [crypto.HashSizeByte]byte type args struct { str *DirSTR } tests := []struct { name string args args - want string + want [crypto.HashSizeByte]byte }{ // {"normal", args{str0}, ""}, - {"panic", args{str1}, ""}, + {"panic", args{str1}, unknown}, } for _, tt := range tests { // FIXME: Refactor testing. See #18. diff --git a/protocol/testutil.go b/protocol/testutil.go index 983ff76..f460222 100644 --- a/protocol/testutil.go +++ b/protocol/testutil.go @@ -14,6 +14,7 @@ import ( 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)