2018-06-17 07:32:44 +00:00
|
|
|
// Copyright 2015 Google Inc. All Rights Reserved.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
// Package ct holds core types and utilities for Certificate Transparency.
|
|
|
|
package ct
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/sha256"
|
|
|
|
"encoding/base64"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/google/certificate-transparency-go/tls"
|
|
|
|
"github.com/google/certificate-transparency-go/x509"
|
|
|
|
)
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// The following structures represent those outlined in RFC6962; any section
|
|
|
|
// numbers mentioned refer to that RFC.
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// LogEntryType represents the LogEntryType enum from section 3.1:
|
|
|
|
// enum { x509_entry(0), precert_entry(1), (65535) } LogEntryType;
|
|
|
|
type LogEntryType tls.Enum // tls:"maxval:65535"
|
|
|
|
|
|
|
|
// LogEntryType constants from section 3.1.
|
|
|
|
const (
|
|
|
|
X509LogEntryType LogEntryType = 0
|
|
|
|
PrecertLogEntryType LogEntryType = 1
|
|
|
|
XJSONLogEntryType LogEntryType = 0x8000 // Experimental. Don't rely on this!
|
|
|
|
)
|
|
|
|
|
|
|
|
func (e LogEntryType) String() string {
|
|
|
|
switch e {
|
|
|
|
case X509LogEntryType:
|
|
|
|
return "X509LogEntryType"
|
|
|
|
case PrecertLogEntryType:
|
|
|
|
return "PrecertLogEntryType"
|
|
|
|
case XJSONLogEntryType:
|
|
|
|
return "XJSONLogEntryType"
|
|
|
|
default:
|
|
|
|
return fmt.Sprintf("UnknownEntryType(%d)", e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-03 07:25:07 +00:00
|
|
|
// RFC6962 section 2.1 requires a prefix byte on hash inputs for second preimage resistance.
|
|
|
|
const (
|
|
|
|
TreeLeafPrefix = byte(0x00)
|
|
|
|
TreeNodePrefix = byte(0x01)
|
|
|
|
)
|
|
|
|
|
2018-06-17 07:32:44 +00:00
|
|
|
// MerkleLeafType represents the MerkleLeafType enum from section 3.4:
|
|
|
|
// enum { timestamped_entry(0), (255) } MerkleLeafType;
|
|
|
|
type MerkleLeafType tls.Enum // tls:"maxval:255"
|
|
|
|
|
|
|
|
// TimestampedEntryLeafType is the only defined MerkleLeafType constant from section 3.4.
|
|
|
|
const TimestampedEntryLeafType MerkleLeafType = 0 // Entry type for an SCT
|
|
|
|
|
|
|
|
func (m MerkleLeafType) String() string {
|
|
|
|
switch m {
|
|
|
|
case TimestampedEntryLeafType:
|
|
|
|
return "TimestampedEntryLeafType"
|
|
|
|
default:
|
|
|
|
return fmt.Sprintf("UnknownLeafType(%d)", m)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Version represents the Version enum from section 3.2:
|
|
|
|
// enum { v1(0), (255) } Version;
|
|
|
|
type Version tls.Enum // tls:"maxval:255"
|
|
|
|
|
|
|
|
// CT Version constants from section 3.2.
|
|
|
|
const (
|
|
|
|
V1 Version = 0
|
|
|
|
)
|
|
|
|
|
|
|
|
func (v Version) String() string {
|
|
|
|
switch v {
|
|
|
|
case V1:
|
|
|
|
return "V1"
|
|
|
|
default:
|
|
|
|
return fmt.Sprintf("UnknownVersion(%d)", v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// SignatureType differentiates STH signatures from SCT signatures, see section 3.2.
|
|
|
|
// enum { certificate_timestamp(0), tree_hash(1), (255) } SignatureType;
|
|
|
|
type SignatureType tls.Enum // tls:"maxval:255"
|
|
|
|
|
|
|
|
// SignatureType constants from section 3.2.
|
|
|
|
const (
|
|
|
|
CertificateTimestampSignatureType SignatureType = 0
|
|
|
|
TreeHashSignatureType SignatureType = 1
|
|
|
|
)
|
|
|
|
|
|
|
|
func (st SignatureType) String() string {
|
|
|
|
switch st {
|
|
|
|
case CertificateTimestampSignatureType:
|
|
|
|
return "CertificateTimestamp"
|
|
|
|
case TreeHashSignatureType:
|
|
|
|
return "TreeHash"
|
|
|
|
default:
|
|
|
|
return fmt.Sprintf("UnknownSignatureType(%d)", st)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ASN1Cert type for holding the raw DER bytes of an ASN.1 Certificate
|
|
|
|
// (section 3.1).
|
|
|
|
type ASN1Cert struct {
|
|
|
|
Data []byte `tls:"minlen:1,maxlen:16777215"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// LogID holds the hash of the Log's public key (section 3.2).
|
|
|
|
// TODO(pphaneuf): Users should be migrated to the one in the logid package.
|
|
|
|
type LogID struct {
|
|
|
|
KeyID [sha256.Size]byte
|
|
|
|
}
|
|
|
|
|
|
|
|
// PreCert represents a Precertificate (section 3.2).
|
|
|
|
type PreCert struct {
|
|
|
|
IssuerKeyHash [sha256.Size]byte
|
|
|
|
TBSCertificate []byte `tls:"minlen:1,maxlen:16777215"` // DER-encoded TBSCertificate
|
|
|
|
}
|
|
|
|
|
|
|
|
// CTExtensions is a representation of the raw bytes of any CtExtension
|
|
|
|
// structure (see section 3.2).
|
|
|
|
// nolint: golint
|
|
|
|
type CTExtensions []byte // tls:"minlen:0,maxlen:65535"`
|
|
|
|
|
|
|
|
// MerkleTreeNode represents an internal node in the CT tree.
|
|
|
|
type MerkleTreeNode []byte
|
|
|
|
|
|
|
|
// ConsistencyProof represents a CT consistency proof (see sections 2.1.2 and
|
|
|
|
// 4.4).
|
|
|
|
type ConsistencyProof []MerkleTreeNode
|
|
|
|
|
|
|
|
// AuditPath represents a CT inclusion proof (see sections 2.1.1 and 4.5).
|
|
|
|
type AuditPath []MerkleTreeNode
|
|
|
|
|
|
|
|
// LeafInput represents a serialized MerkleTreeLeaf structure.
|
|
|
|
type LeafInput []byte
|
|
|
|
|
|
|
|
// DigitallySigned is a local alias for tls.DigitallySigned so that we can
|
|
|
|
// attach a MarshalJSON method.
|
|
|
|
type DigitallySigned tls.DigitallySigned
|
|
|
|
|
|
|
|
// FromBase64String populates the DigitallySigned structure from the base64 data passed in.
|
|
|
|
// Returns an error if the base64 data is invalid.
|
|
|
|
func (d *DigitallySigned) FromBase64String(b64 string) error {
|
|
|
|
raw, err := base64.StdEncoding.DecodeString(b64)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to unbase64 DigitallySigned: %v", err)
|
|
|
|
}
|
|
|
|
var ds tls.DigitallySigned
|
|
|
|
if rest, err := tls.Unmarshal(raw, &ds); err != nil {
|
|
|
|
return fmt.Errorf("failed to unmarshal DigitallySigned: %v", err)
|
|
|
|
} else if len(rest) > 0 {
|
|
|
|
return fmt.Errorf("trailing data (%d bytes) after DigitallySigned", len(rest))
|
|
|
|
}
|
|
|
|
*d = DigitallySigned(ds)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Base64String returns the base64 representation of the DigitallySigned struct.
|
|
|
|
func (d DigitallySigned) Base64String() (string, error) {
|
|
|
|
b, err := tls.Marshal(d)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return base64.StdEncoding.EncodeToString(b), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// MarshalJSON implements the json.Marshaller interface.
|
|
|
|
func (d DigitallySigned) MarshalJSON() ([]byte, error) {
|
|
|
|
b64, err := d.Base64String()
|
|
|
|
if err != nil {
|
|
|
|
return []byte{}, err
|
|
|
|
}
|
|
|
|
return []byte(`"` + b64 + `"`), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalJSON implements the json.Unmarshaler interface.
|
|
|
|
func (d *DigitallySigned) UnmarshalJSON(b []byte) error {
|
|
|
|
var content string
|
|
|
|
if err := json.Unmarshal(b, &content); err != nil {
|
|
|
|
return fmt.Errorf("failed to unmarshal DigitallySigned: %v", err)
|
|
|
|
}
|
|
|
|
return d.FromBase64String(content)
|
|
|
|
}
|
|
|
|
|
|
|
|
// LogEntry represents the (parsed) contents of an entry in a CT log. This is described
|
|
|
|
// in section 3.1, but note that this structure does *not* match the TLS structure
|
|
|
|
// defined there (the TLS structure is never used directly in RFC6962).
|
|
|
|
type LogEntry struct {
|
|
|
|
Index int64
|
|
|
|
Leaf MerkleTreeLeaf
|
|
|
|
// Exactly one of the following three fields should be non-empty.
|
|
|
|
X509Cert *x509.Certificate // Parsed X.509 certificate
|
|
|
|
Precert *Precertificate // Extracted precertificate
|
|
|
|
JSONData []byte
|
|
|
|
|
|
|
|
// Chain holds the issuing certificate chain, starting with the
|
|
|
|
// issuer of the leaf certificate / pre-certificate.
|
|
|
|
Chain []ASN1Cert
|
|
|
|
}
|
|
|
|
|
|
|
|
// PrecertChainEntry holds an precertificate together with a validation chain
|
|
|
|
// for it; see section 3.1.
|
|
|
|
type PrecertChainEntry struct {
|
|
|
|
PreCertificate ASN1Cert `tls:"minlen:1,maxlen:16777215"`
|
|
|
|
CertificateChain []ASN1Cert `tls:"minlen:0,maxlen:16777215"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// CertificateChain holds a chain of certificates, as returned as extra data
|
|
|
|
// for get-entries (section 4.6).
|
|
|
|
type CertificateChain struct {
|
|
|
|
Entries []ASN1Cert `tls:"minlen:0,maxlen:16777215"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// JSONDataEntry holds arbitrary data.
|
|
|
|
type JSONDataEntry struct {
|
|
|
|
Data []byte `tls:"minlen:0,maxlen:1677215"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// SHA256Hash represents the output from the SHA256 hash function.
|
|
|
|
type SHA256Hash [sha256.Size]byte
|
|
|
|
|
|
|
|
// FromBase64String populates the SHA256 struct with the contents of the base64 data passed in.
|
|
|
|
func (s *SHA256Hash) FromBase64String(b64 string) error {
|
|
|
|
bs, err := base64.StdEncoding.DecodeString(b64)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to unbase64 LogID: %v", err)
|
|
|
|
}
|
|
|
|
if len(bs) != sha256.Size {
|
|
|
|
return fmt.Errorf("invalid SHA256 length, expected 32 but got %d", len(bs))
|
|
|
|
}
|
|
|
|
copy(s[:], bs)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Base64String returns the base64 representation of this SHA256Hash.
|
|
|
|
func (s SHA256Hash) Base64String() string {
|
|
|
|
return base64.StdEncoding.EncodeToString(s[:])
|
|
|
|
}
|
|
|
|
|
|
|
|
// MarshalJSON implements the json.Marshaller interface for SHA256Hash.
|
|
|
|
func (s SHA256Hash) MarshalJSON() ([]byte, error) {
|
|
|
|
return []byte(`"` + s.Base64String() + `"`), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalJSON implements the json.Unmarshaller interface.
|
|
|
|
func (s *SHA256Hash) UnmarshalJSON(b []byte) error {
|
|
|
|
var content string
|
|
|
|
if err := json.Unmarshal(b, &content); err != nil {
|
|
|
|
return fmt.Errorf("failed to unmarshal SHA256Hash: %v", err)
|
|
|
|
}
|
|
|
|
return s.FromBase64String(content)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SignedTreeHead represents the structure returned by the get-sth CT method
|
|
|
|
// after base64 decoding; see sections 3.5 and 4.3.
|
|
|
|
type SignedTreeHead struct {
|
|
|
|
Version Version `json:"sth_version"` // The version of the protocol to which the STH conforms
|
|
|
|
TreeSize uint64 `json:"tree_size"` // The number of entries in the new tree
|
|
|
|
Timestamp uint64 `json:"timestamp"` // The time at which the STH was created
|
|
|
|
SHA256RootHash SHA256Hash `json:"sha256_root_hash"` // The root hash of the log's Merkle tree
|
|
|
|
TreeHeadSignature DigitallySigned `json:"tree_head_signature"` // Log's signature over a TLS-encoded TreeHeadSignature
|
|
|
|
LogID SHA256Hash `json:"log_id"` // The SHA256 hash of the log's public key
|
|
|
|
}
|
|
|
|
|
|
|
|
// TreeHeadSignature holds the data over which the signature in an STH is
|
|
|
|
// generated; see section 3.5
|
|
|
|
type TreeHeadSignature struct {
|
|
|
|
Version Version `tls:"maxval:255"`
|
|
|
|
SignatureType SignatureType `tls:"maxval:255"` // == TreeHashSignatureType
|
|
|
|
Timestamp uint64
|
|
|
|
TreeSize uint64
|
|
|
|
SHA256RootHash SHA256Hash
|
|
|
|
}
|
|
|
|
|
|
|
|
// SignedCertificateTimestamp represents the structure returned by the
|
|
|
|
// add-chain and add-pre-chain methods after base64 decoding; see sections
|
|
|
|
// 3.2, 4.1 and 4.2.
|
|
|
|
type SignedCertificateTimestamp struct {
|
|
|
|
SCTVersion Version `tls:"maxval:255"`
|
|
|
|
LogID LogID
|
|
|
|
Timestamp uint64
|
|
|
|
Extensions CTExtensions `tls:"minlen:0,maxlen:65535"`
|
|
|
|
Signature DigitallySigned // Signature over TLS-encoded CertificateTimestamp
|
|
|
|
}
|
|
|
|
|
|
|
|
// CertificateTimestamp is the collection of data that the signature in an
|
|
|
|
// SCT is over; see section 3.2.
|
|
|
|
type CertificateTimestamp struct {
|
|
|
|
SCTVersion Version `tls:"maxval:255"`
|
|
|
|
SignatureType SignatureType `tls:"maxval:255"`
|
|
|
|
Timestamp uint64
|
|
|
|
EntryType LogEntryType `tls:"maxval:65535"`
|
|
|
|
X509Entry *ASN1Cert `tls:"selector:EntryType,val:0"`
|
|
|
|
PrecertEntry *PreCert `tls:"selector:EntryType,val:1"`
|
|
|
|
JSONEntry *JSONDataEntry `tls:"selector:EntryType,val:32768"`
|
|
|
|
Extensions CTExtensions `tls:"minlen:0,maxlen:65535"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s SignedCertificateTimestamp) String() string {
|
|
|
|
return fmt.Sprintf("{Version:%d LogId:%s Timestamp:%d Extensions:'%s' Signature:%v}", s.SCTVersion,
|
|
|
|
base64.StdEncoding.EncodeToString(s.LogID.KeyID[:]),
|
|
|
|
s.Timestamp,
|
|
|
|
s.Extensions,
|
|
|
|
s.Signature)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TimestampedEntry is part of the MerkleTreeLeaf structure; see section 3.4.
|
|
|
|
type TimestampedEntry struct {
|
|
|
|
Timestamp uint64
|
|
|
|
EntryType LogEntryType `tls:"maxval:65535"`
|
|
|
|
X509Entry *ASN1Cert `tls:"selector:EntryType,val:0"`
|
|
|
|
PrecertEntry *PreCert `tls:"selector:EntryType,val:1"`
|
|
|
|
JSONEntry *JSONDataEntry `tls:"selector:EntryType,val:32768"`
|
|
|
|
Extensions CTExtensions `tls:"minlen:0,maxlen:65535"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// MerkleTreeLeaf represents the deserialized structure of the hash input for the
|
|
|
|
// leaves of a log's Merkle tree; see section 3.4.
|
|
|
|
type MerkleTreeLeaf struct {
|
|
|
|
Version Version `tls:"maxval:255"`
|
|
|
|
LeafType MerkleLeafType `tls:"maxval:255"`
|
|
|
|
TimestampedEntry *TimestampedEntry `tls:"selector:LeafType,val:0"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// Precertificate represents the parsed CT Precertificate structure.
|
|
|
|
type Precertificate struct {
|
|
|
|
// DER-encoded pre-certificate as originally added, which includes a
|
|
|
|
// poison extension and a signature generated over the pre-cert by
|
|
|
|
// the pre-cert issuer (which might differ from the issuer of the final
|
|
|
|
// cert, see RFC6962 s3.1).
|
|
|
|
Submitted ASN1Cert
|
|
|
|
// SHA256 hash of the issuing key
|
|
|
|
IssuerKeyHash [sha256.Size]byte
|
|
|
|
// Parsed TBSCertificate structure, held in an x509.Certificate for convenience.
|
|
|
|
TBSCertificate *x509.Certificate
|
|
|
|
}
|
|
|
|
|
|
|
|
// X509Certificate returns the X.509 Certificate contained within the
|
|
|
|
// MerkleTreeLeaf.
|
|
|
|
func (m *MerkleTreeLeaf) X509Certificate() (*x509.Certificate, error) {
|
|
|
|
if m.TimestampedEntry.EntryType != X509LogEntryType {
|
|
|
|
return nil, fmt.Errorf("cannot call X509Certificate on a MerkleTreeLeaf that is not an X509 entry")
|
|
|
|
}
|
|
|
|
return x509.ParseCertificate(m.TimestampedEntry.X509Entry.Data)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Precertificate returns the X.509 Precertificate contained within the MerkleTreeLeaf.
|
|
|
|
//
|
|
|
|
// The returned precertificate is embedded in an x509.Certificate, but is in the
|
|
|
|
// form stored internally in the log rather than the original submitted form
|
|
|
|
// (i.e. it does not include the poison extension and any changes to reflect the
|
|
|
|
// final certificate's issuer have been made; see x509.BuildPrecertTBS).
|
|
|
|
func (m *MerkleTreeLeaf) Precertificate() (*x509.Certificate, error) {
|
|
|
|
if m.TimestampedEntry.EntryType != PrecertLogEntryType {
|
|
|
|
return nil, fmt.Errorf("cannot call Precertificate on a MerkleTreeLeaf that is not a precert entry")
|
|
|
|
}
|
|
|
|
return x509.ParseTBSCertificate(m.TimestampedEntry.PrecertEntry.TBSCertificate)
|
|
|
|
}
|
|
|
|
|
2018-07-07 01:22:35 +00:00
|
|
|
// APIEndpoint is a string that represents one of the Certificate Transparency
|
|
|
|
// Log API endpoints.
|
|
|
|
type APIEndpoint string
|
|
|
|
|
|
|
|
// Certificate Transparency Log API endpoints; see section 4.
|
|
|
|
// WARNING: Should match the URI paths without the "/ct/v1/" prefix. If
|
|
|
|
// changing these constants, may need to change those too.
|
|
|
|
const (
|
|
|
|
AddChainStr APIEndpoint = "add-chain"
|
|
|
|
AddPreChainStr APIEndpoint = "add-pre-chain"
|
|
|
|
GetSTHStr APIEndpoint = "get-sth"
|
|
|
|
GetEntriesStr APIEndpoint = "get-entries"
|
|
|
|
GetProofByHashStr APIEndpoint = "get-proof-by-hash"
|
|
|
|
GetSTHConsistencyStr APIEndpoint = "get-sth-consistency"
|
|
|
|
GetRootsStr APIEndpoint = "get-roots"
|
|
|
|
GetEntryAndProofStr APIEndpoint = "get-entry-and-proof"
|
|
|
|
)
|
|
|
|
|
2018-06-17 07:32:44 +00:00
|
|
|
// URI paths for Log requests; see section 4.
|
2018-07-07 01:22:35 +00:00
|
|
|
// WARNING: Should match the API endpoints, with the "/ct/v1/" prefix. If
|
|
|
|
// changing these constants, may need to change those too.
|
2018-06-17 07:32:44 +00:00
|
|
|
const (
|
|
|
|
AddChainPath = "/ct/v1/add-chain"
|
|
|
|
AddPreChainPath = "/ct/v1/add-pre-chain"
|
|
|
|
GetSTHPath = "/ct/v1/get-sth"
|
|
|
|
GetEntriesPath = "/ct/v1/get-entries"
|
|
|
|
GetProofByHashPath = "/ct/v1/get-proof-by-hash"
|
|
|
|
GetSTHConsistencyPath = "/ct/v1/get-sth-consistency"
|
|
|
|
GetRootsPath = "/ct/v1/get-roots"
|
|
|
|
GetEntryAndProofPath = "/ct/v1/get-entry-and-proof"
|
|
|
|
|
|
|
|
AddJSONPath = "/ct/v1/add-json" // Experimental addition
|
|
|
|
)
|
|
|
|
|
|
|
|
// AddChainRequest represents the JSON request body sent to the add-chain and
|
|
|
|
// add-pre-chain POST methods from sections 4.1 and 4.2.
|
|
|
|
type AddChainRequest struct {
|
|
|
|
Chain [][]byte `json:"chain"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddChainResponse represents the JSON response to the add-chain and
|
|
|
|
// add-pre-chain POST methods.
|
|
|
|
// An SCT represents a Log's promise to integrate a [pre-]certificate into the
|
|
|
|
// log within a defined period of time.
|
|
|
|
type AddChainResponse struct {
|
|
|
|
SCTVersion Version `json:"sct_version"` // SCT structure version
|
|
|
|
ID []byte `json:"id"` // Log ID
|
|
|
|
Timestamp uint64 `json:"timestamp"` // Timestamp of issuance
|
|
|
|
Extensions string `json:"extensions"` // Holder for any CT extensions
|
|
|
|
Signature []byte `json:"signature"` // Log signature for this SCT
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddJSONRequest represents the JSON request body sent to the add-json POST method.
|
|
|
|
// The corresponding response re-uses AddChainResponse.
|
|
|
|
// This is an experimental addition not covered by RFC6962.
|
|
|
|
type AddJSONRequest struct {
|
|
|
|
Data interface{} `json:"data"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetSTHResponse respresents the JSON response to the get-sth GET method from section 4.3.
|
|
|
|
type GetSTHResponse struct {
|
|
|
|
TreeSize uint64 `json:"tree_size"` // Number of certs in the current tree
|
|
|
|
Timestamp uint64 `json:"timestamp"` // Time that the tree was created
|
|
|
|
SHA256RootHash []byte `json:"sha256_root_hash"` // Root hash of the tree
|
|
|
|
TreeHeadSignature []byte `json:"tree_head_signature"` // Log signature for this STH
|
|
|
|
}
|
|
|
|
|
2018-07-03 07:25:07 +00:00
|
|
|
// ToSignedTreeHead creates a SignedTreeHead from the GetSTHResponse.
|
|
|
|
func (r *GetSTHResponse) ToSignedTreeHead() (*SignedTreeHead, error) {
|
|
|
|
sth := SignedTreeHead{
|
|
|
|
TreeSize: r.TreeSize,
|
|
|
|
Timestamp: r.Timestamp,
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(r.SHA256RootHash) != sha256.Size {
|
|
|
|
return nil, fmt.Errorf("sha256_root_hash is invalid length, expected %d got %d", sha256.Size, len(r.SHA256RootHash))
|
|
|
|
}
|
|
|
|
copy(sth.SHA256RootHash[:], r.SHA256RootHash)
|
|
|
|
|
|
|
|
var ds DigitallySigned
|
|
|
|
if rest, err := tls.Unmarshal(r.TreeHeadSignature, &ds); err != nil {
|
|
|
|
return nil, fmt.Errorf("tls.Unmarshal(): %s", err)
|
|
|
|
} else if len(rest) > 0 {
|
|
|
|
return nil, fmt.Errorf("trailing data (%d bytes) after DigitallySigned", len(rest))
|
|
|
|
}
|
|
|
|
sth.TreeHeadSignature = ds
|
|
|
|
|
|
|
|
return &sth, nil
|
|
|
|
}
|
|
|
|
|
2018-06-17 07:32:44 +00:00
|
|
|
// GetSTHConsistencyResponse represents the JSON response to the get-sth-consistency
|
|
|
|
// GET method from section 4.4. (The corresponding GET request has parameters 'first' and
|
|
|
|
// 'second'.)
|
|
|
|
type GetSTHConsistencyResponse struct {
|
|
|
|
Consistency [][]byte `json:"consistency"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetProofByHashResponse represents the JSON response to the get-proof-by-hash GET
|
|
|
|
// method from section 4.5. (The corresponding GET request has parameters 'hash'
|
|
|
|
// and 'tree_size'.)
|
|
|
|
type GetProofByHashResponse struct {
|
|
|
|
LeafIndex int64 `json:"leaf_index"` // The 0-based index of the end entity corresponding to the "hash" parameter.
|
|
|
|
AuditPath [][]byte `json:"audit_path"` // An array of base64-encoded Merkle Tree nodes proving the inclusion of the chosen certificate.
|
|
|
|
}
|
|
|
|
|
|
|
|
// LeafEntry represents a leaf in the Log's Merkle tree, as returned by the get-entries
|
|
|
|
// GET method from section 4.6.
|
|
|
|
type LeafEntry struct {
|
|
|
|
// LeafInput is a TLS-encoded MerkleTreeLeaf
|
|
|
|
LeafInput []byte `json:"leaf_input"`
|
|
|
|
// ExtraData holds (unsigned) extra data, normally the cert validation chain.
|
|
|
|
ExtraData []byte `json:"extra_data"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetEntriesResponse respresents the JSON response to the get-entries GET method
|
|
|
|
// from section 4.6.
|
|
|
|
type GetEntriesResponse struct {
|
|
|
|
Entries []LeafEntry `json:"entries"` // the list of returned entries
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetRootsResponse represents the JSON response to the get-roots GET method from section 4.7.
|
|
|
|
type GetRootsResponse struct {
|
|
|
|
Certificates []string `json:"certificates"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetEntryAndProofResponse represents the JSON response to the get-entry-and-proof
|
|
|
|
// GET method from section 4.8. (The corresponding GET request has parameters 'leaf_index'
|
|
|
|
// and 'tree_size'.)
|
|
|
|
type GetEntryAndProofResponse struct {
|
|
|
|
LeafInput []byte `json:"leaf_input"` // the entry itself
|
|
|
|
ExtraData []byte `json:"extra_data"` // any chain provided when the entry was added to the log
|
|
|
|
AuditPath [][]byte `json:"audit_path"` // the corresponding proof
|
|
|
|
}
|