Skip to content

Commit

Permalink
Index audit log by hash of directory's initial STR
Browse files Browse the repository at this point in the history
  • Loading branch information
masomel committed Jul 3, 2017
1 parent f63dbb0 commit 3168fff
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 79 deletions.
84 changes: 52 additions & 32 deletions protocol/auditlog.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
}
Expand Down
76 changes: 33 additions & 43 deletions protocol/auditlog_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package protocol

import (
"github.com/coniks-sys/coniks-go/crypto"
"testing"
)

Expand All @@ -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")
Expand Down Expand Up @@ -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")
}
Expand All @@ -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")
}
Expand All @@ -125,16 +131,19 @@ 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 {
t.Fatal("Error inserting new server history with prior STRs")
}

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")
Expand Down Expand Up @@ -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")
}
Expand All @@ -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")
}
Expand Down
11 changes: 7 additions & 4 deletions protocol/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 3168fff

Please sign in to comment.