...

Source file src/github.com/google/certificate-transparency-go/types.go

Documentation: github.com/google/certificate-transparency-go

     1  // Copyright 2015 Google LLC. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package ct holds core types and utilities for Certificate Transparency.
    16  package ct
    17  
    18  import (
    19  	"crypto/sha256"
    20  	"encoding/base64"
    21  	"encoding/json"
    22  	"fmt"
    23  
    24  	"github.com/google/certificate-transparency-go/tls"
    25  	"github.com/google/certificate-transparency-go/x509"
    26  )
    27  
    28  ///////////////////////////////////////////////////////////////////////////////
    29  // The following structures represent those outlined in RFC6962; any section
    30  // numbers mentioned refer to that RFC.
    31  ///////////////////////////////////////////////////////////////////////////////
    32  
    33  // LogEntryType represents the LogEntryType enum from section 3.1:
    34  //
    35  //	enum { x509_entry(0), precert_entry(1), (65535) } LogEntryType;
    36  type LogEntryType tls.Enum // tls:"maxval:65535"
    37  
    38  // LogEntryType constants from section 3.1.
    39  const (
    40  	X509LogEntryType    LogEntryType = 0
    41  	PrecertLogEntryType LogEntryType = 1
    42  )
    43  
    44  func (e LogEntryType) String() string {
    45  	switch e {
    46  	case X509LogEntryType:
    47  		return "X509LogEntryType"
    48  	case PrecertLogEntryType:
    49  		return "PrecertLogEntryType"
    50  	default:
    51  		return fmt.Sprintf("UnknownEntryType(%d)", e)
    52  	}
    53  }
    54  
    55  // RFC6962 section 2.1 requires a prefix byte on hash inputs for second preimage resistance.
    56  const (
    57  	TreeLeafPrefix = byte(0x00)
    58  	TreeNodePrefix = byte(0x01)
    59  )
    60  
    61  // MerkleLeafType represents the MerkleLeafType enum from section 3.4:
    62  //
    63  //	enum { timestamped_entry(0), (255) } MerkleLeafType;
    64  type MerkleLeafType tls.Enum // tls:"maxval:255"
    65  
    66  // TimestampedEntryLeafType is the only defined MerkleLeafType constant from section 3.4.
    67  const TimestampedEntryLeafType MerkleLeafType = 0 // Entry type for an SCT
    68  
    69  func (m MerkleLeafType) String() string {
    70  	switch m {
    71  	case TimestampedEntryLeafType:
    72  		return "TimestampedEntryLeafType"
    73  	default:
    74  		return fmt.Sprintf("UnknownLeafType(%d)", m)
    75  	}
    76  }
    77  
    78  // Version represents the Version enum from section 3.2:
    79  //
    80  //	enum { v1(0), (255) } Version;
    81  type Version tls.Enum // tls:"maxval:255"
    82  
    83  // CT Version constants from section 3.2.
    84  const (
    85  	V1 Version = 0
    86  )
    87  
    88  func (v Version) String() string {
    89  	switch v {
    90  	case V1:
    91  		return "V1"
    92  	default:
    93  		return fmt.Sprintf("UnknownVersion(%d)", v)
    94  	}
    95  }
    96  
    97  // SignatureType differentiates STH signatures from SCT signatures, see section 3.2.
    98  //
    99  //	enum { certificate_timestamp(0), tree_hash(1), (255) } SignatureType;
   100  type SignatureType tls.Enum // tls:"maxval:255"
   101  
   102  // SignatureType constants from section 3.2.
   103  const (
   104  	CertificateTimestampSignatureType SignatureType = 0
   105  	TreeHashSignatureType             SignatureType = 1
   106  )
   107  
   108  func (st SignatureType) String() string {
   109  	switch st {
   110  	case CertificateTimestampSignatureType:
   111  		return "CertificateTimestamp"
   112  	case TreeHashSignatureType:
   113  		return "TreeHash"
   114  	default:
   115  		return fmt.Sprintf("UnknownSignatureType(%d)", st)
   116  	}
   117  }
   118  
   119  // ASN1Cert type for holding the raw DER bytes of an ASN.1 Certificate
   120  // (section 3.1).
   121  type ASN1Cert struct {
   122  	Data []byte `tls:"minlen:1,maxlen:16777215"`
   123  }
   124  
   125  // LogID holds the hash of the Log's public key (section 3.2).
   126  // TODO(pphaneuf): Users should be migrated to the one in the logid package.
   127  type LogID struct {
   128  	KeyID [sha256.Size]byte
   129  }
   130  
   131  // PreCert represents a Precertificate (section 3.2).
   132  type PreCert struct {
   133  	IssuerKeyHash  [sha256.Size]byte
   134  	TBSCertificate []byte `tls:"minlen:1,maxlen:16777215"` // DER-encoded TBSCertificate
   135  }
   136  
   137  // CTExtensions is a representation of the raw bytes of any CtExtension
   138  // structure (see section 3.2).
   139  // nolint: revive
   140  type CTExtensions []byte // tls:"minlen:0,maxlen:65535"`
   141  
   142  // MerkleTreeNode represents an internal node in the CT tree.
   143  type MerkleTreeNode []byte
   144  
   145  // ConsistencyProof represents a CT consistency proof (see sections 2.1.2 and
   146  // 4.4).
   147  type ConsistencyProof []MerkleTreeNode
   148  
   149  // AuditPath represents a CT inclusion proof (see sections 2.1.1 and 4.5).
   150  type AuditPath []MerkleTreeNode
   151  
   152  // LeafInput represents a serialized MerkleTreeLeaf structure.
   153  type LeafInput []byte
   154  
   155  // DigitallySigned is a local alias for tls.DigitallySigned so that we can
   156  // attach a MarshalJSON method.
   157  type DigitallySigned tls.DigitallySigned
   158  
   159  // FromBase64String populates the DigitallySigned structure from the base64 data passed in.
   160  // Returns an error if the base64 data is invalid.
   161  func (d *DigitallySigned) FromBase64String(b64 string) error {
   162  	raw, err := base64.StdEncoding.DecodeString(b64)
   163  	if err != nil {
   164  		return fmt.Errorf("failed to unbase64 DigitallySigned: %v", err)
   165  	}
   166  	var ds tls.DigitallySigned
   167  	if rest, err := tls.Unmarshal(raw, &ds); err != nil {
   168  		return fmt.Errorf("failed to unmarshal DigitallySigned: %v", err)
   169  	} else if len(rest) > 0 {
   170  		return fmt.Errorf("trailing data (%d bytes) after DigitallySigned", len(rest))
   171  	}
   172  	*d = DigitallySigned(ds)
   173  	return nil
   174  }
   175  
   176  // Base64String returns the base64 representation of the DigitallySigned struct.
   177  func (d DigitallySigned) Base64String() (string, error) {
   178  	b, err := tls.Marshal(d)
   179  	if err != nil {
   180  		return "", err
   181  	}
   182  	return base64.StdEncoding.EncodeToString(b), nil
   183  }
   184  
   185  // MarshalJSON implements the json.Marshaller interface.
   186  func (d DigitallySigned) MarshalJSON() ([]byte, error) {
   187  	b64, err := d.Base64String()
   188  	if err != nil {
   189  		return []byte{}, err
   190  	}
   191  	return []byte(`"` + b64 + `"`), nil
   192  }
   193  
   194  // UnmarshalJSON implements the json.Unmarshaler interface.
   195  func (d *DigitallySigned) UnmarshalJSON(b []byte) error {
   196  	var content string
   197  	if err := json.Unmarshal(b, &content); err != nil {
   198  		return fmt.Errorf("failed to unmarshal DigitallySigned: %v", err)
   199  	}
   200  	return d.FromBase64String(content)
   201  }
   202  
   203  // RawLogEntry represents the (TLS-parsed) contents of an entry in a CT log.
   204  type RawLogEntry struct {
   205  	// Index is a position of the entry in the log.
   206  	Index int64
   207  	// Leaf is a parsed Merkle leaf hash input.
   208  	Leaf MerkleTreeLeaf
   209  	// Cert is:
   210  	// - A certificate if Leaf.TimestampedEntry.EntryType is X509LogEntryType.
   211  	// - A precertificate if Leaf.TimestampedEntry.EntryType is
   212  	//   PrecertLogEntryType, in the form of a DER-encoded Certificate as
   213  	//   originally added (which includes the poison extension and a signature
   214  	//   generated over the pre-cert by the pre-cert issuer).
   215  	// - Empty otherwise.
   216  	Cert ASN1Cert
   217  	// Chain is the issuing certificate chain starting with the issuer of Cert,
   218  	// or an empty slice if Cert is empty.
   219  	Chain []ASN1Cert
   220  }
   221  
   222  // LogEntry represents the (parsed) contents of an entry in a CT log.  This is described
   223  // in section 3.1, but note that this structure does *not* match the TLS structure
   224  // defined there (the TLS structure is never used directly in RFC6962).
   225  type LogEntry struct {
   226  	Index int64
   227  	Leaf  MerkleTreeLeaf
   228  	// Exactly one of the following three fields should be non-empty.
   229  	X509Cert *x509.Certificate // Parsed X.509 certificate
   230  	Precert  *Precertificate   // Extracted precertificate
   231  	JSONData []byte
   232  
   233  	// Chain holds the issuing certificate chain, starting with the
   234  	// issuer of the leaf certificate / pre-certificate.
   235  	Chain []ASN1Cert
   236  }
   237  
   238  // PrecertChainEntry holds an precertificate together with a validation chain
   239  // for it; see section 3.1.
   240  type PrecertChainEntry struct {
   241  	PreCertificate   ASN1Cert   `tls:"minlen:1,maxlen:16777215"`
   242  	CertificateChain []ASN1Cert `tls:"minlen:0,maxlen:16777215"`
   243  }
   244  
   245  // CertificateChain holds a chain of certificates, as returned as extra data
   246  // for get-entries (section 4.6).
   247  type CertificateChain struct {
   248  	Entries []ASN1Cert `tls:"minlen:0,maxlen:16777215"`
   249  }
   250  
   251  // JSONDataEntry holds arbitrary data.
   252  type JSONDataEntry struct {
   253  	Data []byte `tls:"minlen:0,maxlen:1677215"`
   254  }
   255  
   256  // SHA256Hash represents the output from the SHA256 hash function.
   257  type SHA256Hash [sha256.Size]byte
   258  
   259  // FromBase64String populates the SHA256 struct with the contents of the base64 data passed in.
   260  func (s *SHA256Hash) FromBase64String(b64 string) error {
   261  	bs, err := base64.StdEncoding.DecodeString(b64)
   262  	if err != nil {
   263  		return fmt.Errorf("failed to unbase64 LogID: %v", err)
   264  	}
   265  	if len(bs) != sha256.Size {
   266  		return fmt.Errorf("invalid SHA256 length, expected 32 but got %d", len(bs))
   267  	}
   268  	copy(s[:], bs)
   269  	return nil
   270  }
   271  
   272  // Base64String returns the base64 representation of this SHA256Hash.
   273  func (s SHA256Hash) Base64String() string {
   274  	return base64.StdEncoding.EncodeToString(s[:])
   275  }
   276  
   277  // MarshalJSON implements the json.Marshaller interface for SHA256Hash.
   278  func (s SHA256Hash) MarshalJSON() ([]byte, error) {
   279  	return []byte(`"` + s.Base64String() + `"`), nil
   280  }
   281  
   282  // UnmarshalJSON implements the json.Unmarshaller interface.
   283  func (s *SHA256Hash) UnmarshalJSON(b []byte) error {
   284  	var content string
   285  	if err := json.Unmarshal(b, &content); err != nil {
   286  		return fmt.Errorf("failed to unmarshal SHA256Hash: %v", err)
   287  	}
   288  	return s.FromBase64String(content)
   289  }
   290  
   291  // SignedTreeHead represents the structure returned by the get-sth CT method
   292  // after base64 decoding; see sections 3.5 and 4.3.
   293  type SignedTreeHead struct {
   294  	Version           Version         `json:"sth_version"`         // The version of the protocol to which the STH conforms
   295  	TreeSize          uint64          `json:"tree_size"`           // The number of entries in the new tree
   296  	Timestamp         uint64          `json:"timestamp"`           // The time at which the STH was created
   297  	SHA256RootHash    SHA256Hash      `json:"sha256_root_hash"`    // The root hash of the log's Merkle tree
   298  	TreeHeadSignature DigitallySigned `json:"tree_head_signature"` // Log's signature over a TLS-encoded TreeHeadSignature
   299  	LogID             SHA256Hash      `json:"log_id"`              // The SHA256 hash of the log's public key
   300  }
   301  
   302  func (s SignedTreeHead) String() string {
   303  	sigStr, err := s.TreeHeadSignature.Base64String()
   304  	if err != nil {
   305  		sigStr = tls.DigitallySigned(s.TreeHeadSignature).String()
   306  	}
   307  
   308  	// If the LogID field in the SignedTreeHead is empty, don't include it in
   309  	// the string.
   310  	var logIDStr string
   311  	if id, empty := s.LogID, (SHA256Hash{}); id != empty {
   312  		logIDStr = fmt.Sprintf("LogID:%s, ", id.Base64String())
   313  	}
   314  
   315  	return fmt.Sprintf("{%sTreeSize:%d, Timestamp:%d, SHA256RootHash:%q, TreeHeadSignature:%q}",
   316  		logIDStr, s.TreeSize, s.Timestamp, s.SHA256RootHash.Base64String(), sigStr)
   317  }
   318  
   319  // TreeHeadSignature holds the data over which the signature in an STH is
   320  // generated; see section 3.5
   321  type TreeHeadSignature struct {
   322  	Version        Version       `tls:"maxval:255"`
   323  	SignatureType  SignatureType `tls:"maxval:255"` // == TreeHashSignatureType
   324  	Timestamp      uint64
   325  	TreeSize       uint64
   326  	SHA256RootHash SHA256Hash
   327  }
   328  
   329  // SignedCertificateTimestamp represents the structure returned by the
   330  // add-chain and add-pre-chain methods after base64 decoding; see sections
   331  // 3.2, 4.1 and 4.2.
   332  type SignedCertificateTimestamp struct {
   333  	SCTVersion Version `tls:"maxval:255"`
   334  	LogID      LogID
   335  	Timestamp  uint64
   336  	Extensions CTExtensions    `tls:"minlen:0,maxlen:65535"`
   337  	Signature  DigitallySigned // Signature over TLS-encoded CertificateTimestamp
   338  }
   339  
   340  // CertificateTimestamp is the collection of data that the signature in an
   341  // SCT is over; see section 3.2.
   342  type CertificateTimestamp struct {
   343  	SCTVersion    Version       `tls:"maxval:255"`
   344  	SignatureType SignatureType `tls:"maxval:255"`
   345  	Timestamp     uint64
   346  	EntryType     LogEntryType   `tls:"maxval:65535"`
   347  	X509Entry     *ASN1Cert      `tls:"selector:EntryType,val:0"`
   348  	PrecertEntry  *PreCert       `tls:"selector:EntryType,val:1"`
   349  	JSONEntry     *JSONDataEntry `tls:"selector:EntryType,val:32768"`
   350  	Extensions    CTExtensions   `tls:"minlen:0,maxlen:65535"`
   351  }
   352  
   353  func (s SignedCertificateTimestamp) String() string {
   354  	return fmt.Sprintf("{Version:%d LogId:%s Timestamp:%d Extensions:'%s' Signature:%v}", s.SCTVersion,
   355  		base64.StdEncoding.EncodeToString(s.LogID.KeyID[:]),
   356  		s.Timestamp,
   357  		s.Extensions,
   358  		s.Signature)
   359  }
   360  
   361  // TimestampedEntry is part of the MerkleTreeLeaf structure; see section 3.4.
   362  type TimestampedEntry struct {
   363  	Timestamp    uint64
   364  	EntryType    LogEntryType   `tls:"maxval:65535"`
   365  	X509Entry    *ASN1Cert      `tls:"selector:EntryType,val:0"`
   366  	PrecertEntry *PreCert       `tls:"selector:EntryType,val:1"`
   367  	JSONEntry    *JSONDataEntry `tls:"selector:EntryType,val:32768"`
   368  	Extensions   CTExtensions   `tls:"minlen:0,maxlen:65535"`
   369  }
   370  
   371  // MerkleTreeLeaf represents the deserialized structure of the hash input for the
   372  // leaves of a log's Merkle tree; see section 3.4.
   373  type MerkleTreeLeaf struct {
   374  	Version          Version           `tls:"maxval:255"`
   375  	LeafType         MerkleLeafType    `tls:"maxval:255"`
   376  	TimestampedEntry *TimestampedEntry `tls:"selector:LeafType,val:0"`
   377  }
   378  
   379  // Precertificate represents the parsed CT Precertificate structure.
   380  type Precertificate struct {
   381  	// DER-encoded pre-certificate as originally added, which includes a
   382  	// poison extension and a signature generated over the pre-cert by
   383  	// the pre-cert issuer (which might differ from the issuer of the final
   384  	// cert, see RFC6962 s3.1).
   385  	Submitted ASN1Cert
   386  	// SHA256 hash of the issuing key
   387  	IssuerKeyHash [sha256.Size]byte
   388  	// Parsed TBSCertificate structure, held in an x509.Certificate for convenience.
   389  	TBSCertificate *x509.Certificate
   390  }
   391  
   392  // X509Certificate returns the X.509 Certificate contained within the
   393  // MerkleTreeLeaf.
   394  func (m *MerkleTreeLeaf) X509Certificate() (*x509.Certificate, error) {
   395  	if m.TimestampedEntry.EntryType != X509LogEntryType {
   396  		return nil, fmt.Errorf("cannot call X509Certificate on a MerkleTreeLeaf that is not an X509 entry")
   397  	}
   398  	return x509.ParseCertificate(m.TimestampedEntry.X509Entry.Data)
   399  }
   400  
   401  // Precertificate returns the X.509 Precertificate contained within the MerkleTreeLeaf.
   402  //
   403  // The returned precertificate is embedded in an x509.Certificate, but is in the
   404  // form stored internally in the log rather than the original submitted form
   405  // (i.e. it does not include the poison extension and any changes to reflect the
   406  // final certificate's issuer have been made; see x509.BuildPrecertTBS).
   407  func (m *MerkleTreeLeaf) Precertificate() (*x509.Certificate, error) {
   408  	if m.TimestampedEntry.EntryType != PrecertLogEntryType {
   409  		return nil, fmt.Errorf("cannot call Precertificate on a MerkleTreeLeaf that is not a precert entry")
   410  	}
   411  	return x509.ParseTBSCertificate(m.TimestampedEntry.PrecertEntry.TBSCertificate)
   412  }
   413  
   414  // APIEndpoint is a string that represents one of the Certificate Transparency
   415  // Log API endpoints.
   416  type APIEndpoint string
   417  
   418  // Certificate Transparency Log API endpoints; see section 4.
   419  // WARNING: Should match the URI paths without the "/ct/v1/" prefix.  If
   420  // changing these constants, may need to change those too.
   421  const (
   422  	AddChainStr          APIEndpoint = "add-chain"
   423  	AddPreChainStr       APIEndpoint = "add-pre-chain"
   424  	GetSTHStr            APIEndpoint = "get-sth"
   425  	GetEntriesStr        APIEndpoint = "get-entries"
   426  	GetProofByHashStr    APIEndpoint = "get-proof-by-hash"
   427  	GetSTHConsistencyStr APIEndpoint = "get-sth-consistency"
   428  	GetRootsStr          APIEndpoint = "get-roots"
   429  	GetEntryAndProofStr  APIEndpoint = "get-entry-and-proof"
   430  )
   431  
   432  // URI paths for Log requests; see section 4.
   433  // WARNING: Should match the API endpoints, with the "/ct/v1/" prefix.  If
   434  // changing these constants, may need to change those too.
   435  const (
   436  	AddChainPath          = "/ct/v1/add-chain"
   437  	AddPreChainPath       = "/ct/v1/add-pre-chain"
   438  	GetSTHPath            = "/ct/v1/get-sth"
   439  	GetEntriesPath        = "/ct/v1/get-entries"
   440  	GetProofByHashPath    = "/ct/v1/get-proof-by-hash"
   441  	GetSTHConsistencyPath = "/ct/v1/get-sth-consistency"
   442  	GetRootsPath          = "/ct/v1/get-roots"
   443  	GetEntryAndProofPath  = "/ct/v1/get-entry-and-proof"
   444  
   445  	AddJSONPath = "/ct/v1/add-json" // Experimental addition
   446  )
   447  
   448  // AddChainRequest represents the JSON request body sent to the add-chain and
   449  // add-pre-chain POST methods from sections 4.1 and 4.2.
   450  type AddChainRequest struct {
   451  	Chain [][]byte `json:"chain"`
   452  }
   453  
   454  // AddChainResponse represents the JSON response to the add-chain and
   455  // add-pre-chain POST methods.
   456  // An SCT represents a Log's promise to integrate a [pre-]certificate into the
   457  // log within a defined period of time.
   458  type AddChainResponse struct {
   459  	SCTVersion Version `json:"sct_version"` // SCT structure version
   460  	ID         []byte  `json:"id"`          // Log ID
   461  	Timestamp  uint64  `json:"timestamp"`   // Timestamp of issuance
   462  	Extensions string  `json:"extensions"`  // Holder for any CT extensions
   463  	Signature  []byte  `json:"signature"`   // Log signature for this SCT
   464  }
   465  
   466  // ToSignedCertificateTimestamp creates a SignedCertificateTimestamp from the
   467  // AddChainResponse.
   468  func (r *AddChainResponse) ToSignedCertificateTimestamp() (*SignedCertificateTimestamp, error) {
   469  	sct := SignedCertificateTimestamp{
   470  		SCTVersion: r.SCTVersion,
   471  		Timestamp:  r.Timestamp,
   472  	}
   473  
   474  	if len(r.ID) != sha256.Size {
   475  		return nil, fmt.Errorf("id is invalid length, expected %d got %d", sha256.Size, len(r.ID))
   476  	}
   477  	copy(sct.LogID.KeyID[:], r.ID)
   478  
   479  	exts, err := base64.StdEncoding.DecodeString(r.Extensions)
   480  	if err != nil {
   481  		return nil, fmt.Errorf("invalid base64 data in Extensions (%q): %v", r.Extensions, err)
   482  	}
   483  	sct.Extensions = CTExtensions(exts)
   484  
   485  	var ds DigitallySigned
   486  	if rest, err := tls.Unmarshal(r.Signature, &ds); err != nil {
   487  		return nil, fmt.Errorf("tls.Unmarshal(): %s", err)
   488  	} else if len(rest) > 0 {
   489  		return nil, fmt.Errorf("trailing data (%d bytes) after DigitallySigned", len(rest))
   490  	}
   491  	sct.Signature = ds
   492  
   493  	return &sct, nil
   494  }
   495  
   496  // AddJSONRequest represents the JSON request body sent to the add-json POST method.
   497  // The corresponding response re-uses AddChainResponse.
   498  // This is an experimental addition not covered by RFC6962.
   499  type AddJSONRequest struct {
   500  	Data interface{} `json:"data"`
   501  }
   502  
   503  // GetSTHResponse represents the JSON response to the get-sth GET method from section 4.3.
   504  type GetSTHResponse struct {
   505  	TreeSize          uint64 `json:"tree_size"`           // Number of certs in the current tree
   506  	Timestamp         uint64 `json:"timestamp"`           // Time that the tree was created
   507  	SHA256RootHash    []byte `json:"sha256_root_hash"`    // Root hash of the tree
   508  	TreeHeadSignature []byte `json:"tree_head_signature"` // Log signature for this STH
   509  }
   510  
   511  // ToSignedTreeHead creates a SignedTreeHead from the GetSTHResponse.
   512  func (r *GetSTHResponse) ToSignedTreeHead() (*SignedTreeHead, error) {
   513  	sth := SignedTreeHead{
   514  		TreeSize:  r.TreeSize,
   515  		Timestamp: r.Timestamp,
   516  	}
   517  
   518  	if len(r.SHA256RootHash) != sha256.Size {
   519  		return nil, fmt.Errorf("sha256_root_hash is invalid length, expected %d got %d", sha256.Size, len(r.SHA256RootHash))
   520  	}
   521  	copy(sth.SHA256RootHash[:], r.SHA256RootHash)
   522  
   523  	var ds DigitallySigned
   524  	if rest, err := tls.Unmarshal(r.TreeHeadSignature, &ds); err != nil {
   525  		return nil, fmt.Errorf("tls.Unmarshal(): %s", err)
   526  	} else if len(rest) > 0 {
   527  		return nil, fmt.Errorf("trailing data (%d bytes) after DigitallySigned", len(rest))
   528  	}
   529  	sth.TreeHeadSignature = ds
   530  
   531  	return &sth, nil
   532  }
   533  
   534  // GetSTHConsistencyResponse represents the JSON response to the get-sth-consistency
   535  // GET method from section 4.4.  (The corresponding GET request has parameters 'first' and
   536  // 'second'.)
   537  type GetSTHConsistencyResponse struct {
   538  	Consistency [][]byte `json:"consistency"`
   539  }
   540  
   541  // GetProofByHashResponse represents the JSON response to the get-proof-by-hash GET
   542  // method from section 4.5.  (The corresponding GET request has parameters 'hash'
   543  // and 'tree_size'.)
   544  type GetProofByHashResponse struct {
   545  	LeafIndex int64    `json:"leaf_index"` // The 0-based index of the end entity corresponding to the "hash" parameter.
   546  	AuditPath [][]byte `json:"audit_path"` // An array of base64-encoded Merkle Tree nodes proving the inclusion of the chosen certificate.
   547  }
   548  
   549  // LeafEntry represents a leaf in the Log's Merkle tree, as returned by the get-entries
   550  // GET method from section 4.6.
   551  type LeafEntry struct {
   552  	// LeafInput is a TLS-encoded MerkleTreeLeaf
   553  	LeafInput []byte `json:"leaf_input"`
   554  	// ExtraData holds (unsigned) extra data, normally the cert validation chain.
   555  	ExtraData []byte `json:"extra_data"`
   556  }
   557  
   558  // GetEntriesResponse represents the JSON response to the get-entries GET method
   559  // from section 4.6.
   560  type GetEntriesResponse struct {
   561  	Entries []LeafEntry `json:"entries"` // the list of returned entries
   562  }
   563  
   564  // GetRootsResponse represents the JSON response to the get-roots GET method from section 4.7.
   565  type GetRootsResponse struct {
   566  	Certificates []string `json:"certificates"`
   567  }
   568  
   569  // GetEntryAndProofResponse represents the JSON response to the get-entry-and-proof
   570  // GET method from section 4.8. (The corresponding GET request has parameters 'leaf_index'
   571  // and 'tree_size'.)
   572  type GetEntryAndProofResponse struct {
   573  	LeafInput []byte   `json:"leaf_input"` // the entry itself
   574  	ExtraData []byte   `json:"extra_data"` // any chain provided when the entry was added to the log
   575  	AuditPath [][]byte `json:"audit_path"` // the corresponding proof
   576  }
   577  

View as plain text