1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package ctfe
16
17 import (
18 "context"
19 "crypto/sha256"
20 "errors"
21 "fmt"
22
23 ct "github.com/google/certificate-transparency-go"
24 "github.com/google/trillian"
25 "github.com/google/trillian/types"
26 "google.golang.org/protobuf/encoding/prototext"
27 "k8s.io/klog/v2"
28 )
29
30 type contextKey string
31
32
33
34 var remoteQuotaCtxKey = contextKey("quotaUser")
35
36
37 type MirrorSTHStorage interface {
38
39
40 GetMirrorSTH(ctx context.Context, maxTreeSize int64) (*ct.SignedTreeHead, error)
41 }
42
43
44 type STHGetter interface {
45
46
47 GetSTH(ctx context.Context) (*ct.SignedTreeHead, error)
48 }
49
50
51 type FrozenSTHGetter struct {
52 sth *ct.SignedTreeHead
53 }
54
55
56 func (sg *FrozenSTHGetter) GetSTH(ctx context.Context) (*ct.SignedTreeHead, error) {
57 return sg.sth, nil
58 }
59
60
61
62 type LogSTHGetter struct {
63 li *logInfo
64 cache SignatureCache
65 }
66
67
68
69 func (sg *LogSTHGetter) GetSTH(ctx context.Context) (*ct.SignedTreeHead, error) {
70 currentRoot, err := getSignedLogRoot(ctx, sg.li.rpcClient, sg.li.logID, sg.li.LogPrefix)
71 if err != nil {
72 return nil, err
73 }
74
75
76 sth := &ct.SignedTreeHead{
77 Version: ct.V1,
78 TreeSize: uint64(currentRoot.TreeSize),
79 Timestamp: uint64(currentRoot.TimestampNanos / 1000 / 1000),
80 }
81
82 copy(sth.SHA256RootHash[:], currentRoot.RootHash)
83
84
85 err = signV1TreeHead(sg.li.signer, sth, &sg.cache)
86 if err != nil || len(sth.TreeHeadSignature.Signature) == 0 {
87 return nil, fmt.Errorf("failed to sign tree head: %v", err)
88 }
89
90 return sth, nil
91 }
92
93
94
95
96 type MirrorSTHGetter struct {
97 li *logInfo
98 st MirrorSTHStorage
99 }
100
101
102
103
104
105 func (sg *MirrorSTHGetter) GetSTH(ctx context.Context) (*ct.SignedTreeHead, error) {
106 currentRoot, err := getSignedLogRoot(ctx, sg.li.rpcClient, sg.li.logID, sg.li.LogPrefix)
107 if err != nil {
108 return nil, err
109 }
110
111 sth, err := sg.st.GetMirrorSTH(ctx, int64(currentRoot.TreeSize))
112 if err != nil {
113 return nil, err
114 }
115
116
117 return sth, nil
118 }
119
120
121
122 func getSignedLogRoot(ctx context.Context, client trillian.TrillianLogClient, logID int64, prefix string) (*types.LogRootV1, error) {
123 req := trillian.GetLatestSignedLogRootRequest{LogId: logID}
124 if q := ctx.Value(remoteQuotaCtxKey); q != nil {
125 quotaUser, ok := q.(string)
126 if !ok {
127 return nil, fmt.Errorf("incorrect quota value: %v, type %T", q, q)
128 }
129 req.ChargeTo = appendUserCharge(req.ChargeTo, quotaUser)
130 }
131
132 klog.V(2).Infof("%s: GetSTH => grpc.GetLatestSignedLogRoot %+v", prefix, prototext.Format(&req))
133 rsp, err := client.GetLatestSignedLogRoot(ctx, &req)
134 klog.V(2).Infof("%s: GetSTH <= grpc.GetLatestSignedLogRoot err=%v", prefix, err)
135 if err != nil {
136 return nil, err
137 }
138
139
140 slr := rsp.SignedLogRoot
141 if slr == nil {
142 return nil, errors.New("no log root returned")
143 }
144 klog.V(3).Infof("%s: GetSTH <= slr=%+v", prefix, slr)
145 var currentRoot types.LogRootV1
146 if err := currentRoot.UnmarshalBinary(slr.GetLogRoot()); err != nil {
147 return nil, fmt.Errorf("failed to unmarshal root: %v", slr)
148 }
149 if hashSize := len(currentRoot.RootHash); hashSize != sha256.Size {
150 return nil, fmt.Errorf("bad hash size from backend expecting: %d got %d", sha256.Size, hashSize)
151 }
152
153 return ¤tRoot, nil
154 }
155
156
157 type DefaultMirrorSTHFactory struct{}
158
159
160 func (f DefaultMirrorSTHFactory) NewStorage(logID [sha256.Size]byte) (MirrorSTHStorage, error) {
161 return DefaultMirrorSTHStorage{}, nil
162 }
163
164
165 type DefaultMirrorSTHStorage struct{}
166
167
168 func (st DefaultMirrorSTHStorage) GetMirrorSTH(ctx context.Context, maxTreeSize int64) (*ct.SignedTreeHead, error) {
169 return nil, errors.New("not implemented")
170 }
171
View as plain text