aboutsummaryrefslogtreecommitdiff
path: root/instance.go
blob: 122cb67fcdcae0296d1bdfd440adb8e450ab7fbf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package stfe

import (
	"crypto"
	"fmt"
	"strings"
	"time"

	"crypto/sha256"
	"crypto/x509"
	"net/http"

	"github.com/google/trillian"
	"github.com/system-transparency/stfe/x509util"
)

// Instance is an instance of a particular log front-end
type Instance struct {
	LogParameters *LogParameters
	Client        trillian.TrillianLogClient
	Deadline      time.Duration
}

// LogParameters is a collection of log parameters
type LogParameters struct {
	LogId      []byte              // used externally by everyone
	TreeId     int64               // used internally by Trillian
	Prefix     string              // e.g., "test" for <base>/test
	MaxRange   int64               // max entries per get-entries request
	MaxChain   int64               // max submitter certificate chain length
	AnchorPool *x509.CertPool      // for chain verification
	AnchorList []*x509.Certificate // for access to the raw certificates
	KeyUsage   []x509.ExtKeyUsage  // which extended key usages are accepted
	Signer     crypto.Signer
	HashType   crypto.Hash // hash function used by Trillian
}

// Endpoint is a named HTTP API endpoint
type Endpoint string

const (
	EndpointAddEntry            = Endpoint("add-entry")
	EndpointGetEntries          = Endpoint("get-entries")
	EndpointGetAnchors          = Endpoint("get-anchors")
	EndpointGetProofByHash      = Endpoint("get-proof-by-hash")
	EndpointGetConsistencyProof = Endpoint("get-consistency-proof")
	EndpointGetSth              = Endpoint("get-sth")
)

func (i Instance) String() string {
	return fmt.Sprintf("%s Deadline(%v)\n", i.LogParameters, i.Deadline)
}

func (lp LogParameters) String() string {
	return fmt.Sprintf("LogId(%s) TreeId(%d) Prefix(%s) MaxRange(%d) MaxChain(%d) NumAnchors(%d)", lp.id(), lp.TreeId, lp.Prefix, lp.MaxRange, lp.MaxChain, len(lp.AnchorList))
}

func (e Endpoint) String() string {
	return string(e)
}

// NewInstance creates a new STFE instance
func NewInstance(lp *LogParameters, client trillian.TrillianLogClient, deadline time.Duration) *Instance {
	return &Instance{
		LogParameters: lp,
		Client:        client,
		Deadline:      deadline,
	}
}

// NewLogParameters creates new log parameters.  Note that the signer is
// assumed to be an ed25519 signing key.  Could be fixed at some point.
func NewLogParameters(treeId int64, prefix string, anchors []*x509.Certificate, signer crypto.Signer, maxRange, maxChain int64) (*LogParameters, error) {
	if signer == nil {
		return nil, fmt.Errorf("need a signer but got none")
	}
	if len(anchors) < 1 {
		return nil, fmt.Errorf("need at least one trust anchor")
	}
	if maxRange < 1 {
		return nil, fmt.Errorf("max range must be at least one")
	}
	if maxChain < 1 {
		return nil, fmt.Errorf("max chain must be at least one")
	}
	pub, err := x509.MarshalPKIXPublicKey(signer.Public())
	if err != nil {
		return nil, fmt.Errorf("failed DER encoding SubjectPublicKeyInfo: %v", err)
	}
	hasher := sha256.New()
	hasher.Write(pub)
	return &LogParameters{
		LogId:      hasher.Sum(nil),
		TreeId:     treeId,
		Prefix:     prefix,
		MaxRange:   maxRange,
		MaxChain:   maxChain,
		AnchorPool: x509util.NewCertPool(anchors),
		AnchorList: anchors,
		KeyUsage:   []x509.ExtKeyUsage{}, // placeholder, must be tested if used
		Signer:     signer,
		HashType:   crypto.SHA256, // STFE assumes RFC 6962 hashing
	}, nil
}

// Handlers returns a list of STFE handlers
func (i *Instance) Handlers() []Handler {
	return []Handler{
		Handler{instance: i, handler: addEntry, endpoint: EndpointAddEntry, method: http.MethodPost},
		Handler{instance: i, handler: getEntries, endpoint: EndpointGetEntries, method: http.MethodGet},
		Handler{instance: i, handler: getAnchors, endpoint: EndpointGetAnchors, method: http.MethodGet},
		Handler{instance: i, handler: getProofByHash, endpoint: EndpointGetProofByHash, method: http.MethodGet},
		Handler{instance: i, handler: getConsistencyProof, endpoint: EndpointGetConsistencyProof, method: http.MethodGet},
		Handler{instance: i, handler: getSth, endpoint: EndpointGetSth, method: http.MethodGet},
	}
}

// id formats the log's identifier as base64
func (i *LogParameters) id() string {
	return b64(i.LogId)
}

// Path joins a number of components to form a full endpoint path, e.g., base
// ("example.com"), prefix ("st/v1"), and the endpoint itself ("get-sth").
func (e Endpoint) Path(components ...string) string {
	return strings.Join(append(components, string(e)), "/")
}