Skip to content

Commit 10c1caf

Browse files
committed
Convert evidence to a list
- Use a list for evidence instead of a single value. This should allow evidence to be used more broadly than for X.509 chains in the future: (see davidben/merkle-tree-certs#23). - Use lazy parsing for X.509 chain evidence. Unrelated: - Rename http/server.go functions for consistency with cli.
1 parent 6e9e4d1 commit 10c1caf

File tree

5 files changed

+110
-83
lines changed

5 files changed

+110
-83
lines changed

ca/ca.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ func (ca *Handle) CertificateFor(a mtc.Assertion) (*mtc.BikeshedCertificate, err
552552
var errShortCircuit = errors.New("short circuit")
553553

554554
// Returns the evidence for an issued assertion
555-
func (ca *Handle) EvidenceFor(a mtc.Assertion) (*mtc.Evidence, error) {
555+
func (ca *Handle) EvidenceFor(a mtc.Assertion) (*mtc.EvidenceList, error) {
556556
aa := a.Abridge()
557557
var key [mtc.HashLen]byte
558558
err := aa.Key(key[:])
@@ -568,7 +568,7 @@ func (ca *Handle) EvidenceFor(a mtc.Assertion) (*mtc.Evidence, error) {
568568
return nil, fmt.Errorf("no assertion with key %x on record", key)
569569
}
570570

571-
var ev *mtc.Evidence
571+
var el *mtc.EvidenceList
572572
evFile, err := ca.evFileFor(res.Batch)
573573
if err != nil {
574574
return nil, err
@@ -577,15 +577,15 @@ func (ca *Handle) EvidenceFor(a mtc.Assertion) (*mtc.Evidence, error) {
577577
if err != nil {
578578
return nil, err
579579
}
580-
err = mtc.UnmarshalEvidenceEntries(evFile, func(_ int, ev2 *mtc.Evidence) error {
581-
ev = ev2
580+
err = mtc.UnmarshalEvidenceLists(evFile, func(_ int, el2 *mtc.EvidenceList) error {
581+
el = el2
582582
return errShortCircuit
583583
})
584584
if err != errShortCircuit {
585585
return nil, err
586586
}
587587

588-
return ev, nil
588+
return el, nil
589589
}
590590

591591
// Search for AbridgedAssertions's batch/seqno/offset/evidence_offset by key.

ca/index.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ func ComputeIndex(aaReader, evReader io.Reader, w io.Writer) error {
187187
})
188188

189189
seqno = uint64(0)
190-
err = mtc.UnmarshalEvidenceEntries(evReader, func(offset int, _ *mtc.Evidence) error {
190+
err = mtc.UnmarshalEvidenceLists(evReader, func(offset int, _ *mtc.EvidenceList) error {
191191
entries[seqno].evidenceOffset = uint64(offset)
192192
seqno++
193193
return nil

cmd/mtc/main.go

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ func assertionRequestFromFlagsUnchecked(cc *cli.Context) (*mtc.AssertionRequest,
189189

190190
var (
191191
a mtc.Assertion
192-
e mtc.Evidence
192+
el mtc.EvidenceList
193193
scheme mtc.SignatureScheme
194194
)
195195

@@ -250,8 +250,11 @@ func assertionRequestFromFlagsUnchecked(cc *cli.Context) (*mtc.AssertionRequest,
250250
return nil, fmt.Errorf("from-x509: %s", err)
251251
}
252252

253-
e.Type = mtc.X509ChainEvidenceType
254-
e.Info = mtc.X509ChainEvidenceInfo(certs)
253+
ev, err := mtc.NewX509ChainEvidence(certs)
254+
if err != nil {
255+
return nil, err
256+
}
257+
el = append(el, ev)
255258
}
256259

257260
// Setting any claim will overwrite those suggested by the
@@ -342,7 +345,7 @@ func assertionRequestFromFlagsUnchecked(cc *cli.Context) (*mtc.AssertionRequest,
342345

343346
return &mtc.AssertionRequest{
344347
Assertion: a,
345-
Evidence: e,
348+
Evidence: el,
346349
Checksum: checksum,
347350
}, nil
348351
}
@@ -498,7 +501,10 @@ func handleCaShowQueue(cc *cli.Context) error {
498501
if len(cs.IPv6) != 0 {
499502
fmt.Fprintf(w, "ip6\t%s\n", cs.IPv6)
500503
}
501-
writeEvidence(w, ar.Evidence)
504+
err = writeEvidenceList(w, ar.Evidence)
505+
if err != nil {
506+
return err
507+
}
502508
w.Flush()
503509
fmt.Printf("\n")
504510
return nil
@@ -712,26 +718,29 @@ func writeAssertion(w *tabwriter.Writer, a mtc.Assertion) {
712718
}
713719
}
714720

715-
func writeEvidence(w *tabwriter.Writer, e mtc.Evidence) {
716-
717-
fmt.Fprintf(w, "evidence\t")
718-
switch e.Type {
719-
case mtc.EmptyEvidenceType:
720-
fmt.Fprintf(w, "empty\n")
721-
case mtc.X509ChainEvidenceType:
722-
fmt.Fprintf(w, "x509_chain\n")
723-
for i, cert := range e.Info.(mtc.X509ChainEvidenceInfo) {
724-
fmt.Fprintf(w, " certificate\t%d\n", i)
725-
fmt.Fprintf(w, " subject\t%s\n", cert.Subject.String())
726-
fmt.Fprintf(w, " issuer\t%s\n", cert.Issuer.String())
727-
fmt.Fprintf(w, " serial_no\t%x\n", cert.SerialNumber)
728-
fmt.Fprintf(w, " not_before\t%s\n", cert.NotBefore)
729-
fmt.Fprintf(w, " not_after\t%s\n", cert.NotAfter)
721+
func writeEvidenceList(w *tabwriter.Writer, el mtc.EvidenceList) error {
722+
723+
for _, ev := range el {
724+
switch ev.Type() {
725+
case mtc.X509ChainEvidenceType:
726+
fmt.Fprintf(w, "x509_chain\n")
727+
chain, err := ev.(mtc.X509ChainEvidence).Chain()
728+
if err != nil {
729+
return err
730+
}
731+
for j, cert := range chain {
732+
fmt.Fprintf(w, " certificate\t%d\n", j)
733+
fmt.Fprintf(w, " subject\t%s\n", cert.Subject.String())
734+
fmt.Fprintf(w, " issuer\t%s\n", cert.Issuer.String())
735+
fmt.Fprintf(w, " serial_no\t%x\n", cert.SerialNumber)
736+
fmt.Fprintf(w, " not_before\t%s\n", cert.NotBefore)
737+
fmt.Fprintf(w, " not_after\t%s\n", cert.NotAfter)
738+
}
739+
default:
740+
fmt.Fprintf(w, "unknown type=%d info=%x\n", ev.Type(), ev.Info())
730741
}
731-
default:
732-
fmt.Fprintf(w, "unknown\n")
733-
fmt.Fprintf(w, " raw\t%x", e.Info.(mtc.UnknownEvidenceInfo))
734742
}
743+
return nil
735744
}
736745

737746
func handleInspectCert(cc *cli.Context) error {
@@ -820,7 +829,10 @@ func handleInspectAssertionRequest(cc *cli.Context) error {
820829
w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0)
821830
fmt.Fprintf(w, "checksum\t%x\n", ar.Checksum)
822831
writeAssertion(w, ar.Assertion)
823-
writeEvidence(w, ar.Evidence)
832+
err = writeEvidenceList(w, ar.Evidence)
833+
if err != nil {
834+
return err
835+
}
824836
w.Flush()
825837
return nil
826838
}
@@ -834,13 +846,14 @@ func handleInspectEvidence(cc *cli.Context) error {
834846
defer r.Close()
835847

836848
count := 0
837-
err = mtc.UnmarshalEvidenceEntries(
849+
err = mtc.UnmarshalEvidenceLists(
838850
bufio.NewReader(r),
839-
func(_ int, e *mtc.Evidence) error {
851+
func(_ int, el *mtc.EvidenceList) error {
840852
count++
841853
w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0)
842-
writeEvidence(w, *e)
854+
writeEvidenceList(w, *el)
843855
w.Flush()
856+
fmt.Printf("\n")
844857
return nil
845858
},
846859
)

http/server.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func (s *Server) Shutdown(ctx context.Context) error {
4444
return s.server.Shutdown(ctx)
4545
}
4646

47-
func assertionFromRequestUnchecked(r *http.Request) (*mtc.AssertionRequest, error) {
47+
func assertionRequestFromHTTPUnchecked(r *http.Request) (*mtc.AssertionRequest, error) {
4848
var (
4949
ar mtc.AssertionRequest
5050
)
@@ -65,8 +65,8 @@ func assertionFromRequestUnchecked(r *http.Request) (*mtc.AssertionRequest, erro
6565
}
6666
}
6767

68-
func assertionFromRequest(r *http.Request) (*mtc.AssertionRequest, error) {
69-
ar, err := assertionFromRequestUnchecked(r)
68+
func assertionRequestFromHTTP(r *http.Request) (*mtc.AssertionRequest, error) {
69+
ar, err := assertionRequestFromHTTPUnchecked(r)
7070
if err != nil {
7171
return nil, err
7272
}
@@ -87,7 +87,7 @@ func handleCaQueue(path string) func(w http.ResponseWriter, r *http.Request) {
8787
return
8888
}
8989
defer h.Close()
90-
a, err := assertionFromRequest(r)
90+
a, err := assertionRequestFromHTTP(r)
9191
if err != nil {
9292
http.Error(w, "invalid assertion", http.StatusBadRequest)
9393
return
@@ -110,7 +110,7 @@ func handleCaCert(path string) func(w http.ResponseWriter, r *http.Request) {
110110
return
111111
}
112112
defer h.Close()
113-
a, err := assertionFromRequest(r)
113+
a, err := assertionRequestFromHTTP(r)
114114
if err != nil {
115115
http.Error(w, "invalid assertion", http.StatusBadRequest)
116116
return

mtc.go

Lines changed: 59 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -57,20 +57,22 @@ type Claims struct {
5757
type EvidenceType uint16
5858

5959
const (
60-
EmptyEvidenceType EvidenceType = iota
61-
X509ChainEvidenceType
60+
X509ChainEvidenceType EvidenceType = iota
6261
)
6362

64-
type Evidence struct {
65-
Type EvidenceType
66-
Info EvidenceInfo
67-
}
63+
type EvidenceList []Evidence
6864

69-
type EvidenceInfo any
65+
type Evidence interface {
66+
Type() EvidenceType
67+
Info() []byte
68+
}
7069

71-
type X509ChainEvidenceInfo []*x509.Certificate
70+
type X509ChainEvidence []byte
7271

73-
type UnknownEvidenceInfo []byte
72+
type UnknownEvidence struct {
73+
typ EvidenceType
74+
info []byte
75+
}
7476

7577
// Represents a claim we do not how to interpret.
7678
type UnknownClaim struct {
@@ -122,7 +124,7 @@ type AbridgedAssertion struct {
122124
type AssertionRequest struct {
123125
Checksum []byte
124126
Assertion Assertion
125-
Evidence Evidence
127+
Evidence EvidenceList
126128
}
127129

128130
// Copy of tls.SignatureScheme to prevent cycling dependencies
@@ -924,6 +926,22 @@ func (a *AbridgedAssertion) unmarshal(s *cryptobyte.String) error {
924926
return nil
925927
}
926928

929+
func (e X509ChainEvidence) Type() EvidenceType { return X509ChainEvidenceType }
930+
func (e X509ChainEvidence) Info() []byte { return e }
931+
func (e X509ChainEvidence) Chain() ([]*x509.Certificate, error) {
932+
return x509.ParseCertificates(e)
933+
}
934+
func NewX509ChainEvidence(certs []*x509.Certificate) (X509ChainEvidence, error) {
935+
var b cryptobyte.Builder
936+
for _, cert := range certs {
937+
b.AddBytes(cert.Raw)
938+
}
939+
return b.Bytes()
940+
}
941+
942+
func (e UnknownEvidence) Type() EvidenceType { return e.typ }
943+
func (e UnknownEvidence) Info() []byte { return e.info }
944+
927945
func (ar *AssertionRequest) UnmarshalBinary(data []byte) error {
928946
var (
929947
s cryptobyte.String = cryptobyte.String(data)
@@ -1595,10 +1613,10 @@ func (c *Claims) MarshalBinary() ([]byte, error) {
15951613
return b.Bytes()
15961614
}
15971615

1598-
func (e *Evidence) UnmarshalBinary(data []byte) error {
1599-
*e = Evidence{}
1616+
func (el *EvidenceList) UnmarshalBinary(data []byte) error {
1617+
*el = EvidenceList{}
16001618
s := cryptobyte.String(data)
1601-
err := e.unmarshal(&s)
1619+
err := el.unmarshal(&s)
16021620
if err != nil {
16031621
return err
16041622
}
@@ -1608,68 +1626,64 @@ func (e *Evidence) UnmarshalBinary(data []byte) error {
16081626
return nil
16091627
}
16101628

1611-
func (e *Evidence) unmarshal(s *cryptobyte.String) error {
1629+
func (el *EvidenceList) unmarshal(s *cryptobyte.String) error {
16121630

16131631
var (
1632+
evidenceList cryptobyte.String
16141633
evidenceInfo cryptobyte.String
16151634
evidenceType EvidenceType
16161635
)
16171636

1618-
if !s.ReadUint16((*uint16)(&evidenceType)) ||
1619-
!s.ReadUint24LengthPrefixed(&evidenceInfo) {
1637+
if !s.ReadUint24LengthPrefixed(&evidenceList) {
16201638
return ErrTruncated
16211639
}
1622-
e.Type = evidenceType
1623-
switch e.Type {
1624-
case EmptyEvidenceType:
1625-
if !evidenceInfo.Empty() {
1626-
return errors.New("non-empty info for empty evidence")
1640+
1641+
for !evidenceList.Empty() {
1642+
if !evidenceList.ReadUint16((*uint16)(&evidenceType)) ||
1643+
!evidenceList.ReadUint24LengthPrefixed(&evidenceInfo) {
1644+
return ErrTruncated
16271645
}
1628-
case X509ChainEvidenceType:
1629-
chain, err := x509.ParseCertificates([]byte(evidenceInfo))
1630-
if err != nil {
1631-
return errors.New("failed to parse X.509 chain")
1646+
1647+
switch evidenceType {
1648+
case X509ChainEvidenceType:
1649+
*el = append(*el, X509ChainEvidence(evidenceInfo))
1650+
default:
1651+
*el = append(*el, UnknownEvidence{
1652+
typ: evidenceType,
1653+
info: evidenceInfo,
1654+
})
16321655
}
1633-
e.Info = X509ChainEvidenceInfo(chain)
1634-
default:
1635-
unknownInfo := make([]byte, len(evidenceInfo))
1636-
evidenceInfo.CopyBytes(unknownInfo)
1637-
e.Info = UnknownEvidenceInfo(unknownInfo)
16381656
}
16391657

16401658
return nil
16411659
}
16421660

1643-
func (e *Evidence) MarshalBinary() ([]byte, error) {
1661+
func (el *EvidenceList) MarshalBinary() ([]byte, error) {
16441662
var b cryptobyte.Builder
16451663

1646-
b.AddUint16(uint16(e.Type))
16471664
b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
1648-
switch e.Type {
1649-
case EmptyEvidenceType:
1650-
case X509ChainEvidenceType:
1651-
for _, cert := range e.Info.(X509ChainEvidenceInfo) {
1652-
b.AddBytes(cert.Raw)
1653-
}
1654-
default:
1655-
b.AddBytes(e.Info.(UnknownEvidenceInfo))
1665+
for _, e := range *el {
1666+
b.AddUint16(uint16(e.Type()))
1667+
b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
1668+
b.AddBytes(e.Info())
1669+
})
16561670
}
16571671
})
16581672

16591673
return b.Bytes()
16601674
}
16611675

1662-
// Unmarshals Evidence entries from r and calls f for each, with
1663-
// the offset in the stream as first argument, and the Evidence
1676+
// Unmarshals EvidenceLists from r and calls f for each, with
1677+
// the offset in the stream as first argument, and the EvidenceList
16641678
// as second argument.
16651679
//
16661680
// Returns early on error.
1667-
func UnmarshalEvidenceEntries(r io.Reader,
1668-
f func(int, *Evidence) error) error {
1681+
func UnmarshalEvidenceLists(r io.Reader,
1682+
f func(int, *EvidenceList) error) error {
16691683
return unmarshal(r, f)
16701684
}
16711685

1672-
func (e *Evidence) maxSize() int {
1686+
func (el *EvidenceList) maxSize() int {
16731687
return (65535+2)*2 + 2
16741688
}
16751689

0 commit comments

Comments
 (0)