Skip to content

Commit 6e9e4d1

Browse files
authored
Merge pull request #16 from bwesterb/lvalenta/evidence
Add support for evidence
2 parents d9aab33 + 9267f5f commit 6e9e4d1

File tree

8 files changed

+526
-193
lines changed

8 files changed

+526
-193
lines changed

ca/ca.go

Lines changed: 133 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,8 @@ import (
2121
"golang.org/x/crypto/cryptobyte"
2222
)
2323

24-
const csLen = 32
25-
2624
var (
27-
ErrChecksumInvalid = errors.New("Invalid checksum")
28-
ErrClosed = errors.New("Handle is closed")
25+
ErrClosed = errors.New("Handle is closed")
2926
)
3027

3128
type NewOpts struct {
@@ -50,76 +47,12 @@ type Handle struct {
5047

5148
indices map[uint32]*Index
5249
aas map[uint32]*os.File
50+
evs map[uint32]*os.File
5351
trees map[uint32]*Tree
5452

5553
batchNumbersCache []uint32 // cache for existing batches
5654
}
5755

58-
type QueuedAssertion struct {
59-
Checksum []byte
60-
Assertion mtc.Assertion
61-
}
62-
63-
func (a *QueuedAssertion) UnmarshalBinary(data []byte) error {
64-
var (
65-
s cryptobyte.String = cryptobyte.String(data)
66-
checksum [csLen]byte
67-
)
68-
if !s.CopyBytes(checksum[:]) {
69-
return mtc.ErrTruncated
70-
}
71-
72-
a.Checksum = make([]byte, csLen)
73-
copy(a.Checksum, checksum[:])
74-
75-
checksum2 := sha256.Sum256([]byte(s))
76-
if !bytes.Equal(checksum2[:], checksum[:]) {
77-
return ErrChecksumInvalid
78-
}
79-
80-
if err := a.Assertion.UnmarshalBinary([]byte(s)); err != nil {
81-
return err
82-
}
83-
84-
return nil
85-
}
86-
87-
func (a *QueuedAssertion) marshalAndCheckAssertion() ([]byte, error) {
88-
buf, err := a.Assertion.MarshalBinary()
89-
if err != nil {
90-
return nil, err
91-
}
92-
93-
checksum2 := sha256.Sum256([]byte(buf))
94-
if a.Checksum == nil {
95-
a.Checksum = checksum2[:]
96-
} else if !bytes.Equal(checksum2[:], a.Checksum) {
97-
return nil, ErrChecksumInvalid
98-
}
99-
100-
return buf, nil
101-
}
102-
103-
// If set, checks whether the Checksum is correct. If not set, sets the
104-
// Checksum to the correct value.
105-
func (a *QueuedAssertion) Check() error {
106-
_, err := a.marshalAndCheckAssertion()
107-
return err
108-
}
109-
110-
func (a *QueuedAssertion) MarshalBinary() ([]byte, error) {
111-
var b cryptobyte.Builder
112-
113-
buf, err := a.marshalAndCheckAssertion()
114-
if err != nil {
115-
return nil, err
116-
}
117-
b.AddBytes(a.Checksum)
118-
b.AddBytes(buf)
119-
120-
return b.Bytes()
121-
}
122-
12356
func (ca *Handle) Params() mtc.CAParams {
12457
return ca.params
12558
}
@@ -137,6 +70,10 @@ func (ca *Handle) Close() error {
13770
r.Close()
13871
}
13972

73+
for _, r := range ca.evs {
74+
r.Close()
75+
}
76+
14077
for _, t := range ca.trees {
14178
t.Close()
14279
}
@@ -165,7 +102,7 @@ func (h *Handle) dropQueue() error {
165102
//
166103
// For each entry, if checksum is not nil, makes sure the assertion
167104
// matches the checksum
168-
func (h *Handle) QueueMultiple(it func(yield func(qa QueuedAssertion) error) error) error {
105+
func (h *Handle) QueueMultiple(it func(yield func(ar mtc.AssertionRequest) error) error) error {
169106
if h.closed {
170107
return ErrClosed
171108
}
@@ -177,8 +114,8 @@ func (h *Handle) QueueMultiple(it func(yield func(qa QueuedAssertion) error) err
177114
defer w.Close()
178115
bw := bufio.NewWriter(w)
179116

180-
if err := it(func(qa QueuedAssertion) error {
181-
buf, err := qa.MarshalBinary()
117+
if err := it(func(ar mtc.AssertionRequest) error {
118+
buf, err := ar.MarshalBinary()
182119
if err != nil {
183120
return err
184121
}
@@ -208,14 +145,9 @@ func (h *Handle) QueueMultiple(it func(yield func(qa QueuedAssertion) error) err
208145
// Queue assertion for publication.
209146
//
210147
// If checksum is not nil, makes sure assertion matches the checksum.
211-
func (h *Handle) Queue(a mtc.Assertion, checksum []byte) error {
212-
return h.QueueMultiple(func(yield func(qa QueuedAssertion) error) error {
213-
return yield(
214-
QueuedAssertion{
215-
Checksum: checksum,
216-
Assertion: a,
217-
},
218-
)
148+
func (h *Handle) Queue(ar mtc.AssertionRequest) error {
149+
return h.QueueMultiple(func(yield func(ar mtc.AssertionRequest) error) error {
150+
return yield(ar)
219151
})
220152
}
221153

@@ -227,6 +159,7 @@ func Open(path string) (*Handle, error) {
227159
path: path,
228160
indices: make(map[uint32]*Index),
229161
aas: make(map[uint32]*os.File),
162+
evs: make(map[uint32]*os.File),
230163
trees: make(map[uint32]*Tree),
231164
}
232165
if err := h.lock(); err != nil {
@@ -282,6 +215,10 @@ func (h Handle) aaPath(number uint32) string {
282215
return gopath.Join(h.batchPath(number), "abridged-assertions")
283216
}
284217

218+
func (h Handle) evPath(number uint32) string {
219+
return gopath.Join(h.batchPath(number), "evidence")
220+
}
221+
285222
func (h Handle) batchPath(number uint32) string {
286223
return gopath.Join(h.batchesPath(), fmt.Sprintf("%d", number))
287224
}
@@ -387,7 +324,7 @@ func (h *Handle) listBatchRange() (mtc.BatchRange, error) {
387324
}
388325

389326
// Calls f on each assertion queued to be published.
390-
func (h *Handle) WalkQueue(f func(QueuedAssertion) error) error {
327+
func (h *Handle) WalkQueue(f func(mtc.AssertionRequest) error) error {
391328
r, err := os.OpenFile(h.queuePath(), os.O_RDONLY, 0)
392329
if err != nil {
393330
return fmt.Errorf("Opening queue: %w", err)
@@ -400,7 +337,7 @@ func (h *Handle) WalkQueue(f func(QueuedAssertion) error) error {
400337
var (
401338
prefix [2]byte
402339
aLen uint16
403-
qa QueuedAssertion
340+
ar mtc.AssertionRequest
404341
)
405342
_, err := io.ReadFull(br, prefix[:])
406343
if err == io.EOF {
@@ -418,12 +355,12 @@ func (h *Handle) WalkQueue(f func(QueuedAssertion) error) error {
418355
return fmt.Errorf("Reading queue: %w", err)
419356
}
420357

421-
err = qa.UnmarshalBinary(buf)
358+
err = ar.UnmarshalBinary(buf)
422359
if err != nil {
423360
return fmt.Errorf("Parsing queue: %w", err)
424361
}
425362

426-
err = f(qa)
363+
err = f(ar)
427364
if err != nil {
428365
return err
429366
}
@@ -489,6 +426,14 @@ func (h *Handle) closeBatch(batch uint32) error {
489426
delete(h.aas, batch)
490427
}
491428

429+
if r, ok := h.evs[batch]; ok {
430+
err := r.Close()
431+
if err != nil {
432+
return fmt.Errorf("closing evidence for %d: %w", batch, err)
433+
}
434+
delete(h.evs, batch)
435+
}
436+
492437
if r, ok := h.trees[batch]; ok {
493438
err := r.Close()
494439
if err != nil {
@@ -545,10 +490,25 @@ func (ca *Handle) aaFileFor(batch uint32) (*os.File, error) {
545490
return r, nil
546491
}
547492

493+
// Returns file handle to evidence file for the given batch.
494+
func (ca *Handle) evFileFor(batch uint32) (*os.File, error) {
495+
if r, ok := ca.evs[batch]; ok {
496+
return r, nil
497+
}
498+
499+
r, err := os.Open(ca.evPath(batch))
500+
if err != nil {
501+
return nil, err
502+
}
503+
504+
return r, nil
505+
}
506+
548507
type keySearchResult struct {
549508
Batch uint32
550509
SequenceNumber uint64
551510
Offset uint64
511+
EvidenceOffset uint64
552512
}
553513

554514
// Returns the certificate for an issued assertion
@@ -589,7 +549,46 @@ func (ca *Handle) CertificateFor(a mtc.Assertion) (*mtc.BikeshedCertificate, err
589549
}, nil
590550
}
591551

592-
// Search for AbridgedAssertions's batch/seqno/offset by key.
552+
var errShortCircuit = errors.New("short circuit")
553+
554+
// Returns the evidence for an issued assertion
555+
func (ca *Handle) EvidenceFor(a mtc.Assertion) (*mtc.Evidence, error) {
556+
aa := a.Abridge()
557+
var key [mtc.HashLen]byte
558+
err := aa.Key(key[:])
559+
if err != nil {
560+
return nil, err
561+
}
562+
res, err := ca.aaByKey(key[:])
563+
if err != nil {
564+
return nil, fmt.Errorf("searching by key: %w", err)
565+
}
566+
567+
if res == nil {
568+
return nil, fmt.Errorf("no assertion with key %x on record", key)
569+
}
570+
571+
var ev *mtc.Evidence
572+
evFile, err := ca.evFileFor(res.Batch)
573+
if err != nil {
574+
return nil, err
575+
}
576+
_, err = evFile.Seek(int64(res.EvidenceOffset), 0)
577+
if err != nil {
578+
return nil, err
579+
}
580+
err = mtc.UnmarshalEvidenceEntries(evFile, func(_ int, ev2 *mtc.Evidence) error {
581+
ev = ev2
582+
return errShortCircuit
583+
})
584+
if err != errShortCircuit {
585+
return nil, err
586+
}
587+
588+
return ev, nil
589+
}
590+
591+
// Search for AbridgedAssertions's batch/seqno/offset/evidence_offset by key.
593592
func (ca *Handle) aaByKey(key []byte) (*keySearchResult, error) {
594593
batches, err := ca.listBatchRange()
595594
if err != nil {
@@ -600,7 +599,7 @@ func (ca *Handle) aaByKey(key []byte) (*keySearchResult, error) {
600599
return nil, nil
601600
}
602601

603-
for batch := batches.End - 1; batch <= batches.End; batch-- {
602+
for batch := batches.End - 1; batch >= batches.Begin && batch <= batches.End; batch-- {
604603
res, err := ca.aaByKeyIn(batch, key)
605604
if err != nil {
606605
return nil, fmt.Errorf("Searching in batch %d: %w", batch, err)
@@ -610,6 +609,7 @@ func (ca *Handle) aaByKey(key []byte) (*keySearchResult, error) {
610609
Batch: batch,
611610
SequenceNumber: res.SequenceNumber,
612611
Offset: res.Offset,
612+
EvidenceOffset: res.EvidenceOffset,
613613
}, nil
614614
}
615615
}
@@ -760,6 +760,7 @@ func (h *Handle) issueBatch(number uint32, empty bool) error {
760760
"tree",
761761
"signed-validity-window",
762762
"abridged-assertions",
763+
"evidence",
763764
"index",
764765
},
765766
)
@@ -884,7 +885,7 @@ func (h *Handle) issueBatchTo(dir string, batch mtc.Batch, empty bool) error {
884885
prevHeads = w.ValidityWindow.TreeHeads
885886
}
886887

887-
// Read queue and write abridged-assertions
888+
// Read queue and write abridged-assertions and evidence
888889
aasPath := gopath.Join(dir, "abridged-assertions")
889890
aasW, err := os.Create(aasPath)
890891
if err != nil {
@@ -893,23 +894,48 @@ func (h *Handle) issueBatchTo(dir string, batch mtc.Batch, empty bool) error {
893894
defer aasW.Close()
894895
aasBW := bufio.NewWriter(aasW)
895896

897+
evPath := gopath.Join(dir, "evidence")
898+
evW, err := os.Create(evPath)
899+
if err != nil {
900+
return fmt.Errorf("creating %s: %w", evPath, err)
901+
}
902+
defer evW.Close()
903+
evBW := bufio.NewWriter(evW)
904+
896905
if !empty {
897-
err = h.WalkQueue(func(qa QueuedAssertion) error {
898-
aa := qa.Assertion.Abridge()
906+
err = h.WalkQueue(func(ar mtc.AssertionRequest) error {
907+
aa := ar.Assertion.Abridge()
899908
buf, err := aa.MarshalBinary()
900909
if err != nil {
901-
return fmt.Errorf("Marshalling assertion %x: %w", qa.Checksum, err)
910+
return fmt.Errorf("Marshalling assertion %x: %w", ar.Checksum, err)
902911
}
903912

904913
_, err = aasBW.Write(buf)
905914
if err != nil {
906915
return fmt.Errorf(
907916
"Writing assertion %x to %s: %w",
908-
qa.Checksum,
917+
ar.Checksum,
909918
aasPath,
910919
err,
911920
)
912921
}
922+
923+
ev := ar.Evidence
924+
buf, err = ev.MarshalBinary()
925+
if err != nil {
926+
return fmt.Errorf("Marshalling evidence %x: %w", ar.Checksum, err)
927+
}
928+
929+
_, err = evBW.Write(buf)
930+
if err != nil {
931+
return fmt.Errorf(
932+
"Writing evidence %x to %s: %w",
933+
ar.Checksum,
934+
evPath,
935+
err,
936+
)
937+
}
938+
913939
return nil
914940
})
915941
if err != nil {
@@ -932,6 +958,21 @@ func (h *Handle) issueBatchTo(dir string, batch mtc.Batch, empty bool) error {
932958
}
933959
defer aasR.Close()
934960

961+
err = evBW.Flush()
962+
if err != nil {
963+
return fmt.Errorf("flushing %s: %w", evPath, err)
964+
}
965+
966+
err = evW.Close()
967+
if err != nil {
968+
return fmt.Errorf("closing %s: %w", evPath, err)
969+
}
970+
evR, err := os.OpenFile(evPath, os.O_RDONLY, 0)
971+
if err != nil {
972+
return fmt.Errorf("opening %s: %w", evPath, err)
973+
}
974+
defer evR.Close()
975+
935976
// Compute tree
936977
tree, err := batch.ComputeTree(bufio.NewReader(aasR))
937978
if err != nil {
@@ -970,7 +1011,7 @@ func (h *Handle) issueBatchTo(dir string, batch mtc.Batch, empty bool) error {
9701011

9711012
defer indexW.Close()
9721013

973-
err = ComputeIndex(aasR, indexW)
1014+
err = ComputeIndex(aasR, evR, indexW)
9741015
if err != nil {
9751016
return fmt.Errorf("computing %s to start: %w", indexPath, err)
9761017
}

0 commit comments

Comments
 (0)