-
Notifications
You must be signed in to change notification settings - Fork 30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Client-auditor protocol #155
Merged
Merged
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
5a923db
Add client-auditor messages
masomel d9ed76d
Create audit log structure, query API finished
masomel 146e91a
Add/Update docs to include auditor, add ReqUnknownDirectory auditor e…
masomel 90e2517
Use single generic verifySTRConsistency to be used by client and auditor
masomel e8178c1
Add tests for audit log, debug audit log
masomel badbafc
Add assertions to validate auditor messages on client
masomel 3bd8653
Add generic STR response handler
masomel c2d107f
# This is a combination of 2 commits.
masomel 13d3eb2
Fix documentation
masomel 0d0d312
Use DirSTR instead of merkletree.SignedTreeRoot in auditlog
masomel 8b1eeeb
Remove all references to auditor-directory communication, make audito…
masomel 3872e32
STRList -> STRHistoryRange
masomel 1f609a8
Fail sooner in GetObservedSTRs
masomel 477cddf
Revert changes to protocol/str.go
masomel c6d106c
Always request epoch range in AuditingRequest, fix Insert() bug
masomel 9843f4a
Index audit log by hash of directory's initial STR
masomel 9f212b1
Insert latest STR into snapshot map right away
masomel fcebf89
Fix go vet error
masomel 7e54087
Change audit log index from byte array to string
masomel 699858a
Add test case for getting an STR after an audit log update
masomel 92cee27
Refactor common functions
vqhuy 92c6a98
Use slice for initial history inserted, remove IsKnownDirectory
masomel 073aa70
dirName --> addr, some documentation fixes
masomel e3cb343
Small fixes
masomel e886828
Revert "Change audit log index from byte array to string"
masomel 3e340b9
More fixes for reverting
masomel File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
// 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" | ||
"github.com/coniks-sys/coniks-go/crypto/sign" | ||
) | ||
|
||
type directoryHistory struct { | ||
addr string | ||
signKey sign.PublicKey | ||
snapshots map[uint64]*DirSTR | ||
latestSTR *DirSTR | ||
} | ||
|
||
// 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). | ||
// 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 | ||
// 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 | ||
func (h *directoryHistory) updateLatestSTR(newLatest *DirSTR) { | ||
h.snapshots[newLatest.Epoch] = newLatest | ||
h.latestSTR = newLatest | ||
} | ||
|
||
// caller validates that initSTR is for epoch 0 | ||
func newDirectoryHistory(addr string, signKey sign.PublicKey, initSTR *DirSTR) *directoryHistory { | ||
h := new(directoryHistory) | ||
h.addr = addr | ||
h.signKey = signKey | ||
h.snapshots = make(map[uint64]*DirSTR) | ||
h.updateLatestSTR(initSTR) | ||
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 { | ||
return make(map[[crypto.HashSizeByte]byte]*directoryHistory) | ||
} | ||
|
||
// 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 [crypto.HashSizeByte]byte, dirHistory *directoryHistory) { | ||
l[dirInitHash] = dirHistory | ||
} | ||
|
||
// 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 [crypto.HashSizeByte]byte) (*directoryHistory, bool) { | ||
h, ok := l[dirInitHash] | ||
return h, ok | ||
} | ||
|
||
// 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, 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 | ||
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 { | ||
return ErrMalformedDirectoryMessage | ||
} | ||
|
||
// compute the hash of the initial STR | ||
dirInitHash := ComputeDirectoryIdentity(snaps[0]) | ||
|
||
// error if we want to create a new entry for a directory | ||
// we already know | ||
h, ok := l.get(dirInitHash) | ||
if ok { | ||
return ErrAuditLog | ||
} | ||
|
||
// create the new directory history | ||
h = newDirectoryHistory(addr, signKey, snaps[0]) | ||
|
||
// add each STR into the history | ||
// start at 1 since we've inserted the initial STR above | ||
// 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 { | ||
return ErrMalformedDirectoryMessage | ||
} | ||
|
||
// verify the consistency of each new STR before inserting | ||
// into the audit log | ||
if err := verifySTRConsistency(signKey, h.latestSTR, str); err != nil { | ||
return err | ||
} | ||
|
||
h.updateLatestSTR(snaps[i]) | ||
} | ||
|
||
// Finally, add the new history to the log | ||
l.set(dirInitHash, h) | ||
|
||
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 Response message as param | ||
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) | ||
if !ok { | ||
return ErrAuditLog | ||
} | ||
|
||
if err := verifySTRConsistency(h.signKey, h.latestSTR, newSTR); err != nil { | ||
return err | ||
} | ||
|
||
// update the latest STR | ||
h.updateLatestSTR(newSTR) | ||
return nil | ||
} | ||
|
||
// 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, 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 [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. | ||
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) | ||
if !ok { | ||
return NewErrorResponse(ReqUnknownDirectory), ReqUnknownDirectory | ||
} | ||
|
||
// make sure the request is well-formed | ||
if req.EndEpoch > h.latestSTR.Epoch || req.StartEpoch > req.EndEpoch { | ||
return NewErrorResponse(ErrMalformedClientMessage), | ||
ErrMalformedClientMessage | ||
} | ||
|
||
var strs []*DirSTR | ||
for ep := req.StartEpoch; ep <= req.EndEpoch; ep++ { | ||
str := h.snapshots[ep] | ||
strs = append(strs, str) | ||
} | ||
|
||
return NewSTRHistoryRange(strs) | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the refactor suggested above, these two operations (
verifySTRConsistency
,updateLatestSTR
) can be combined into anh.internalUpdate(newSTR)
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because of what I'm doing for #170, I need to see if it makes sense to refactor these operations both on the client and auditor. I'll probably hold off on that for now.