@@ -75,8 +75,18 @@ type LogEntry struct {
7575
7676 // LeafIndex is the zero-based index of the leaf in the log.
7777 // It must be between 0 and 2^40-1.
78+ //
79+ // If RFC6962ArchivalLeaf is true, this field is ignored and
80+ // should be set to 0.
7881 LeafIndex int64
7982
83+ // RFC6962ArchivalLeaf is true if this LogEntry is an archived
84+ // RFC 6962 log leaf, which is missing the leaf index extension.
85+ //
86+ // [ReadTileLeaf] always sets this to false. To read such leaves,
87+ // use [ReadTileLeafMaybeArchival].
88+ RFC6962ArchivalLeaf bool
89+
8090 // Timestamp is the TimestampedEntry.timestamp.
8191 Timestamp int64
8292}
@@ -107,7 +117,7 @@ func (e *LogEntry) MerkleTreeLeaf() []byte {
107117 b .AddBytes (e .Certificate )
108118 })
109119 }
110- addExtensions (b , e . LeafIndex )
120+ addExtensions (b , e )
111121 return b .BytesOrPanic ()
112122}
113123
@@ -125,6 +135,26 @@ func (e *LogEntry) MerkleTreeLeaf() []byte {
125135// ReadTileLeaf reads a LogEntry from a data tile, and returns the remaining
126136// data in the tile.
127137func ReadTileLeaf (tile []byte ) (e * LogEntry , rest []byte , err error ) {
138+ e , rest , err = readTileLeaf (tile )
139+ if err != nil {
140+ return nil , rest , err
141+ }
142+ if e .RFC6962ArchivalLeaf {
143+ return nil , rest , fmt .Errorf ("leaf is missing leaf index extension" )
144+ }
145+ return e , rest , nil
146+ }
147+
148+ // ReadTileLeafMaybeArchival reads a LogEntry from a data tile, and returns the
149+ // remaining data in the tile.
150+ //
151+ // If the leaf is missing the leaf index extension, the returned LogEntry has
152+ // RFC6962ArchivalLeaf set to true, and LeafIndex set to zero.
153+ func ReadTileLeafMaybeArchival (tile []byte ) (e * LogEntry , rest []byte , err error ) {
154+ return readTileLeaf (tile )
155+ }
156+
157+ func readTileLeaf (tile []byte ) (e * LogEntry , rest []byte , err error ) {
128158 e = & LogEntry {}
129159 s := cryptobyte .String (tile )
130160 var timestamp uint64
@@ -153,13 +183,17 @@ func ReadTileLeaf(tile []byte) (e *LogEntry, rest []byte, err error) {
153183 default :
154184 return nil , s , fmt .Errorf ("invalid data tile: unknown type %d" , entryType )
155185 }
156- var extensionType uint8
157- var extensionData cryptobyte.String
158- if ! extensions .ReadUint8 (& extensionType ) || extensionType != 0 ||
159- ! extensions .ReadUint16LengthPrefixed (& extensionData ) ||
160- ! readUint40 (& extensionData , & e .LeafIndex ) || ! extensionData .Empty () ||
161- ! extensions .Empty () {
162- return nil , s , fmt .Errorf ("invalid data tile extensions" )
186+ if extensions .Empty () {
187+ e .RFC6962ArchivalLeaf = true
188+ } else {
189+ var extensionType uint8
190+ var extensionData cryptobyte.String
191+ if ! extensions .ReadUint8 (& extensionType ) || extensionType != 0 ||
192+ ! extensions .ReadUint16LengthPrefixed (& extensionData ) ||
193+ ! readUint40 (& extensionData , & e .LeafIndex ) || ! extensionData .Empty () ||
194+ ! extensions .Empty () {
195+ return nil , s , fmt .Errorf ("invalid data tile extensions" )
196+ }
163197 }
164198 for ! fingerprints .Empty () {
165199 var f [32 ]byte
@@ -187,7 +221,7 @@ func AppendTileLeaf(t []byte, e *LogEntry) []byte {
187221 b .AddBytes (e .Certificate )
188222 })
189223 }
190- addExtensions (b , e . LeafIndex )
224+ addExtensions (b , e )
191225 if e .IsPrecert {
192226 b .AddUint24LengthPrefixed (func (b * cryptobyte.Builder ) {
193227 b .AddBytes (e .PreCertificate )
@@ -201,9 +235,13 @@ func AppendTileLeaf(t []byte, e *LogEntry) []byte {
201235 return b .BytesOrPanic ()
202236}
203237
204- func addExtensions (b * cryptobyte.Builder , leafIndex int64 ) {
238+ func addExtensions (b * cryptobyte.Builder , e * LogEntry ) {
239+ if e .RFC6962ArchivalLeaf {
240+ b .AddUint16 (0 )
241+ return
242+ }
205243 b .AddUint16LengthPrefixed (func (b * cryptobyte.Builder ) {
206- ext , err := MarshalExtensions (Extensions {LeafIndex : leafIndex })
244+ ext , err := MarshalExtensions (Extensions {LeafIndex : e . LeafIndex })
207245 if err != nil {
208246 b .SetError (err )
209247 return
0 commit comments